型と値の特性
値の表現
事前宣言された型(以下のインターフェースanyとerrorを参照)、配列、および構造体の値は自己完結型です:そのような各値はそのデータのすべての完全なコピーを含み、そのような型の変数は値全体を格納します。たとえば、配列変数は配列のすべての要素のストレージ(変数)を提供します。それぞれのゼロ値は値の型に固有であり、決してnilではありません。
nilではないポインタ、関数、スライス、マップ、およびチャネルの値には、複数の値によって共有される可能性のある基礎となるデータへの参照が含まれています:
- ポインタ値は、ポインタの基底型の値を保持する変数への参照です。
- 関数値は、(場合によっては匿名の)関数とその環境への参照を含みます。
- スライス値は、スライスの長さ、容量、および基底配列への参照を含みます。
- マップまたはチャネル値は、マップまたはチャネルの実装固有のデータ構造への参照です。
インターフェース値は、インターフェースの動的型に応じて、自己完結型であるか、基礎となるデータへの参照を含むことがあります。事前宣言された識別子nilは、参照を含むことができる型のゼロ値です。
複数の値が基礎となるデータを共有する場合、ある値を変更すると別の値も変更される可能性があります。たとえば、スライスの要素を変更すると、配列を共有するすべてのスライスの基底配列のその要素が変更されます。
基底型
各型Tには基底型があります:もしTが事前宣言されたブール型、数値型、または文字列型、あるいは型リテラルの一つである場合、対応する基底型はT自身です。それ以外の場合、Tの基底型は、Tがその宣言で参照する型の基底型です。型パラメータの場合、それは常にインターフェースである型制約の基底型です。
type (
A1 = string
A2 = A1
)
type (
B1 string
B2 B1
B3 []B1
B4 B3
)
func f[P any](x P) { … }string、A1、A2、B1、およびB2の基底型はstringです。[]B1、B3、およびB4の基底型は[]B1です。Pの基底型はinterface{}です。
型の同一性
二つの型は同一(「同じ」)であるか、または異なるかのいずれかです。
名前付き型は常に他の型とは異なります。それ以外の場合、二つの型は、その基底型リテラルが構造的に等価である場合に同一です;つまり、それらは同じリテラル構造を持ち、対応するコンポーネントが同一の型を持ちます。詳細には:
- 二つの配列型は、同一の要素型と同じ配列の長さを持つ場合に同一です。
- 二つのスライス型は、同一の要素型を持つ場合に同一です。
- 二つの構造体型は、同じフィールドのシーケンスを持ち、対応するフィールドのペアが同じ名前、同一の型、同一のタグを持ち、かつ両方が埋め込まれているか、両方が埋め込まれていない場合に同一です。異なるパッケージからのエクスポートされていないフィールド名は常に異なります。
- 二つのポインタ型は、同一のベース型を持つ場合に同一です。
- 二つの関数型は、同じ数のパラメータと結果値を持ち、対応するパラメータと結果の型が同一であり、かつ両方の関数が可変引数を持つか、両方とも持たない場合に同一です。パラメータと結果の名前は一致する必要はありません。
- 二つのインターフェース型は、同じ型セットを定義する場合に同一です。
- 二つのマップ型は、同一のキーと要素の型を持つ場合に同一です。
- 二つのチャネル型は、同一の要素型と同じ方向を持つ場合に同一です。
- 二つのインスタンス化された型は、それらの定義された型とすべての型引数が同一である場合に同一です。
以下の宣言が与えられた場合:
type (
A0 = []string
A1 = A0
A2 = struct{ a, b int }
A3 = int
A4 = func(A3, float64) *A0
A5 = func(x int, _ float64) *[]string
B0 A0
B1 []string
B2 struct{ a, b int }
B3 struct{ a, c int }
B4 func(int, float64) *B0
B5 func(x int, y float64) *A1
C0 = B0
D0[P1, P2 any] struct{ x P1; y P2 }
E0 = D0[int, string]
)これらの型は同一です:
A0, A1, and []string
A2 and struct{ a, b int }
A3 and int
A4, func(int, float64) *[]string, and A5
B0 and C0
D0[int, string] and E0
[]int and []int
struct{ a, b *B5 } and struct{ a, b *B5 }
func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5B0とB1は、それらが別々の型定義によって作成された新しい型であるため異なります;func(int, float64) *B0とfunc(x int, y float64) *[]stringは、B0が[]stringとは異なるため異なります;またP1とP2は、それらが異なる型パラメータであるため異なります。D0[int, string]とstruct{ x int; y string }は、前者がインスタンス化された定義型であるのに対し、後者は型リテラルであるため異なります(ただし、それらは依然として代入可能です)。
代入可能性
型Vの値xが型Tの変数に代入可能である(「xはTに代入可能」)のは、以下の条件のいずれかが適用される場合です:
VとTが同一である。VとTが同一の基底型を持ち、型パラメータではなく、かつVまたはTの少なくとも一方が名前付き型ではない。VとTが同一の要素型を持つチャネル型であり、Vが双方向チャネルであり、かつVまたはTの少なくとも一方が名前付き型ではない。Tがインターフェース型であり、型パラメータではなく、かつxがTを実装している。xが事前宣言された識別子nilであり、Tがポインタ型、関数型、スライス型、マップ型、チャネル型、またはインターフェース型であり、型パラメータではない。xが型Tの値によって表現可能な型付けされていない定数である。
さらに、xの型VまたはTが型パラメータである場合、xが型Tの変数に代入可能なのは、以下の条件のいずれかが適用される場合です:
xが事前宣言された識別子nilであり、Tが型パラメータであり、かつxがTの型セット内のすべての型に代入可能である。Vが名前付き型ではなく、Tが型パラメータであり、かつxがTの型セット内のすべての型に代入可能である。Vが型パラメータであり、Tが名前付き型ではなく、かつVの型セット内のすべての型の値がTに代入可能である。
表現可能性
定数 x は、型パラメータではない型 T の値によって表現可能であるのは、以下の条件のいずれかが適用される場合です:
xがTによって決定される値の集合内にある。Tが浮動小数点型であり、xがオーバーフローなしにTの精度に丸めることができる。丸めは IEEE 754 の偶数丸めルールを使用しますが、IEEE の負のゼロはさらに符号なしゼロに簡略化されます。定数値は決して IEEE の負のゼロ、NaN、または無限大にはならないことに注意してください。Tが複素数型であり、xの成分real(x)とimag(x)がTの成分型(float32またはfloat64)の値によって表現可能である。
T が型パラメータである場合、x は T の型セット内のすべての型の値によって x が表現可能である場合に、型 T の値によって表現可能です。
x T x は T の値によって表現可能である理由
'a' byte 97 はバイト値の集合内にある
97 rune rune は int32 のエイリアスであり、97 は 32 ビット整数の集合内にある
"foo" string "foo" は文字列値の集合内にある
1024 int16 1024 は 16 ビット整数の集合内にある
42.0 byte 42 は符号なし 8 ビット整数の集合内にある
1e10 uint64 10000000000 は符号なし 64 ビット整数の集合内にある
2.718281828459045 float32 2.718281828459045 は 2.7182817 に丸められ、float32 値の集合内にある
-1e-1000 float64 -1e-1000 は IEEE の -0.0 に丸められ、さらに 0.0 に簡略化される
0i int 0 は整数値である
(42 + 0i) float32 42.0(虚部がゼロ)は float32 値の集合内にあるx T x が T の値によって表現可能ではない理由
0 bool 0 はブール値の集合内にない
'a' string 'a' はルーンであり、文字列値の集合内にない
1024 byte 1024 は符号なし 8 ビット整数の集合内にない
-1 uint16 -1 は符号なし 16 ビット整数の集合内にない
1.1 int 1.1 は整数値ではない
42i float32 (0 + 42i) は float32 値の集合内にない
1e1000 float64 1e1000 は丸めた後に IEEE の +Inf にオーバーフローするメソッドセット
型のメソッドセットは、その型のオペランドに対して呼び出し可能なメソッドを決定します。すべての型には(空の可能性もある)メソッドセットが関連付けられています:
- 定義型
Tのメソッドセットは、レシーバ型Tで宣言されたすべてのメソッドから構成されます。 - 定義型
Tへのポインタのメソッドセット(ここでTはポインタでもインターフェースでもない)は、レシーバ*TまたはTで宣言されたすべてのメソッドの集合です。 - インターフェース型のメソッドセットは、インターフェースの型セット内の各型のメソッドセットの交差です(結果のメソッドセットは通常、インターフェースで宣言されたメソッドの集合です)。
埋め込みフィールドを含む構造体(および構造体へのポインタ)にはさらに規則が適用され、構造体型のセクションで説明されています。その他の型には空のメソッドセットがあります。