Movatterモバイル変換


[0]ホーム

URL:


Future Tech Blog
フューチャー技術ブログ
Programmingカテゴリ

Go 1.22 リリース連載 slicesのマイナーアップデート

The Gopher character is based on the Go mascot designed byRenée French

はじめに

TIGの辻です。Go1.22連載の2本目です。

この記事では、マイナーアップデートから slices パッケージを取り上げて紹介します。

slices のアップデート内容

  • slice を連結するConcat() API が追加になった(#56353)
  • slice の長さを小さくする関数で、破棄された slice の要素をゼロ値とする(#63393)
  • Insert() で引数が範囲外の場合に、常に panic させる(#63913)

slice を連結するConcat() API が追加になった(#56353)

以下の API が追加になりました。渡された slice を連結して新しい slice を返却します

funcConcat[S ~[]E,Eany](slices ...S) S

コード例です

package main

import (
"fmt"
"slices"
)

funcmain() {
n1 := []int{1,2}
n2 := []int{10,20}
n3 := []int{100,200}
result := slices.Concat(n1, n2, n3)
fmt.Println(result)// [1 2 10 20 100 200]
}

ちなみにGo 1.21ですと appned() では複数の slice を連結できず、slice を unpack して以下のように実装する必要がありました。

package main

import (
"fmt"
)

funcmain() {
n1 := []int{1,2}
n2 := []int{10,20}
n3 := []int{100,200}
result :=append(n1,append(n2, n3...)...)
fmt.Println(result)// [1 2 10 20 100 200]
}

slice の長さを小さくする関数で、破棄された slice の要素をゼロ値とする(#63393)

以下のAPIの機能改善です。slice の長さが小さくなる関数で、破棄すべき slice の要素をゼロ値でクリアするようになっています

  • Delete()
  • DeleteFunc()
  • Compact()
  • CompactFunc()
  • Replace()

Delete() のコード例です

Go1.21

package main

import (
"fmt"
"slices"
)

funcmain() {
src := []int{1,2,3,4,5,6}
result := slices.Delete(src,1,3)

// 元の slice では Delete() 後に元々あった 4, 5番目の要素が残っている
fmt.Println(src)// [1 4 5 6 5 6]

fmt.Println(result)// [1 4 5 6]
}

Go1.22

package main

import (
"fmt"
"slices"
)

funcmain() {
src := []int{1,2,3,4,5,6}
result := slices.Delete(src,1,3)

// 元の slice では Delete() 後に元々あった 4, 5番目の要素はゼロ値でクリアされている
fmt.Println(src)// [1 4 5 6 0 0]

fmt.Println(result)// [1 4 5 6]
}

横道にそれますがDelete() に関して CL#541477 からコードの変更内容を見てみました。
https://go-review.googlesource.com/c/go/+/541477

変更前は要素を除いた値をappned() しているだけですが、変更後は明示的にclear() しています

  • 変更前
funcDelete[S ~[]E,Eany](s S, i, jint) S {
_ = s[i:j]// bounds check

returnappend(s[:i], s[j:]...)
}
  • 変更後
funcDelete[S ~[]E,Eany](s S, i, jint) S {
_ = s[i:j]// bounds check

oldlen :=len(s)
s =append(s[:i], s[j:]...)
clear(s[len(s):oldlen])// zero/nil out the obsolete elements, for GC
return s
}

Insert() で引数が範囲外の場合に、常に panic させる(#63913)

Insert() APIの機能改善です。
Go1.21では範囲外の Index が渡されても、挿入する要素が存在しない場合は panic しませんでした。
ただドキュメント上での説明ではInsert panics if i is out of range とあり動きにドキュメントと動作に乖離がありました。
https://pkg.go.dev/slices@go1.21.0#Insert

Go1.21では以下のコードが実行できます

Go1.21

package main

import (
"fmt"
"slices"
)

funcmain() {
s := []string{"a","b","c"}
s = slices.Insert(s,-1)// panic は起きない

fmt.Println(s)// [a b c]
}

ただし範囲外の Index に値を追加する場合はGo.1.21でも panic になります

package main

import (
"fmt"
"slices"
)

funcmain() {
s := []string{"a","b","c"}

// panic: runtime error: slice bounds out of range [:-1]
s = slices.Insert(s,-1,"x")// panic が起きる

fmt.Println(s)
}

Go1.22

Go1.22では範囲外の Index が指定されている場合は要素の有無に関わらず、panic するようになります

package main

import (
"fmt"
"slices"
)

funcmain() {
s := []string{"a","b","c"}

// panic: runtime error: slice bounds out of range [-1:]
s = slices.Insert(s,-1)// panic が起きる

fmt.Println(s)
}

おわりに

slices パッケージの機能追加/更新を紹介しました。
slices パッケージはGo1.21で標準ライブラリに追加されましたが、ユーザーに見える/見えにくい内容含めて、まだまだ進化しそうでこれからも楽しみですね

目次

  1. はじめに
  2. slices のアップデート内容
    1. slice を連結する Concat() API が追加になった(#56353)
    2. slice の長さを小さくする関数で、破棄された slice の要素をゼロ値とする(#63393)
      1. Go1.21
      2. Go1.22
    3. Insert() で引数が範囲外の場合に、常に panic させる(#63913)
      1. Go1.21
      2. Go1.22
  3. おわりに

カテゴリー


[8]ページ先頭

©2009-2025 Movatter.jp