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

[インデックス 1006] 構造体フィールドのアノテーション文字列機能の実装

コミット

  • コミットハッシュ: f27aaf4819495aaa1b664c27e6e7dfd47059bffb
  • 作成者: Russ Cox rsc@golang.org
  • 日付: 2008年10月30日 午後3時13分(Pacific Time)
  • コミットメッセージ: structure field annotation strings

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/f27aaf4819495aaa1b664c27e6e7dfd47059bffb

元コミット内容

このコミットは、Go言語の構造体フィールドにアノテーション文字列(現在のGoの構造体タグ)を追加する機能を実装したものです。変更されたファイルは以下の通りです:

  • src/cmd/gc/dcl.c: 14行追加
  • src/cmd/gc/go.h: 1行追加
  • src/cmd/gc/go.y: 10行追加、1行削除
  • src/cmd/gc/subr.c: 9行追加、3行削除

合計で30行追加、4行削除の変更が行われました。

変更の背景

2008年10月の時点で、Go言語はまだ開発初期段階にありました。Go言語の設計は2007年9月に開始され、2008年1月にはKen Thompsonが最初のコンパイラーの開発を開始しました。この時期のコンパイラーは、後にgcと呼ばれるGoの標準コンパイラーの前身となる重要な基盤でした。

Russ Coxは2008年にGoogleのGoチームに参加し、初期のGoコンパイラー、ランタイム、そして後のGo 1.5でのブートストラップの開発に携わりました。このコミットは、Go言語の型システムにおける重要な機能の一つである構造体フィールドアノテーション(構造体タグ)の実装を示しています。

この機能の実装は、後にGoの標準ライブラリーでJSON/XMLエンコーディングパッケージなどで広く使用されることになる重要な言語機能の基盤となりました。

前提知識の解説

Go言語コンパイラー(gc)の構造

Go言語の「標準」コンパイラーは、Google GoチームがサポートするGo toolchainの一部であり、gcと呼ばれます。初期のgcはCで書かれていました。これは、ブートストラップの困難さのためです(Go環境を設定するにはGoコンパイラーが必要でした)。しかし、Go 1.5リリース以降、コンパイラーはGoプログラムになりました。

yacc(Yet Another Compiler Compiler)

このコミットで変更されているgo.yファイルは、yacc文法ファイルです。yaccは、コンパイラーの構文解析部分を生成するツールです。Go言語の初期コンパイラーでは、yacc文法を使用してGoソースコードの構文解析を行っていました。

構造体フィールドアノテーション

構造体フィールドアノテーション(現在のGoの構造体タグ)は、フィールド宣言の後に続くオプションの文字列リテラルタグです。これらのタグは、対応するフィールド宣言のすべてのフィールドの属性となります。タグはリフレクションインターフェースを通じて見えるようになり、構造体の型同一性に関与しますが、それ以外は無視されます。

技術的詳細

1. 文法の拡張(go.y)

%type <val> oliteral

structdcl:
    // ... existing rules ...
|   new_name type oliteral
    {
        $$ = nod(ODCLFIELD, $1, N);
        $$->type = $2;
        $$->val = $3;
    }

oliteral:
    {
        $$.ctype = CTxxx;
    }
|   LLITERAL

この変更により、構造体フィールド宣言の文法が拡張され、フィールド名と型の後にオプションのリテラル(文字列)を含めることができるようになりました。

2. 型定義の拡張(go.h)

struct Type
{
    // ... existing fields ...
    // TFIELD
    Type*   down;       // also used in TMAP
    String* note;       // literal string annotation
    // ... other fields ...
};

Type構造体にnoteフィールドが追加されました。これは文字列アノテーションを格納するためのフィールドです。

3. 宣言処理の実装(dcl.c)

String *note;

// ...

note = nil;

// ...

switch(n->val.ctype) {
case CTSTR:
    note = n->val.u.sval;
    break;
default:
    yyerror("structure field annotation must be string");
case CTxxx:
    note = nil;
    break;
}

f = typ(TFIELD);
f->type = n->type;
f->note = note;

この実装では、構造体フィールドの宣言時にアノテーション文字列の処理が行われます。アノテーションは文字列でなければならず、そうでない場合はエラーが発生します。

4. 型の表示処理(subr.c)

if(t->sym == S || t->embedded) {
    if(exporting)
        fmtprint(fp, "? ");
    fmtprint(fp, "%T", t->type);
} else
    fmtprint(fp, "%hS %T", t->sym, t->type);
if(t->note)
    fmtprint(fp, " \"%Z\"", t->note);
return 0;

型の表示処理では、フィールドのアノテーション文字列がある場合、それを引用符で囲んで表示するようになりました。

コアとなるコードの変更箇所

1. 文法規則の追加(go.y:1384-1389)

|   new_name type oliteral
    {
        $$ = nod(ODCLFIELD, $1, N);
        $$->type = $2;
        $$->val = $3;
    }

2. 型構造体の拡張(go.h:63)

String* note;           // literal string annotation

3. アノテーション処理ロジック(dcl.c:38-47)

switch(n->val.ctype) {
case CTSTR:
    note = n->val.u.sval;
    break;
default:
    yyerror("structure field annotation must be string");
case CTxxx:
    note = nil;
    break;
}

4. 型表示の修正(subr.c:119-120)

if(t->note)
    fmtprint(fp, " \"%Z\"", t->note);

コアとなるコードの解説

文法レベルでの変更

go.yファイルでの変更は、Go言語の構文解析レベルでの根本的な拡張です。構造体フィールドの宣言において、フィールド名と型の後にオプションのリテラル(アノテーション文字列)を受け入れるように文法が拡張されました。

oliteral規則は、オプションのリテラルを定義します。これは空(CTxxx)または実際のリテラル値(LLITERAL)のいずれかです。

型システムレベルでの変更

go.hでのType構造体へのnoteフィールドの追加は、Go言語の型システムにおける基本的な拡張です。これにより、各フィールドタイプがアノテーション文字列を持つことができるようになりました。

セマンティクス処理での変更

dcl.cでのstotype関数の変更は、構文解析された構造体フィールド宣言を実際の型情報に変換する際の処理です。ここでは、アノテーション値の型チェックが行われ、文字列でない場合はエラーが発生します。

表示処理での変更

subr.cでのTpretty関数の変更は、型情報をテキスト形式で表示する際の処理です。アノテーション文字列がある場合、それを引用符で囲んで表示します。

関連リンク

参考にした情報源リンク