新機能
strings/bytesパッケージに、末尾から最後のセパレータで文字列を分割するCutLast関数を追加する
strings
この項目の注釈は AI により生成されており、誤りを含む場合があります。
使用例のコンパイル検証: 検証済み
概要
stringsパッケージおよびbytesパッケージにCutLast関数が追加される。既存のstrings.Cutがセパレータの最初の出現位置で文字列を分割するのに対し、CutLastはセパレータの最後の出現位置で分割する。セパレータが見つからない場合はs, "", falseを返す仕様であり、これはCutが見つからない場合にs, "", falseを返すのと対称的な設計である。内部的にはstrings.LastIndexを使った実装に相当する。
導入経緯
提案者は、文字列を末尾側から分割する処理(package-url仕様の一部パースなど)のために自作のCutLast関数を何度も書く必要があったことを動機として挙げている。議論の中で@rogpeppeは自身のコードベース内だけで少なくとも5つの同等の独自実装を発見したと報告しており、標準ライブラリでの提供に対する支持が広がった。
議論タイムライン
- 2026-03-25: Proposal Review Meetingで議題(active)として追加された。
- 2026-04-08: Proposal Review Meetingで likely accept と判定された。
- 2026-04-16: 前回ミーティングからコンセンサスに変化がないことが確認され、accepted となった。
議論のハイライト
- 関数名は
LastIndexとの一貫性を重視したLastCut案と、CutXファミリーへの帰属を重視したCutLast案が議論され、最終的にCutLastが採用された。 - 最大の争点は、セパレータが見つからない場合の戻り値である。@rogpeppeは自身が逆のセマンティクス(
"", s, false)で実装した関数を、実際にはbefore側に完全な文字列が入る前提のコードで誤用していたことを報告し、s, "", false(Cutと対称的な仕様)を支持する実証的な根拠となった。 CutSuffixとの混同が懸念されたが、戻り値の型が異なる(CutLastは3値、CutSuffixは2値)ため、実際の誤用は少ないと判断された。- 実装のCLが誤って自動マージ可能な状態になっており、コメント期間中に取り込まれてしまうという経緯があったが、その後のミーティングでコンセンサスに変化がないことが確認され、正式に承認された。
使用例
Before
package main
import (
"fmt"
"strings"
)
func cutLast(s, sep string) (before, after string, found bool) {
if i := strings.LastIndex(s, sep); i >= 0 {
return s[:i], s[i+len(sep):], true
}
return s, "", false
}
func main() {
dir, file, ok := cutLast("/usr/local/bin/go", "/")
fmt.Println(dir, file, ok)
}
After
package main
import (
"fmt"
"strings"
)
func main() {
dir, file, ok := strings.CutLast("/usr/local/bin/go", "/")
fmt.Println(dir, file, ok)
}
実装解説
strings.CutLastはstrings.go:1291で定義されており、LastIndexでセパレータの最後の出現位置を求め、見つかった場合はその前後で文字列を分割し、見つからない場合は元の文字列全体をbeforeとして返す。bytes.CutLastもbytes.go:1430に同様のロジックで実装されている。