[インデックス 1036] ファイルの概要
コミット
- コミットハッシュ:
90e5574f1ca9aa695613484f5b0cbf4e6777f641
- 作成者: Ken Thompson ken@golang.org
- 日時: 2008年11月3日 15:32:49 -0800
- 要約: 可変長引数(...)の処理をGoの設計仕様に従って実装
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/90e5574f1ca9aa695613484f5b0cbf4e6777f641
元コミット内容
treat ... as agreed
only unencapsulated if passing one ddd
argument to one ddd parameter.
R=r
OCL=18376
CL=18376
変更ファイル: src/cmd/gc/walk.c
- 27行追加、10行削除
変更の背景
2008年11月の時点でのGoは、まだ開発初期段階にあり、言語仕様の詳細が固まっていく重要な時期でした。このコミットは、Go言語の可変長引数(...)の処理方法を正式に実装したものです。
Ken Thompson(Goの共同開発者の一人)が、可変長引数の「カプセル化」に関する仕様を実装しました。具体的には、「可変長引数から可変長パラメータに1つの引数を渡す場合のみ、カプセル化せずに直接渡す」という特別な処理を実装しています。
前提知識の解説
可変長引数(Variadic Functions)とは
可変長引数は、関数が任意の数の引数を受け取ることができる機能です。Go言語では「...」(三点リーダー、ellipsis)を使用してこれを表現します。
// 可変長引数の例
func sum(numbers ...int) int {
total := 0
for _, n := range numbers {
total += n
}
return total
}
Go言語の初期コンパイラ「gc」
- gcは「Go Compiler」の略称
- 2008年当時、Ken ThompsonがC言語で実装
- Go言語のソースコードをC言語に変換するトランスパイラとして開始
- 後にネイティブコード生成に進化
walk.cファイルの役割
walk.cは、Goコンパイラの「AST(抽象構文木)ウォーク」処理を担うファイルです。コンパイラがソースコードを解析した後、構文木を走査して意味解析や最適化を行います。
技術的詳細
実装された仕様
コミットメッセージによると、このコミットは「可変長引数から可変長パラメータに1つの引数を渡す場合のみ、カプセル化せずに直接渡す」という特別な処理を実装しています。
通常の可変長引数処理
一般的に、可変長引数は以下のように処理されます:
- 通常ケース: 複数の引数を構造体にまとめて渡す
- 特別ケース: 1つの可変長引数を1つの可変長パラメータに渡す場合、直接渡す
カプセル化の意味
- カプセル化あり: 引数を構造体に格納してポインタを渡す
- カプセル化なし: 引数を直接渡す(パフォーマンス向上)
コアとなるコードの変更箇所
変更箇所1: mkdotargs関数のシグネチャ変更
// 変更前
Node* mkdotargs(Node *r, Iter *saver, Node *nn, Type *l, int fp)
// 変更後
Node* mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp)
新しいパラメータrr
を追加して、次の引数を事前に確認できるようにしました。
変更箇所2: 特別ケースの判定ロジック
// 特別ケース判定の追加
// 可変長引数が1つで、かつ可変長パラメータが1つの場合
rr = listnext(&saver);
if(r != N && rr == N && isddd(r->type)) {
// 直接代入(カプセル化なし)
a = nod(OAS, nodarg(l, fp), r);
a = convas(a);
nn = list(a, nn);
return rev(nn);
}
変更箇所3: エラーチェックの追加
// DDDパラメータが最後でない場合のエラー処理
ll = structnext(&savel);
if(ll != T)
yyerror("... must be last argument");
コアとなるコードの解説
1. 引数の事前チェック
rr = listnext(&saver);
次の引数を事前に取得し、可変長引数が1つしかないかを判定します。
2. 特別ケースの判定
if(r != N && rr == N && isddd(r->type))
この条件文は以下を確認します:
r != N
: 現在の引数が存在するrr == N
: 次の引数が存在しない(つまり引数が1つだけ)isddd(r->type)
: 現在の引数が可変長型である
3. 直接代入処理
a = nod(OAS, nodarg(l, fp), r);
a = convas(a);
nn = list(a, nn);
return rev(nn);
特別ケースでは、構造体にカプセル化せずに直接代入を行います。
4. 通常の処理
// 通常ケース -- 残りの引数を構造体にまとめて
// 可変長パラメータ(空インターフェース)にポインタを渡す
nn = mkdotargs(r, rr, &saver, nn, l, fp);
複数の引数がある場合は、従来通り構造体にまとめて処理します。