Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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. 通常ケース: 複数の引数を構造体にまとめて渡す
  2. 特別ケース: 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);

複数の引数がある場合は、従来通り構造体にまとめて処理します。

関連リンク

参考にした情報源リンク