はじめに
Go 1.18 がリリースされました。Go 1.18でシュッとGenerics を手軽に良さを実感する方法としてsamber/lo があります。 もちろん、Tutorial: Getting started with generics で完全に理解できるならそちらの方が良いですし、これを終わった後でやることも推奨です。その他のリリースパーティや勉強会もとても勉強になりますが とにかく、samber/lo 便利なので紹介させてください!!!!!!!
今回はとても大きな変更です。Generics が入りました。構成としては2つ。
- Type parameter
- Type sets
参考資料
DevFest Tokyo 2021 でmattn さんが発表したスライド&動画がとても分かりやすいので是非、見てみてください。
全てfor 文で解決するのか?- そう、全て筋肉が解決してくれる
Golang にはuniq メゾットのようなものがなく、重複のある slice に対して独自に処理を実装しなければいけなかった。 愚直にfor を回すの結果として最速だからである。
arr := []string{"Samuel", "Marc", "Samuel"} m := map[string]bool{} for _, ele := range arr { if !m[ele] { m[ele] = true uniq = append(uniq, ele) } } fmt.Printf("%v", uniq) // ["Samuel", "Marc"]
Go Playground - The Go Programming Language
どういうことかというと、重複キーがあるので、同様のキーを持つmapの場合は新しく値を上書きしないみたいな処理を書かなければならなかった。
m["Samuel"] = true
は一度目はこれが呼ばれるけど、二度目はすでにtrue
なので if句の中に入ってず、resultにSamuel
が二度入ることがないという様な仕組みです。
とにかく、全てをfor
で扱い全ての型を制御するマッチョでした。
全てfor 文で解決するのか?- samber/lo とか?
Golang にはuniq メゾットのようなものがなく、重複のある slice に対して独自に処理を実装しなければいけなかったがsamber/lo というプロジェクトでは
Go 1.18 のGenerics を使うことによってreflect
より早くfor
とも遜色なく動作するヘルパーを提供します。他にもいくつもの ヘルパー がありますが今回はuniq のみ紹介します。
package main import ( "fmt" "github.com/samber/lo" ) func main() { arr := []string{"Samuel", "Marc", "Samuel"} names := lo.Uniq[string](arr) fmt.Println(names) // []string{"Samuel", "Marc"} }
uniqValues := lo.Uniq[int]([]int{1, 2, 2, 1}) // []int{1, 2}
実装をみるとこんな感じでmapと空のstructを使う方法でuniq が実装されている。
lo/slice.go at v1.10.1 · samber/lo · GitHub
func Uniq[T comparable](collection []T) []T { result := make([]T, 0, len(collection)) seen := make(map[T]struct{}, len(collection)) for _, item := range collection { if _, ok := seen[item]; ok { continue } seen[item] = struct{}{} result = append(result, item) } return result }
とにかく、for
で愚直に回す言語から多少はスマートな解決ができる様になった(もしくは今後、期待ができる様になった)。
最後に
この記事を読んで興味が湧いたら元のProposalやTutorial: Getting started with generics を読んでみてください。自分も何度かやってみて読んでみて使える様になりたいと思ってます。また、Go本体にも機能として追加される日を楽しみしてます。