The Go Programming Language Specificationの翻訳、6回目です。
前回までの訳はGo言語仕様[日本語訳]にまとめてあります。


型と値の特性

2つの型があるとします。これらは同じ型であったり、異なる型であったり、互換性を持つ型どうしだったり、互換性を持たなかったりします。同じ型どうしは常に互換性を持っていますが、2つの型が互換性を持つからといって同一の型であるとは限りません。

型の同一性と互換性

型の同一性

2つの型の名前が同一の宣言によるものなら、これら2つの型は同一です(§宣言とスコープ)。名前を持つ型と、無名の型が同一の型であることはあり得ません。2つの無名の型が、対応する型リテラルが同じリテラル構造を持ち、かつ対応する構成要素が同一の型であれば、この2つは同一の型です。詳しく説明します。

  • 配列型の場合は、要素の型と配列の長さが同じであれば同一の型です。
  • スライス型の場合は、要素の型が同じであれば同一の型です。
  • 構造体型の場合は、フィールドの並び順と、対応するフィールドの名前と型が同じであれば同一の型です。このとき匿名フィールドどうしは同じ名前であるとみなされます。
  • ポインタ型の場合は、ベース型が同じであれば同一の型です。
  • 関数型の場合は、パラメータと戻り値の個数、および対応するパラメータと戻り値の型がそれぞれ同じであれば同一の型です。“…”パラメータはすべて同一の型として規定されています。パラメータと戻り値の名前は比較には使われません。
  • インタフェース型の場合は、同じ名前、同じ関数型のメソッド群を持っていれば同一の型です。メソッドの順序は関係ありません。
  • マップ型の場合は、キーと値の型が同じであれば同一の型です。
  • チャネル型の場合は、値の型と方向が同じであれば同一の型です。

型の互換性

型の互換性は、同一性ほどは厳密ではありません。型の名前の有り無しに関わらず、お互いの型リテラルが互換性を持ってさえいれば、2つの型には互換性があります。他の点において、型の互換性の定義は先ほど解説した型の同一性と同じなので、「同一」を「互換性を持つ」に置き換えてみてください。

宣言をおこないます。

type (
	T0 []string;
	T1 []string;
	T2 struct { a, b int };
	T3 struct { a, c int };
	T4 func (int, float) *T0;
	T5 func (x int, y float) *[]string;
)

次の型どうしは同一です。

T0 と T0
[]int と []int
struct { a, b *T5 } と struct { a, b *T5 }
func (x int, y float) *[]string と func (int, float) (result *[]string)

T0T1は同一でもなければ、互換性もありません。それは、これらが別個に宣言された名前付きの型であるためです。

次の型どうしは互換性があります。

T0 と T0
T0 と []string
T3 と struct { a int; c int }
T4 と func (x int, y float) *[]string

T2struct { a, c int }には互換性はありません。それはフィールド名が異なるためです。

代入の適合性

下の条件をひとつ以上満たすとき、静的な型Vの値であるvは、型Tに代入できます。

  • VTに互換性がある。
  • Tはインタフェース型であり、VT実装している。
  • Vは配列のポインタで、Tはそれと互換性のある要素型を持ったスライスであり、なおかつVTどちらかが名前を持たない。(代入後、スライスの変数は配列を参照するようになります。要素はコピーされるわけではありません。)
  • Vは双方向チャネルで、Tはそれと互換性のある要素型を持ったチャネルであり、すくなくともVTどちらかが名前を持たない。

Tが構造体のときは、Tの全フィールドがエクスポートされているか、またはTが宣言されているパッケージ内で代入が行われる必要があります。言い換えると構造体型の値を構造体型の変数に代入できるのは、構造体の全フィールドが個別に代入可能なときだけです。

型を持たない定数vが、型Tの値を正しく表すことができるならば、vは型Tに対し代入の適合性を持ちます。

事前宣言済み識別子nilは、ポインタ・関数・スライス・マップ・チャネル・インタフェース型いずれにも代入の適合性を持ち、それらの型のゼロ値を表します。

また、ブランク識別子にはどんな値でも代入可能です。

比較の適合性

あるケースを除き、すべての型は、互換性がある他の静的な型と値を比較することができます。数値型と文字列型の値は、全種類の比較演算子を使って比較することができますが、論理値型はイコールかそうでないかの比較のみできます。

コンポジット型の値は演算子==!=を使用して、イコールかそうでないか比較します。以下に但し書きがあります。

  • 配列および構造体は、どれとも比較できません。
  • スライスの値はnilとだけ比較できます。スライスの値がnilとなるのは、明示的にnilを代入したか、初期化されていないか、nil値を持つ他のスライスの値を代入したときだけです。
  • インタフェースの値がnilとイコールになるのは、nilを明示的に代入したか、初期化されていないか、nil値を持つ他のインタフェースの値を代入したときです。
  • nilと比較可能な型どうしは、2つの値がともにnilであればイコールであり、一方だけがnilであればイコールではありません。
  • ポインタの値は、双方が同じ位置を指し示していればイコールです。
  • 関数の値は、双方が同じ関数を参照していればイコールです。
  • チャネルとマップの値は、双方が同一のmakeの呼び出して作成されたときにイコールとなります(§スライス、マップ、チャネルの作成)。2つのチャネル型の値を比較する際、チャネルの型どうしが互換性を持っている必要がありますが、チャネルの方向は無視されます。
  • インタフェースの値は、双方の静的な型が互換性を持っていれば比較できます。イコールとなるのは双方が同じ動的な型をもち、かつその値自体がイコールのときだけです。