Functional programming for the win! Add a utility function to map the
values of a slice, along with a curried variant, to tide us over until
equivalent functionality gets added to the standard library
(https://go.dev/issue/61898)
Signed-off-by: Cory Snider <csnider@mirantis.com>
| ... | ... |
@@ -11,3 +11,21 @@ func Dedup[T comparable](slice []T) []T {
|
| 11 | 11 |
} |
| 12 | 12 |
return out |
| 13 | 13 |
} |
| 14 |
+ |
|
| 15 |
+func Map[S ~[]In, In, Out any](s S, fn func(In) Out) []Out {
|
|
| 16 |
+ res := make([]Out, len(s)) |
|
| 17 |
+ for i, v := range s {
|
|
| 18 |
+ res[i] = fn(v) |
|
| 19 |
+ } |
|
| 20 |
+ return res |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+func Mapper[In, Out any](fn func(In) Out) func([]In) []Out {
|
|
| 24 |
+ return func(s []In) []Out {
|
|
| 25 |
+ res := make([]Out, len(s)) |
|
| 26 |
+ for i, v := range s {
|
|
| 27 |
+ res[i] = fn(v) |
|
| 28 |
+ } |
|
| 29 |
+ return res |
|
| 30 |
+ } |
|
| 31 |
+} |
| 14 | 32 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,49 @@ |
| 0 |
+package sliceutil_test |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "net/netip" |
|
| 4 |
+ "strconv" |
|
| 5 |
+ "testing" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/docker/internal/sliceutil" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func TestMap(t *testing.T) {
|
|
| 11 |
+ s := []int{1, 2, 3}
|
|
| 12 |
+ m := sliceutil.Map(s, func(i int) int { return i * 2 })
|
|
| 13 |
+ if len(m) != len(s) {
|
|
| 14 |
+ t.Fatalf("expected len %d, got %d", len(s), len(m))
|
|
| 15 |
+ } |
|
| 16 |
+ for i, v := range m {
|
|
| 17 |
+ if expected := s[i] * 2; v != expected {
|
|
| 18 |
+ t.Fatalf("expected %d, got %d", expected, v)
|
|
| 19 |
+ } |
|
| 20 |
+ } |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+func TestMap_TypeConvert(t *testing.T) {
|
|
| 24 |
+ s := []int{1, 2, 3}
|
|
| 25 |
+ m := sliceutil.Map(s, func(i int) string { return strconv.Itoa(i) })
|
|
| 26 |
+ if len(m) != len(s) {
|
|
| 27 |
+ t.Fatalf("expected len %d, got %d", len(s), len(m))
|
|
| 28 |
+ } |
|
| 29 |
+ for i, v := range m {
|
|
| 30 |
+ if expected := strconv.Itoa(s[i]); v != expected {
|
|
| 31 |
+ t.Fatalf("expected %s, got %s", expected, v)
|
|
| 32 |
+ } |
|
| 33 |
+ } |
|
| 34 |
+} |
|
| 35 |
+ |
|
| 36 |
+func TestMapper(t *testing.T) {
|
|
| 37 |
+ s := []string{"1.2.3.4", "fe80::1"}
|
|
| 38 |
+ mapper := sliceutil.Mapper(netip.MustParseAddr) |
|
| 39 |
+ m := mapper(s) |
|
| 40 |
+ if len(m) != len(s) {
|
|
| 41 |
+ t.Fatalf("expected len %d, got %d", len(s), len(m))
|
|
| 42 |
+ } |
|
| 43 |
+ for i, v := range m {
|
|
| 44 |
+ if expected := netip.MustParseAddr(s[i]); v != expected {
|
|
| 45 |
+ t.Fatalf("expected %s, got %s", expected, v)
|
|
| 46 |
+ } |
|
| 47 |
+ } |
|
| 48 |
+} |