[Go] slices パッケージ

slices パッケージが Go 1.21 から標準パッケージになったため、よく使うものをまとめておく。
- 実験結果からわかった、公式ドキュメントの説明では語られていなかった挙動も含めて
- 個人的に [samber/lo](https://github.com/samber/lo) を使うことが多かったため、どの関数に対応するものなのかも



slices | 説明 | 破壊的/非破壊的 | samber/lo | サンプルコード
---|---|---|---|---
Contains | 指定した要素が存在するかを返す。 | 非破壊的 | [Contains](https://github.com/samber/lo#contains) | [サンプル](https://go.dev/play/p/Jv45YYeaUSF)
[ContainsFunc](https://pkg.go.dev/slices#ContainsFunc) | 指定した関数の返り値が true になる要素が存在するかを返す。 | 非破壊的 |[ContainsBy](https://github.com/samber/lo#containsby) | [サンプル](https://go.dev/play/p/7FgdvqNLJrI)
[Index](https://pkg.go.dev/slices#Index) | 指定した要素を検索し、見つかった最初の要素のインデックス値を返す。見つからなかった場合 -1 を返す。 | 非破壊的 | [IndexOf](https://github.com/samber/lo?tab=readme-ov-file#indexof) | [サンプル](https://go.dev/play/p/XxQu7Zf3iYP)
[IndexFunc](https://pkg.go.dev/slices#IndexFunc) | 指定した関数の返り値が true になる要素を検索し、見つかった最初の要素のインデックス値を返す。見つからなかった場合、-1 を返す。 | 非破壊的 | [FindIndexOf](https://github.com/samber/lo?tab=readme-ov-file#findindexof) | [サンプル]([FindIndexOf](https://github.com/samber/lo?tab=readme-ov-file#findindexof))
該当ナシ |  指定した関数の返り値が true になる要素を検索し、見つかった最初の要素の値と、true を返す。見つからなかった場合、ゼロ値と false を返す。 | 非破壊的 | [Find](https://github.com/samber/lo?tab=readme-ov-file#find)
該当ナシ |  指定した関数の返り値が true になる要素を検索し、見つかった最初の要素の値、インデックス値とtrue を返す。見つからなかった場合、ゼロ値、-1、false を返す。| 非破壊的 | [FindIndexOf](https://github.com/samber/lo?tab=readme-ov-file#findindexof)
[Compact](https://pkg.go.dev/slices#Compact)   | 連続する同じ値の要素をユニークにしたスライスを返す。<br><br>※注意<br>　- **元のスライスは破壊的に変更され、ユニークにされた分の要素はゼロで埋められる(= おそらく元のスライスに使い道はない)** <br>　- この関数で期待する結果を得るには、先にソートされている必要がある。  | 破壊的 | [Uniq](https://github.com/samber/lo?tab=readme-ov-file#uniq) ※こちらはソート不要。また、同名の Compact という関数があるが、これはゼロ値の要素を削除するというものだった。| [サンプル](https://go.dev/play/p/cTnv_hoKACB)
[CompactFunc](https://pkg.go.dev/slices#CompactFunc) | 指定の連続する 2 つの要素を比較する関数 `func(a, b)` で true を返す場合、それら要素をユニークにしたスライスを返す。<br><br>※注意<br>　- **元のスライスは破壊的に変更され、ユニークにされた分の要素はゼロで埋められる(= おそらく元のスライスに使い道はない)**<br>　- この関数で期待する結果を得るには、先にソートされている必要がある | | [UniqBy](https://github.com/samber/lo?tab=readme-ov-file#uniqby) ※こちらは、指定する関数の形が `func(i int) int` であり、返り値が同じである要素がユニークになる。ソート不要。| [サンプル](https://go.dev/play/p/xyK1-f29sjH)
Reverse | 指定したスライスの要素の順番を逆にする。 | 破壊的 |[Reverse](https://github.com/samber/lo#reverse) (破壊的) | [サンプル](https://go.dev/play/p/K0ErSwtEMEc)
Sort | 指定したスライスを昇順にソートする。 | 破壊的 | 該当ナシ | [サンプル](https://go.dev/play/p/ICwQLX1q874)
SortFunc | スライスを、指定した関数 `func(a, b <要素の形>) int`でソートする。<br><br>・昇順ソートの場合: a < b で -1, a > b で 1 を返すようにする<br>・降順ソートの場合: a > b で 1, a < b で -1 を返すようにする<br><br>これは、a < b で -1, a > b で 1 を返してくれるという仕様が一致するc `cmp.Compare(a, b)` と相性がよく、よくサンプルでも組み合わせたものを見かける。| 破壊的 |該当ナシ | [サンプル](https://go.dev/play/p/Zjb1VsnGne8)
Max | スライス内の最大値を返す。 | 非破壊的 | [Max](https://github.com/samber/lo?tab=readme-ov-file#max) | [サンプル](https://go.dev/play/p/4o6y9W3kyr2)
MaxFunc | 指定した関数 `func(a, b <要素の型>) int` が昇順にソートさせるようなものである場合、スライスの最大値を返す。<br>・昇順ソートの場合: a < b で -1, a > b で 1 を返すようにする<br>・降順ソートの場合: a > b で 1, a < b で -1 を返すようにする<br><br>これは、a < b で -1, a > b で 1 を返してくれるという仕様が一致する `cmp.Compare(a, b)` と相性がよく、よくサンプルでも組み合わせたものを見かける。 | 非破壊的 | [MaxBy](https://github.com/samber/lo?tab=readme-ov-file#maxby) ※こちらは指定する関数の形が `func(item xxx, max xxx) bool` であり、最後に true を返した要素を返すというもの。| [サンプル](https://go.dev/play/p/cyrdzfD4ATx)
Min | スライス内の最小値を返す。 | 非破壊的 | [Min](https://github.com/samber/lo?tab=readme-ov-file#min) | [サンプル](https://go.dev/play/p/wIsqZqSudkc)
MinFunc | 指定した関数 `func(a, b <要素の型>) int` が昇順にソートさせるようなものである場合、スライスの最小値を返す。    | 非破壊的 | [MinBy](https://github.com/samber/lo?tab=readme-ov-file#minby) ※こちらは指定する関数の形が `func(item xxx, min xxx) bool` であり、最後に true を返した要素を返すというもの。| [サンプル](https://go.dev/play/p/uASNZLGQGBg)
 
# 所感
`sort.Slices` でのソートに慣れていると、SortFunc(および MaxFunc、MinFunc) のクセ強感がすごい。
[多くの場合 `slices.SortFunc` を使った方が高速](https://pkg.go.dev/sort#Slice)らしいので慣れないと…。
`cmp.Compare` と併用することで、だいぶ違和感は低減できる。