Slide 1

Slide 1 text

Genericsな便利ライブラリ Let’s Go Talk #2 LT @masanetes

Slide 2

Slide 2 text

自己紹介 山本 真史 Accelia株式会社 インフラエンジニア 基盤開発/構築(Docker, Kubernetes, GCP, AWS) バックエンド開発(Go)

Slide 3

Slide 3 text

go1.18 型パラメータを用いたGenerics導入👏 Go @golang·Follow Go go1.18 is released! Release notes: go.dev/doc/go1.18 Download: go.dev/dl/#go1.18 #golang 2:36 AM · Mar 16, 2022 3.5K Reply Copy link Read 63 replies

Slide 4

Slide 4 text

そもそもGenericsってなんだっけ? ジェネリック(総称あるいは汎用)プログラミング(英: generic programming)は、具体的なデータ型に直接依存しない、抽象的か つ汎用的なコード記述を可能にするコンピュータプログラミング手法である。 (ジェネリックプログラミング - https://ja.wikipedia.org/w/index.php?curid=740871)

Slide 5

Slide 5 text

Without Generics 具体的なデータ型 抽象的に func main() { SplitInt([]int{1, 2, 3, 4}) // [1 2] [3 4] SplitStr([]string{"foo", "bar"}) // [foo] [bar] } func SplitInt(v []int) ([]int, []int) { mid := len(v) / 2 return v[:mid], v[mid:] } func SplitStr(v []string) ([]string, []string) { mid := len(v) / 2 return v[:mid], v[mid:] } func Split(v []interface{}) ([]interface{}, []interface{}) mid := len(v) / 2 return v[:mid], v[mid:] }

Slide 6

Slide 6 text

都度 型アサーション v1, _ := Split([]interface{}{1, "hoge", 3, 4}) vint, ok := v.(int) if ok { func main() { sum := 0 for _, v := range v1 { sum += vint } } fmt.Println(sum) }

Slide 7

Slide 7 text

With Generics 具体的なデータ型 抽象的に func main() { SplitInt([]int{1, 2, 3, 4}) // [1 2] [3 4] SplitStr([]string{"foo", "bar"}) // [foo] [bar] } func SplitInt(v []int) ([]int, []int) { mid := len(v) / 2 return v[:mid], v[mid:] } func SplitStr(v []string) ([]string, []string) { mid := len(v) / 2 return v[:mid], v[mid:] } func Split[T any](v []T) ([]T, []T) { mid := len(v) / 2 return v[:mid], v[mid:] }

Slide 8

Slide 8 text

型安全に、抽象化! func main() { // v1, _ := Split([]int{1, "hoge", 3, 4}) (untyped string constant) as int value in array or slice literal v1, _ := Split([]int{1, 2, 3, 4}) sum := 0 for _, v := range v1 { sum += v } fmt.Println(sum) }

Slide 9

Slide 9 text

go1.18+ベースのslice,map等操作ライブラリ github.com/samber/lo github.com/elliotchance/pie/v2

Slide 10

Slide 10 text

lo lodashスタイルのライブラリ。たくさん機能がある Slice操作関数。Filter,Map,Reduce,Uniq... map操作関数。FindKey,Keys,Values,Assign... github.com/samber/lo numbers := []int{1, 2, 3, 4} lo.Filter(numbers, func(x int, _ int) bool { return x%2 == 0 }) // []int{2, 4} lo.Map(numbers, func(x int, _ int) int { return x * 2 }) // []int{2, 4, 6, 8} mapA := map[string]int{"foo": 10} mapB := map[string]int{"bar": 20} lo.FindKey(mapA, 10) // foo, true lo.Assign(mapA, mapB) // map[string]int{"foo": 10, "bar": 20}

Slide 11

Slide 11 text

loのMap関数実装 T型スライスと、T=>Rにする関数を引数にとって、R型スライスを返す func Map[T any, R any](collection []T, iteratee func(T, int) R) []R { result := make([]R, len(collection)) for i, item := range collection { result[i] = iteratee(item, i) } return result }

Slide 12

Slide 12 text

便利!👏だけど、こういう書き方できるやつもあるかな?🤔 // こんなやつ slice := []int{1,2,3,4} slice. Filter(...). Map(...). Reduce(...)

Slide 13

Slide 13 text

pie Slice, Map操作のためのユーティリティ関数ライブラリ。メソッドチェインで操作できる github.com/elliotchance/pie/v2 numbers := []int{1, 2, 3, 4} pie.Of(numbers). Filter(func(x int) bool { return x%2 == 0 }). // {[2, 4]} Map(func(x int) int { return x * 2 }). // {[4, 8]} Reverse(). // {[8, 4]} Result // [8, 4]

Slide 14

Slide 14 text

便利!👏でも、型変換しようとするとエラーになる numbers := []int{1, 2, 3, 4} pie.Of(numbers). Map(func(x int) string { return strconv.Itoa(x) + "x" }) // 期待 []string{1x, 2x, 3x, 4x} // cannot use func(x int) string {…} (value of type func(x int) string) // as type func(int) int in argument to pie.Of(numbers).Map

Slide 15

Slide 15 text

pieのMapメソッド実装 T型スライスと、T=>Tにする関数を引数にとって、T型スライスを返す…? オモッテタントチガウ…🤔 func (o OfSlice[T]) Map(fn func(T) T) OfSlice[T] { return OfSlice[T]{Map(o.Result, fn)} } func (o OfSlice[T]) Map[E any](fn func(T) E) OfSlice[E] { return OfSlice[E]{Map(o.Result, fn)} }

Slide 16

Slide 16 text

メソッドに型パラメータは渡せない ので、こういった操作は現時点では出来ませんでした。 Type Parameters Proposal - No parameterized method そもそもGoのGenericsではメソッドに型パラメータが渡せない func (o OfSlice[T]) Map[E any](fn func(T) E) OfSlice[E] { return OfSlice[T]{Map(o.Result, fn)} } // syntax error: method must have no type parameters

Slide 17

Slide 17 text

まとめ Genericsで型安全に抽象度を上げることができる Go1.18+で使えるライブラリでsliceやmap操作を楽にできる(lo,pie) メソッドに型パラメータを渡すことは現時点ではできない(たくさん議論されている。今後にも期待!)

Slide 18

Slide 18 text

参考 Type Parameters Proposal https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md When To Use Generics https://go.dev/blog/when-generics An Introduction To Generics https://go.dev/blog/intro-generics github.com/samber/lo github.com/elliotchance/pie/v2