グローバルナビゲーションへ

本文へ

フッターへ

お役立ち情報Blog



Go1.21で追加された「slicesパッケージ」とは?実際にパッケージ内の関数を使うコードを書いてみた。

最近になって開発中のプロジェクトのGoのバージョンが1.21になったので、新しく追加された機能について調べようと思い、今回はslicesパッケージについて調べてみました。

slicesパッケージの概要

Package slices defines various functions useful with slices of any type.

とパッケージのドキュメントに書かれているように、slicesパッケージは、あらゆる型のスライスに対して役立つ関数を提供しているパッケージのようです。ジェネリクスを利用して実装されており、あまり型のことを気にせずに使用できそうです。

slicesパッケージの関数

Clip スライスから使われていないキャパシティを取り除いたスライスを返します。
Contains スライスに特定の要素が含まれているかを判定します。
Delete スライスの指定した位置の要素を削除します。
Equal 渡された二つのスライスが等しいかを判定します。
Index スライスに特定の要素がどの位置にあるかを数値で返します。
Insert スライスの指定した位置に指定した要素を挿入します。
IsSorted スライスが昇順でソートされているかを判定します。
Max スライス内で最も大きい要素を返します。
Min スライス内で最も小さい要素を返します。
Replace スライスの指定した位置の要素を、指定した要素に入れ替えたスライスを返します。
Reverse スライス内の順番を反転します。
Sort スライスを昇順でソートします。
SortFunc スライスを、引数に渡した関数を基に昇順でソートします。

slicesパッケージの関数の使用例

上で挙げた関数を使ったコードを実際にいくつか書いてみます。

Delete

season := []string{"Spring", "Summer", "Autumn", "Winter"}
season = slices.Delete(season, 1, 3)
fmt.Println(season) // [Spring Winter]

// slicesパッケージを使わない場合
season = []string{"Spring", "Summer", "Autumn", "Winter"}
season = append(season[:1], season[3])
fmt.Println(season) // [Spring Winter]

appendを使った従来の方法よりもシンプルで、読んでいても分かりやすいコードになったと思います。マップのdeleteとは違い、返り値のスライスを利用するようです。

Insert

season := []string{"Spring", "Summer", "Winter"}
season = slices.Insert(season, 2, "Autumn")
fmt.Println(season) // [Spring Summer Autumn Winter]

// 複数の要素を挿入可能
season = []string{"Sunday", "Monday", "Tuesday", "Friday", "Saturday"}
season = slices.Insert(season, 3, "Wednesday", "Thursday")
fmt.Println(season) // [Sunday Monday Tuesday Wednesday Thursday Friday Saturday]

// slicesパッケージを使わない場合
season = []string{"Spring", "Summer", "Winter"}
season = append(season[:2], "Autumn", season[2])
fmt.Println(season) // [Spring Summer Autumn Winter]

これもappendを使う従来の方法よりも直感的でわかりやすいコードになったと思います。

Replace

season := []string{"Spring", "夏", "秋", "Winter"}
season = slices.Replace(season, 1, 3, "Summer", "Autumn")
fmt.Println(season) // [Spring Summer Autumn Winter]

// slicesパッケージを使わない場合
season = []string{"Spring", "夏", "秋", "Winter"}
season = append(season[:1], "Summer", "Autumn", season[3])
fmt.Println(season) // [Spring Summer Autumn Winter]

Replaceは、上記のDeleteInsertを続けて行うような関数です。

Sort

numbers := []int{1, 3, 5, 2, 100, 50}
slices.Sort(numbers)
fmt.Println(numbers) // [1 2 3 5 50 100]

// slicesパッケージを使わない場合
numbers = []int{1, 3, 5, 2, 100, 50}
sort.Ints(numbers)
fmt.Println(numbers) // [1 2 3 5 50 100]

降順でソートしたい場合は、ソート後にReverseという関数を使えば実装できます。

SortFunc

type Person struct {
    name string
    age  int
}

p1 := Person{"Alice", 25}
p2 := Person{"Vera", 10}
p3 := Person{"Bob", 40}
p4 := Person{"Alice", 15}

persons := []Person{p1, p2, p3, p4}
fmt.Println(persons) // [{Alice 25} {Vera 10} {Bob 40} {Alice 15}]

slices.SortFunc(persons, func(a, b Person) int {
    if n := cmp.Compare(a.name, b.name); n != 0 {
        return n
    }

    return cmp.Compare(a.age, b.age)
})
fmt.Println(persons) // [{Alice 15} {Alice 25} {Bob 40} {Vera 10}]

// slicesパッケージを使わない場合
persons = []Person{p1, p2, p3, p4}
fmt.Println(persons) // [{Alice 25} {Vera 10} {Bob 40} {Alice 15}]

sort.Slice(persons, func(i, j int) bool {
    if persons[i].name == persons[j].name {
        return persons[i].age < persons[j].age
    }

    return persons[i].name < persons[j].name
})
fmt.Println(persons) // [{Alice 15} {Alice 25} {Bob 40} {Vera 10}]

SortFuncを使えば、様々な条件のソートを実装できます。上記のコードでは、名前順でソートし、名前で比較して違いがなければ、年齢でソートする、といった条件のソートを実装しました。

さいごに

Go1.21で新たに追加されたパッケージの中からslicesパッケージについて調べてみました。上でも書いたように、従来よりも直感的でわかりやすいコードを書けるようになっていると思います。また、slicesパッケージにあるSort関数と同じような機能は、以前からあるsortパッケージの関数にもありますが、現在はそれらの関数のドキュメントに、

Note: consider using the newer slices.Sort function, which runs faster.

などと書かれ、slicesパッケージの使用を推奨しています。なのでこれからスライスを操作するようなコードを書くときはまずこちらのslicesパッケージの使用を検討しましょう。

この記事を書いた人

wanderlust
wanderlust事業開発部 web application engineer
これまで農業、士業と経験し、まったく異業種のエンジニアとしてアーティスに入社。
現在は事業開発部でバックエンドエンジニアとして仕事に従事。可読性の高いコードが書けるよう日々勉強中。趣味は一人旅。
この記事のカテゴリ

FOLLOW US

最新の情報をお届けします