メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#71151active

strings, bytes: add CutLast

新規提案

要約

AIによる要約であり、誤りを含む場合があります。

概要

strings および bytes パッケージに CutLast 関数を追加する提案です。既存の strings.Cut が先頭から最初のセパレータで文字列を分割するのに対し、CutLast は末尾から最後のセパレータで分割します。

ステータス変更

(未分類)active
2026年3月25日のProposal Review Meeting(@adonovan, @bradfitz, @cherrymui, @griesemer, @neild, @rolandshoemaker出席)において、週次レビューの議題(active)として正式に追加されました。@adonovanがissue内の議論を整理し、関数の意味論に関するコミュニティの実践的な経験を踏まえて、標準ライブラリへの追加を支持する見解をまとめたことが、activeへの移行を後押しした可能性があります。

技術的背景

現状の問題点

strings.Cut はGo 1.18で追加され、文字列を先頭から最初のセパレータで分割する便利な関数として広く利用されています。しかし、末尾から最後のセパレータで分割する対称的な操作は標準ライブラリに存在しないため、各開発者がそれぞれ独自に実装しています。
@rogpeppeが自身のコードベースで少なくとも5つの独自 cutLast 定義を発見するなど、この関数の需要は明確に存在します。標準化されていないため実装ごとに意味論が異なり、「セパレータが見つからない場合に何を返すか」という点で混乱が生じています。

提案された解決策

以下のシグネチャで CutLaststrings および bytes パッケージに追加します。

// CutLast slices s around the last instance of sep,
// returning the text before and after sep.
// The found result reports whether sep appears in s.
// If sep does not appear in s, CutLast returns s, "", false.
func CutLast(s, sep string) (before, after string, found bool)

内部実装は strings.LastIndex を使った単純なものです。

これによって何ができるようになるか

末尾から文字列を分割する操作を標準APIで簡潔に記述でき、各プロジェクトでの独自実装が不要になります。

コード例

// Before: 従来のワークアラウンド(独自実装が必要)
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
}
// 例: URLパスから最後のスラッシュで分割
path := "foo/bar/baz"
dir, base, ok := cutLast(path, "/")
// dir = "foo/bar", base = "baz", ok = true
// After: 標準ライブラリのCutLastを使った書き方
dir, base, ok := strings.CutLast(path, "/")
// dir = "foo/bar", base = "baz", ok = true

実践的なユースケースとして以下が挙げられます。

  • URLパスから最後のパスコンポーネントを分離する
  • ファイル名から拡張子を取り出す(filepath.Ext が使えない場合)
  • package-url 仕様のように末尾からの分割が必要なフォーマットを解析する

議論のハイライト

  • 関数名について: CutLastLastCut の二案が議論されました。@earthboundkidは LastIndex との一貫性から LastCut を推しましたが、提案者は CutLast を提案しており、コアチームの@rscも以前の関連issue(#46336)で LastCut という名前を使用していました。
  • セパレータが見つからない場合の戻り値: 最も議論になった設計上の決定です。提案の仕様では return s, "", false(元の文字列を before に返す)としていますが、return "", s, false(元の文字列を after に返す)とする実装例も存在しました。
  • rogpeppeの実証: @rogpeppeは自身が return "", s, false で実装した関数を繰り返し誤用していたことを報告し、return s, "", false の方が直感的に正しいことを実践的に証明しました。これはCutとの一貫性とも合致します。
  • adonovanの整理: @adonovanは「Cutはセパレータが見つからない場合に完全な文字列を最初の戻り値(before)に入れる」という設計と一貫させ、CutLastreturn s, "", false とすべきとまとめました。
  • 標準化の意義: 複数の開発者が独自実装を持ち、かつ意味論の違いによりバグが発生しているという事実が、標準ライブラリへの追加を正当化する根拠として挙げられています。

関連リンク