spec: type inferred composite literals
要約
概要
コンポジットリテラル(構造体・スライス・マップのリテラル)において、代入先の型が静的に判明している場合に型名を省略できるようにする言語仕様の拡張提案です。2015年に初めて提起され、約10年の議論を経て2026年4月に likely accept(承認見込み)へ移行しました。
ステータス変更
active → likely accept
2026年4月8日のProposal Review Meeting(@aclements、@adonovan、@griesemer、@ianlancetaylor、@neild)において、長年の議論が成熟段階に達したと判断されました。@aclementsが仕様変更の具体的な定式化(assignabilityへの規則追加と文法変更)を提示し、コンパイラ実装が既存のインフラを活用できる点が確認されたことで、承認見込みとなりました。なお、ツール(特にgopls)への影響が大きいため、Go 1.27には間に合わず、Go 1.28を目標としています。
技術的背景
現状の問題点
Goのコンポジットリテラルは現状、一部の限定的な文脈(別のコンポジットリテラルの要素など)でのみ型名を省略できます。それ以外では常に型名を明示しなければならず、特に関数呼び出しや戻り値での冗長な記述が問題となっています。
// 現状: 関数呼び出しで型名の繰り返しが必要
type Options struct {
Level int
Verbose bool
}
func NewReader(r io.Reader, opts Options) *Reader { ... }
// 呼び出し側で型名を明示しなければならない
NewReader(r, Options{Level: 1, Verbose: true})
// スライスの要素でも同様
points := []image.Point{
image.Point{1, 2},
image.Point{3, 4},
}
提案された解決策
代入先の型が判明している「代入文脈(assignment context)」では、コンポジットリテラルの型名を省略可能にします。仕様上は、assignability(代入可能性)の定義に以下の規則を追加します。
値
xが{ <elements> }の形式の型なしコンポジットリテラルであり、同じ要素を持つ型付きコンポジットリテラルT{ <elements> }が型Tの有効なコンポジットリテラルである場合、xはT型の変数に代入可能である。
文法変更は以下のとおりです。
// 変更前
CompositeLit = LiteralType LiteralValue .
LiteralValue = "{" [ ElementList [ "," ] ] "}" .
// 変更後
CompositeLit = [ LiteralType ] UntypedLit .
UntypedLit = "{" [ ElementList [ "," ] ] "}" .
「代入文脈」として認められる場面は次のとおりです。
- 代入文の右辺(変数が明示的に型付けされている場合)
- 変数宣言の初期化値(型が明示されている場合)
- 関数の引数
- 戻り値(
return文) - 別のコンポジットリテラルの要素
- チャネルへの送信値
- マップのインデックス式のキー
これによって何ができるようになるか
型が文脈から明確に判断できるあらゆる場面でコンポジットリテラルの型名を省略でき、コードの冗長性が大幅に低減されます。
コード例
// Before: 現状の書き方(型名の繰り返し)
NewReader(r, Options{Level: compress.BestSpeed})
points := []image.Point{
image.Point{1, 2},
image.Point{3, 4},
image.Point{5, 6},
}
func fetchData() (Result, error) {
return Result{Value: 42}, nil
}
ch <- pkg.Message{Body: "hello"}
// After: 型推論コンポジットリテラルを使った書き方
NewReader(r, {Level: compress.BestSpeed})
points := []image.Point{
{1, 2},
{3, 4},
{5, 6},
}
func fetchData() (Result, error) {
return {Value: 42}, nil
}
ch <- {Body: "hello"}
テーブル駆動テストでの活用例(Go開発者に特に恩恵が大きいユースケース)。
// After: テストケース定義が簡潔になる
tests := []struct {
input string
want int
}{
{"foo", 1},
{"bar", 2},
{"baz", 3},
}
議論のハイライト
- 前史: Go 1 リリース前にも一度実装が試みられたが、「可読性が全体的に低下する」として撤回された経緯がある。今回はその教訓を踏まえ、約10年間にわたり慎重に議論が続けられた。
- 可読性に関する根本的な意見対立: 型名を省略することで読みやすくなる場面(例: 関数呼び出しの引数)と読みにくくなる場面(例: チャネル送信)の両方が存在し、強制的な自動変換ではなく開発者の裁量に委ねることで決着した。
gofmt -sのような既存ツールは、省略可能な型を自動削除しない方針。 - スタイルの非強制: 型名を書いても書かなくても構文的に両方正しい状態とし、どちらを選ぶかはコーディングスタイルの問題として扱う。
gopls等のIDEツールがホバー表示などで型情報を補完する方向性が示された。 - ツールへの影響が焦点: コンパイラ実装は既存インフラを活用でき比較的単純だが、
gopls(Go言語サーバー)への影響が大きい。型名がソース上に現れなくなるため、型でリテラルを検索する機能や型ヒント表示の改善が必要となり、リリース目標がGo 1.28に設定された。 - 未解決の詳細: 仕様内の既存「要素型の省略(Elision of element types)」節を廃止して整理できる見込みだが、詳細はTBD。ポインタ型の変数への代入(
*Tへのリテラル代入)も対象とする方向。