[インデックス 1010] ファイルの概要
このコミットは、Go言語の仕様書 (doc/go_spec.txt
) に構造体フィールドタグの概念を導入するものです。これにより、構造体のフィールドにメタデータを付与する機能が言語レベルでサポートされるようになります。
コミット
- コミットハッシュ:
2e90e5424ee21cc3303bd2479e7ab5e935191326
- Author: Robert Griesemer gri@golang.org
- Date: Thu Oct 30 15:52:37 2008 -0700
- コミットメッセージ:
- language for struct field tags DELTA=17 (15 added, 0 deleted, 2 changed) OCL=18177 CL=18184
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2e90e5424ee21cc3303bd2479e7ab5e935191326
元コミット内容
このコミットは、Go言語の仕様に「構造体フィールドタグ」という新しい言語機能を導入することを目的としています。これにより、構造体の各フィールドに任意の文字列リテラルを「タグ」として付加できるようになります。このタグは、Goのコンパイラによって直接解釈されることはなく、リフレクションライブラリを通じて実行時にアクセス可能になります。
変更の背景
Go言語における構造体フィールドタグの導入は、主に以下の目的のためです。
- シリアライゼーション/デシリアライゼーション: JSON、XML、YAMLなどの異なるデータ形式との間でGoの構造体を変換する際に、フィールド名をカスタマイズしたり、特定のフィールドを無視したりするためのメタデータを提供します。例えば、Goのフィールド名と異なるJSONキーを使用したい場合に
json:"my_field_name"
のように指定できます。 - バリデーション: データバリデーションライブラリが、構造体のフィールドに対して特定の制約(例: 必須、最小/最大値、正規表現パターンなど)を定義するためにタグを利用できます。
- データベース操作 (ORM): データベースのORM(Object-Relational Mapping)ライブラリが、Goの構造体フィールドをデータベースのテーブルカラムにマッピングするためにタグを使用します。例えば、
db:"column_name"
のように指定して、Goのフィールド名と異なるカラム名を指定できます。 - カスタム動作: 開発者が独自のパッケージや内部ロジックのために、特定のフィールドにカスタムの指示やメタデータを提供するために使用できます。
- ドキュメンテーション: 副次的な目的として、タグはコード内のインラインドキュメンテーションとしても機能し、フィールドの意図や動作に関する追加のコンテキストを提供できます。
これらの機能は、Goの「明示性」の哲学に沿っており、データ変換が行われる際に予測可能な動作を保証し、「魔法」や隠れた推論を避けることを目的としています。
前提知識の解説
Goの構造体 (Struct)
Go言語における構造体は、異なるデータ型のフィールドをまとめた複合データ型です。C言語の構造体やJava/Pythonのクラスのインスタンス変数に似ています。構造体は、関連するデータを一つの論理的な単位として扱うために使用されます。
例:
type Person struct {
Name string
Age int
}
Goのリフレクション (Reflection)
Goのリフレクションは、プログラムが自身の構造(型、フィールド、メソッドなど)を検査し、実行時にそれらを操作する能力を指します。これにより、コンパイル時には未知の型や構造体に対しても汎用的な処理を記述することが可能になります。
構造体フィールドタグは、このリフレクションメカニズムを通じてアクセスされます。reflect
パッケージを使用することで、構造体のフィールド情報(名前、型、そしてタグ)を取得し、そのタグ文字列を読み取ることができます。
技術的詳細
このコミットによって導入される構造体フィールドタグは、Goの型システムにメタデータを付加するシンプルなメカニズムを提供します。
構文:
構造体フィールド宣言の最後に、バッククォート (
) で囲まれた文字列リテラルを追加することでタグを付与します。
FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] .
Tag = string_lit .
例:
type User struct {
ID int `json:"id" db:"user_id"`
Username string `json:"username,omitempty"`
Email string `json:"-"` // このフィールドはJSONに含めない
}
上記の例では、ID
フィールドには json:"id" db:"user_id"
というタグが、Username
フィールドには json:"username,omitempty"
というタグが、Email
フィールドには json:"-"
というタグが付与されています。
タグの利用:
タグはGoのコンパイラによって直接解釈されることはありません。その代わり、reflect
パッケージを使用して実行時にアクセスされます。
import (
"fmt"
"reflect"
)
type MyStruct struct {
Field1 string `my_tag:"value1"`
Field2 int `another_tag:"value2,option"`
}
func main() {
s := MyStruct{}
t := reflect.TypeOf(s)
field1, _ := t.FieldByName("Field1")
fmt.Println("Field1 tag:", field1.Tag.Get("my_tag")) // 出力: value1
field2, _ := t.FieldByName("Field2")
fmt.Println("Field2 tag:", field2.Tag.Get("another_tag")) // 出力: value2,option
}
reflect.StructTag
型は、タグ文字列を解析し、キーと値のペアとしてアクセスするための Get
メソッドを提供します。これにより、ライブラリやフレームワークは、構造体のフィールドに付加されたメタデータに基づいて動的な処理を行うことができます。
コアとなるコードの変更箇所
このコミットは、Go言語の仕様書 (doc/go_spec.txt
) のみを変更しています。実際のコンパイラやランタイムのコード変更は含まれていませんが、仕様書への追加が言語機能の正式な導入を意味します。
変更点は以下の通りです。
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -4,7 +4,7 @@ The Go Programming Language Specification (DRAFT)
Robert Griesemer, Rob Pike, Ken Thompson
----
-(October 28, 2008)
+(October 30, 2008)
This document is a semi-formal specification of the Go systems
@@ -1094,7 +1094,8 @@ identifier may be declared twice and all field types must be complete
types (§Types).
StructType = "struct" [ "{" [ List<FieldDecl> ] "}" ] .
- FieldDecl = IdentifierList CompleteType | TypeName .\n+\tFieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] .\n+\tTag = string_lit .\n \n // An empty struct.\n struct {}\n@@ -1135,6 +1136,20 @@ Fields and methods (§Method declarations) of an anonymous field become directly
accessible as fields and methods of the struct without the need to provide the
type name of the respective anonymous field (§Selectors).\n \n+A field declaration may be followed by an optional string literal tag which\n+becomes an ``attribute\'\' for all the identifiers in the corresponding\n+field declaration. The tags are available via the reflection library but\n+are ignored otherwise. A tag may contain arbitrary application-specific\n+information (for instance protocol buffer field information).\n+\n+\t// A struct corresponding to the EventIdMessage protocol buffer.\n+\t// The tag strings contain the protocol buffer field tags.\n+\tstruct {\n+\t\ttime_usec uint64 \"1\";\n+\t\tserver_ip uint32 \"2\";\n+\t\tprocess_id uint32 \"3\";\n+\t}\n+\n Forward declaration:\n A struct type consisting of only the reserved word \"struct\" may be used in\n a type declaration; it declares an incomplete struct type (§Type declarations).\n```
## コアとなるコードの解説
変更は主に `doc/go_spec.txt` の2つのセクションにあります。
1. **日付の更新**:
```diff
-(October 28, 2008)
+(October 30, 2008)
```
これは単に仕様書のドラフト日付を更新したものです。
2. **`StructType` および `FieldDecl` の定義変更**:
```diff
- FieldDecl = IdentifierList CompleteType | TypeName .
+ FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] .
+ Tag = string_lit .
```
この変更が最も重要です。
- `FieldDecl` (フィールド宣言) の定義に `[ Tag ]` が追加されました。これは、フィールド宣言の後にオプションで `Tag` を付加できることを意味します。
- `Tag = string_lit .` という新しい定義が追加されました。これは、`Tag` が文字列リテラルであることを明示しています。Go言語の文字列リテラルは、通常ダブルクォート (`"`) またはバッククォート (`` ` ``) で囲まれますが、構造体タグではバッククォートが慣例的に使用されます。
3. **構造体フィールドタグに関する説明の追加**:
```diff
+A field declaration may be followed by an optional string literal tag which
+becomes an ``attribute\'\' for all the identifiers in the corresponding
+field declaration. The tags are available via the reflection library but
+are ignored otherwise. A tag may contain arbitrary application-specific
+information (for instance protocol buffer field information).
+
+ // A struct corresponding to the EventIdMessage protocol buffer.
+ // The tag strings contain the protocol buffer field tags.
+ struct {
+ time_usec uint64 "1";
+ server_ip uint32 "2";
+ process_id uint32 "3";
+ }
```
このセクションでは、構造体フィールドタグの目的と動作について詳細に説明しています。
- 「フィールド宣言にはオプションの文字列リテラルタグが続くことができ、それは対応するフィールド宣言内のすべての識別子に対する『属性』となる」と説明しています。
- 「タグはリフレクションライブラリを通じて利用可能だが、それ以外では無視される」と明記しており、コンパイラがタグを直接解釈しないことを強調しています。
- 「タグには任意のアプリケーション固有の情報(例えばプロトコルバッファのフィールド情報)を含めることができる」と述べ、その汎用性を示しています。
- `EventIdMessage` プロトコルバッファに対応する構造体の例が示されており、プロトコルバッファのフィールドタグとして数値が文字列リテラルで指定されている具体的な使用例が提供されています。これは、タグがどのように外部システムとの連携に利用されるかを示す良い例です。
これらの変更により、Go言語の仕様に構造体フィールドタグの概念が正式に組み込まれ、Goプログラマは構造体フィールドにメタデータを付加し、リフレクションを通じてそのメタデータを利用できるようになりました。
## 関連リンク
- **GitHubコミットページ**: [https://github.com/golang/go/commit/2e90e5424ee21cc3303bd2479e7ab5e935191326](https://github.com/golang/go/commit/2e90e5424ee21cc3303bd2479e7ab5e935191326)
## 参考にした情報源リンク
- [Go struct tags: What are they and how to use them?](https://www.digitalocean.com/community/tutorials/go-struct-tags-what-are-they-and-how-to-use-them)
- [What are struct tags in Go? - Stack Overflow](https://stackoverflow.com/questions/24709293/what-are-struct-tags-in-go)
- [Go Struct Tags: A Comprehensive Guide - Medium](https://medium.com/@saurav.sahu/go-struct-tags-a-comprehensive-guide-221212121212)
- [Go Struct Tags - Coding Explorations](https://codingexplorations.com/go-struct-tags/)
- [Go Struct Tags - DoltHub](https://www.dolt.com/blog/go-struct-tags)
- [Go Struct Tags: The Definitive Guide - Buka.sh](https://buka.sh/go-struct-tags-the-definitive-guide/)
- [Go Struct Tags: A Deep Dive - Medium](https://medium.com/itnext/go-struct-tags-a-deep-dive-3f3f3f3f3f3f)
- [Go Wiki: Well known struct tags](https://go.dev/wiki/WellKnownStructTags)
- [Go Struct Tags - GitHub](https://github.com/golang/go/wiki/WellKnownStructTags)