- 言語バージョン go1.23 (2024年6月13日)
- はじめに
- 表記法
- ソースコードの表現
- 字句要素
- 定数
- 変数
- 型
- 型と値の特性
- ブロック
- 宣言とスコープ
- 式
- 文
- Built-in functions
- パッケージ
- プログラムの初期化と実行
- エラー
- 実行時パニック
- システムの考慮事項
- 付録
言語バージョン go1.23 (2024年6月13日)
はじめに
これはGoプログラミング言語のリファレンスマニュアルです。ジェネリクスのないGo1.18以前のバージョンはこちらで見つけることができます。詳細や他の文書についてはgo.devを参照してください。
Goはシステムプログラミングを念頭に置いて設計された汎用言語です。強い型付けがされており、ガベージコレクションが行われ、並行プログラミングに対する明示的なサポートがあります。プログラムはパッケージから構成されており、その特性により依存関係の効率的な管理が可能です。
構文はコンパクトで解析が簡単であり、統合開発環境などの自動ツールによる簡単な分析が可能です。
表記法
構文は拡張バックナウア形式(EBNF)の変種を使用して指定されています:
Syntax = { Production } .
Production = production_name "=" [ Expression ] "." .
Expression = Term { "|" Term } .
Term = Factor { Factor } .
Factor = production_name | token [ "…" token ] | Group | Option | Repetition .
Group = "(" Expression ")" .
Option = "[" Expression "]" .
Repetition = "{" Expression "}" .
生成物は、項と次の演算子から構成される式であり、優先順位が高い順に並んでいます:
| alternation
() grouping
[] option (0 or 1 times)
{} repetition (0 to n times)
小文字の生成物名は、字句(終端)トークンを識別するために使用されます。非終端はキャメルケースで表記されます。字句トークンは二重引用符""
またはバッククォート``
で囲まれています。
形式a … b
は、a
からb
までの文字の集合を代替として表します。水平省略記号…
は、仕様の他の場所でも使用され、さらに指定されていないさまざまな列挙やコードスニペットを非公式に示します。文字…
(...
の3文字とは異なる)は、Go言語のトークンではありません。
[Go 1.xx]の形式のリンクは、記述された言語機能(またはその一部)が言語バージョン1.xxで変更または追加されたことを示し、したがって、その言語バージョンをビルドするためには最低限そのバージョンが必要です。詳細については、付録のリンクされたセクションを参照してください。
ソースコードの表現
ソースコードはUTF-8でエンコードされたUnicodeテキストです。テキストは正規化されていないため、単一のアクセント付きコードポイントは、アクセントと文字を組み合わせて構成された同じ文字とは異なります。これらは2つのコードポイントとして扱われます。簡単のため、この文書ではソーステキスト内のUnicodeコードポイントを指すために、無条件の用語文字を使用します。
各コードポイントは異なります。たとえば、大文字と小文字の文字は異なる文字です。
実装制限:他のツールとの互換性のために、コンパイラはソーステキスト内のNUL文字(U+0000)を許可しない場合があります。
実装制限:他のツールとの互換性のために、コンパイラはソーステキスト内の最初のUnicodeコードポイントがUTF-8エンコードされたバイトオーダーマーク(U+FEFF)である場合、これを無視することがあります。ソース内の他の場所でバイトオーダーマークが許可されない場合があります。
文字
次の用語は特定のUnicode文字カテゴリを示すために使用されます:
= /* the Unicode code point U+000A */ .
= /* an arbitrary Unicode code point except newline */ .
= /* a Unicode code point categorized as "Letter" */ .
= /* a Unicode code point categorized as "Number, decimal digit" */ .
Unicode標準8.0のセクション4.5「一般カテゴリ」では、文字カテゴリのセットが定義されています。Goは、文字カテゴリLu、Ll、Lt、Lm、またはLoのすべての文字をUnicode文字として扱い、数字カテゴリNdの文字をUnicode数字として扱います。
文字と数字
アンダースコア文字_
(U+005F)は小文字の文字と見なされます。
= | "_" .
= "0" … "9" .
= "0" | "1" .
= "0" … "7" .
= "0" … "9" | "A" … "F" | "a" … "f" .
字句要素
コメント
コメントはプログラムのドキュメントとして機能します。2つの形式があります:
- 1. 行コメントは文字列
//
で始まり、行の終わりで終了します。 - 2. 一般コメントは文字列
/*
で始まり、最初の次の文字列*/
で終了します。
コメントはruneやstring literalの内部、またはコメントの内部で開始することはできません。改行を含まない一般コメントはスペースのように機能します。他のコメントは改行のように機能します。
トークン
トークンはGo言語の語彙を形成します。4つのクラスがあります:識別子、キーワード、演算子と句読点、およびリテラル。ホワイトスペースは、スペース(U+0020)、水平タブ(U+0009)、キャリッジリターン(U+000D)、および改行(U+000A)から構成され、トークンが結合されるのを防ぐために無視されます。また、改行またはファイルの終わりはセミコロンの挿入を引き起こす場合があります。入力をトークンに分割する際、次のトークンは有効なトークンを形成する最長の文字列のシーケンスです。
セミコロン
正式な構文では、セミコロン";"
がいくつかの生成物の終端子として使用されます。Goプログラムは、次の2つのルールを使用して、これらのセミコロンのほとんどを省略できます:
- 1. 入力がトークンに分割されると、行の最後のトークンの直後にトークンストリームに自動的にセミコロンが挿入されます。
- 2. 複雑な文が1行に収まるようにするために、閉じる
")"
または"}"
の前にセミコロンを省略できます。
この文書のコード例は、これらのルールを使用してセミコロンを省略しています。
識別子
識別子は変数や型などのプログラムエンティティに名前を付けます。識別子は1つ以上の文字と数字のシーケンスです。識別子の最初の文字は文字でなければなりません。
= { | } .
a
_x9
ThisVariableIsExported
αβ
一部の識別子は事前宣言済みです。
キーワード
次のキーワードは予約されており、識別子として使用することはできません。
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
演算子と句読点
次の文字列は演算子(代入演算子を含む)および句読点[Go 1.18]を表します:
+ & += &= && == != ( )
- | -= |= || < <= [ ]
* ^ *= ^= <- > >= { }
/ << /= <<= ++ = := , ;
% >> %= >>= -- ! ... . :
&^ &^= ~
整数リテラル
整数リテラルは、整数定数を表す数字のシーケンスです。オプションの接頭辞は非10進数の基数を設定します:0b
または0B
は2進数、0
、0o
、または0O
は8進数、0x
または0X
は16進数[Go 1.13]です。単一の0
は10進数のゼロと見なされます。16進数リテラルでは、文字a
からf
およびA
からF
は値10から15を表します。
可読性のために、アンダースコア文字_
は基数接頭辞の後または連続する数字の間に現れることがあります。このようなアンダースコアはリテラルの値を変更しません。
= | | | .
= "0" | ( "1" … "9" ) [ [ "_" ] ] .
= "0" ( "b" | "B" ) [ "_" ] .
= "0" [ "o" | "O" ] [ "_" ] .
= "0" ( "x" | "X" ) [ "_" ] .
= { [ "_" ] } .
= { [ "_" ] } .
= { [ "_" ] } .
= { [ "_" ] } .
42
4_2
0600
0_600
0o600
0O600 // second character is capital letter 'O'
0xBadFace
0xBad_Face
0x_67_7a_2f_cc_40_c6
170141183460469231731687303715884105727
170_141183_460469_231731_687303_715884_105727
_42 // an identifier, not an integer literal
42_ // invalid: _ must separate successive digits
4__2 // invalid: only one _ at a time
0_xBadFace // invalid: _ must separate successive digits
浮動小数点リテラル
浮動小数点リテラルは、浮動小数点定数の10進数または16進数の表現です。
10進浮動小数点リテラルは、整数部(10進数の数字)、小数点、分数部(10進数の数字)、および指数部(e
またはE
の後にオプションの符号と10進数の数字が続く)で構成されます。整数部または分数部のいずれかが省略される場合があります。小数点または指数部のいずれかが省略される場合があります。指数値expは、仮数(整数部と分数部)を10expでスケーリングします。
16進浮動小数点リテラルは、0x
または0X
の接頭辞、整数部(16進数の数字)、基数点、分数部(16進数の数字)、および指数部(p
またはP
の後にオプションの符号と10進数の数字が続く)で構成されます。整数部または分数部のいずれかが省略される場合があります。基数点も省略可能ですが、指数部は必須です。(この構文はIEEE 754-2008 §5.12.3で示されたものと一致します。)指数値expは、仮数(整数部と分数部)を2expでスケーリングします[Go 1.13]。
可読性のために、アンダースコア文字_
は基数接頭辞の後または連続する数字の間に現れることがあります。このようなアンダースコアはリテラルの値を変更しません。
= | .
= "." [ ] [ ] |
|
"." [ ] .
= ( "e" | "E" ) [ "+" | "-" ] .
= "0" ( "x" | "X" ) .
= [ "_" ] "." [ ] |
[ "_" ] |
"." .
= ( "p" | "P" ) [ "+" | "-" ] .
0.
72.40
072.40 // == 72.40
2.71828
1.e+0
6.67428e-11
1E6
.25
.12345E+5
1_5. // == 15.0
0.15e+0_2 // == 15.0
0x1p-2 // == 0.25
0x2.p10 // == 2048.0
0x1.Fp+0 // == 1.9375
0X.8p-0 // == 0.5
0X_1FFFP-16 // == 0.1249847412109375
0x15e-2 // == 0x15e - 2 (integer subtraction)
0x.p1 // invalid: mantissa has no digits
1p-2 // invalid: p exponent requires hexadecimal mantissa
0x1.5e-2 // invalid: hexadecimal mantissa requires p exponent
1_.5 // invalid: _ must separate successive digits
1._5 // invalid: _ must separate successive digits
1.5_e1 // invalid: _ must separate successive digits
1.5e_1 // invalid: _ must separate successive digits
1.5e1_ // invalid: _ must separate successive digits
虚数リテラル
虚数リテラルは、複素定数の虚数部分を表します。整数(#Integer_literals)または浮動小数点(#Floating-point_literals)リテラルの後に小文字のi
が続きます。虚数リテラルの値は、対応する整数または浮動小数点リテラルの値に虚数単位iを掛けたものです[Go 1.13]。
= ( | | ) "i" .
後方互換性のために、虚数リテラルの整数部分がすべて10進数の数字(および可能なアンダースコア)で構成されている場合、先頭の0
があっても10進数の整数と見なされます。
0i
0123i // == 123i for backward-compatibility
0o123i // == 0o123 * 1i == 83i
0xabci // == 0xabc * 1i == 2748i
0.i
2.71828i
1.e+0i
6.67428e-11i
1E6i
.25i
.12345E+5i
0x1p-2i // == 0x1p-2 * 1i == 0.25i
runeリテラル
runeリテラルは、rune定数を表し、Unicodeコードポイントを識別する整数値です。runeリテラルは、'x'
または'\n'
のように、単一引用符で囲まれた1つ以上の文字として表現されます。引用符内では、改行とエスケープされていない単一引用符以外の任意の文字が現れることができます。単一引用符で囲まれた文字は、その文字自体のUnicode値を表し、バックスラッシュで始まる複数の文字列はさまざまな形式で値をエンコードします。
最も単純な形式は、引用符内の単一の文字を表します。GoのソーステキストはUTF-8でエンコードされたUnicode文字であるため、複数のUTF-8エンコードされたバイトが単一の整数値を表すことがあります。たとえば、リテラル'a'
は、リテラルa
、Unicode U+0061、値0x61
を表す単一バイトを保持し、'ä'
はリテラルa
-ダイエレシス、U+00E4、値0xe4
を表す2バイトを保持します。
いくつかのバックスラッシュエスケープにより、任意の値をASCIIテキストとしてエンコードできます。整数値を数値定数として表現する方法は4つあります:\x
の後に正確に2つの16進数の数字、\u
の後に正確に4つの16進数の数字、\U
の後に正確に8つの16進数の数字、そして単純なバックスラッシュ\
の後に正確に3つの8進数の数字です。各ケースで、リテラルの値は対応する基数の数字によって表される値です。
これらの表現はすべて整数を生成しますが、有効範囲は異なります。8進数のエスケープは、0から255の範囲の値を表す必要があります。16進数のエスケープは、構造上この条件を満たします。エスケープ\u
および\U
はUnicodeコードポイントを表すため、その中にはいくつかの値が不正であり、特に0x10FFFF
を超える値やサロゲートハーフが含まれます。
バックスラッシュの後、特定の単一文字のエスケープは特別な値を表します:
\a U+0007 alert or bell
\b U+0008 backspace
\f U+000C form feed
\n U+000A line feed or newline
\r U+000D carriage return
\t U+0009 horizontal tab
\v U+000B vertical tab
\\ U+005C backslash
\' U+0027 single quote (valid escape only within rune literals)
\" U+0022 double quote (valid escape only within string literals)
runeリテラル内のバックスラッシュの後に認識されない文字があると、不正です。
= "'" ( | ) "'" .
= | | | .
= | .
= `\` .
= `\` "x" .
= `\` "u" .
= `\` "U"
.
= `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ) .
'a'
'ä'
'本'
'\t'
'\000'
'\007'
'\377'
'\x07'
'\xff'
'\u12e4'
'\U00101234'
'\'' // rune literal containing single quote character
'aa' // illegal: too many characters
'\k' // illegal: k is not recognized after a backslash
'\xa' // illegal: too few hexadecimal digits
'\0' // illegal: too few octal digits
'\400' // illegal: octal value over 255
'\uDFFF' // illegal: surrogate half
'\U00110000' // illegal: invalid Unicode code point
文字列リテラル
文字列リテラルは、文字のシーケンスを連結して得られるstring constantを表します。2つの形式があります:生文字列リテラルと解釈された文字列リテラル。
生文字列リテラルは、`foo`
のようにバッククォートで囲まれた文字列のシーケンスです。引用符内では、バッククォート以外の任意の文字が現れることができます。生文字列リテラルの値は、引用符の間にある解釈されていない(暗黙的にUTF-8でエンコードされた)文字から構成される文字列です。特に、バックスラッシュには特別な意味はなく、文字列には改行を含めることができます。生文字列リテラル内のキャリッジリターン文字(’\r’)は、生文字列の値から削除されます。
解釈された文字列リテラルは、"bar"
のように二重引用符で囲まれた文字列のシーケンスです。引用符内では、改行とエスケープされていない二重引用符以外の任意の文字が現れることができます。引用符の間のテキストはリテラルの値を形成し、バックスラッシュエスケープはruneリテラル内でのように解釈されます(\'
は不正で\"
は合法です)、同じ制限があります。3桁の8進数(\
nnn)および2桁の16進数(\x
nn)のエスケープは、結果の文字列の個々のバイトを表します。他のすべてのエスケープは、個々の文字の(おそらく複数バイトの)UTF-8エンコーディングを表します。したがって、文字列リテラル内の\377
および\xFF
は、値0xFF
=255の単一バイトを表し、ÿ
、\u00FF
、\U000000FF
および\xc3\xbf
は、文字U+00FFのUTF-8エンコーディングの2バイト0xc3
0xbf
を表します。
= | .
= "`" { | } "`" .
= `"` { | } `"` .
\n` // same as "\\n\n\\n"
"\n"
"\"" // same as `"`
"Hello, world!\n"
"日本語"
"\u65e5本\U00008a9e"
"\xff\u00FF"
"\uD800" // illegal: surrogate half
"\U00110000" // illegal: invalid Unicode code point
これらの例はすべて同じ文字列を表します:
"日本語" // UTF-8 input text
"\u65e5\u672c\u8a9e" // the explicit Unicode code points
"\U000065e5\U0000672c\U00008a9e" // the explicit Unicode code points
"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" // the explicit UTF-8 bytes
ソースコードが文字を2つのコードポイントとして表す場合、たとえばアクセントと文字を組み合わせた形の場合、runeリテラルに配置するとエラーが発生し(単一のコードポイントではないため)、文字列リテラルに配置すると2つのコードポイントとして表示されます。
定数
定数にはブール定数、rune定数、整数定数、浮動小数点定数、複素定数、および文字列定数があります。rune、整数、浮動小数点、および複素定数は総称して数値定数と呼ばれます。
定数値はrune、整数、浮動小数点、虚数、またはstringリテラル、定数を示す識別子、定数式、定数の結果を持つ変換、またはmin
やmax
のような定数引数に適用されるいくつかの組み込み関数の結果値、unsafe.Sizeof
のような特定の値に適用される、cap
やlen
のようないくつかの式に適用される、real
およびimag
のような複素定数に適用される、または数値定数に適用されるcomplex
の結果値で表されます。ブールの真理値は、事前宣言された定数true
およびfalse
で表されます。事前宣言された識別子iotaは整数定数を示します。
一般に、複素定数は定数式の一形態であり、そのセクションで議論されます。
数値定数は任意の精度の正確な値を表し、オーバーフローしません。したがって、IEEE 754の負のゼロ、無限大、非数値を示す定数は存在しません。
定数は型を持つか無型である可能性があります。リテラル定数、true
、false
、iota
、および無型の定数オペランドのみを含む特定の定数式は無型です。
定数は、定数宣言または変換によって明示的に型を与えられるか、変数宣言や代入文で使用されるとき、または式のオペランドとして使用されるときに暗黙的に型を与えられます。定数値がそれぞれの型の値として表現できない場合、エラーが発生します。型が型パラメータである場合、定数は型パラメータの非定数値に変換されます。
無型定数にはデフォルト型があり、これは定数が型付き値が必要なコンテキストで暗黙的に変換される型です。たとえば、i := 0
のような短い変数宣言では、明示的な型がありません。無型定数のデフォルト型はbool
、rune
、int
、float64
、complex128
、またはstring
であり、それぞれブール、rune、整数、浮動小数点、複素、または文字列定数に応じて異なります。
実装制限:数値定数は言語内で任意の精度を持ちますが、コンパイラは内部表現を使用して制限された精度で実装する場合があります。とはいえ、すべての実装は次のことを行わなければなりません:
- 整数定数を少なくとも256ビットで表現する。
- 浮動小数点定数、複素定数の部分を含む、少なくとも256ビットの仮数と少なくとも16ビットの符号付き2進数指数で表現する。
- 整数定数を正確に表現できない場合はエラーを出す。
- 浮動小数点または複素定数をオーバーフローのために表現できない場合はエラーを出す。
- 精度の制限により浮動小数点または複素定数を表現できない場合は、最も近い表現可能な定数に丸める。
これらの要件は、リテラル定数と定数式の評価結果の両方に適用されます。
変数
変数は値を保持するためのストレージ位置です。許可される値のセットは、変数の型によって決まります。
変数宣言または、関数のパラメータと結果の場合、関数宣言または関数リテラルのシグネチャは、名前付き変数のストレージを予約します。組み込み関数new
を呼び出すか、複合リテラルのアドレスを取得すると、実行時に変数のストレージが割り当てられます。このような匿名変数は、(おそらく暗黙的な)ポインタ間接参照を介して参照されます。
構造化変数の配列、スライス、および構造体型には、個別にアドレス指定できる要素とフィールドがあります。各要素は変数のように機能します。
変数の静的型(または単に型)は、その宣言で与えられた型、new
呼び出しまたは複合リテラルで提供された型、または構造化変数の要素の型です。インターフェース型の変数は、実行時に変数に割り当てられた値の(非インターフェース)型である異なる動的型も持ちます(値が事前宣言された識別子nil
である場合は、型がありません)。動的型は実行中に変化する可能性がありますが、インターフェース変数に格納された値は常に変数の静的型に代入可能です。
var x interface{} // x is nil and has static type interface{}
var v *T // v has value nil, static type *T
x = 42 // x has value 42 and dynamic type int
x = v // x has value (*T)(nil) and dynamic type *T
変数の値は、式内で変数を参照することによって取得されます。これは、変数に代入された最も最近の値です。変数にまだ値が割り当てられていない場合、その値はその型のゼロ値です。
型
型は、特定の値に固有の操作とメソッドを持つ値のセットを決定します。型には型名が付けられる場合があり、型がジェネリックである場合は型引数が続かなければなりません。型は、既存の型から型を構成する型リテラルを使用して指定することもできます。
= [ ] | | "(" ")" .
= | .
= "[" [ "," ] "]" .
= { "," } .
= | | | | |
| | .
言語は特定の型名を事前宣言します。他の型名は、型宣言や型パラメータリストで導入されます。複合型—配列、構造体、ポインタ、関数、インターフェース、スライス、マップ、およびチャネル型—は、型リテラルを使用して構築できます。
事前宣言された型、定義された型、および型パラメータは名前付き型と呼ばれます。エイリアスは、エイリアス宣言で与えられた型が名前付き型である場合、名前付き型を示します。
ブール型
ブール型は、事前宣言された定数true
およびfalse
によって示されるブール真理値のセットを表します。事前宣言されたブール型はbool
であり、これは定義された型です。
数値型
整数、浮動小数点、または複素型は、それぞれ整数、浮動小数点、または複素値のセットを表します。これらは総称して数値型と呼ばれます。事前宣言されたアーキテクチャ非依存の数値型は:
uint8 the set of all unsigned 8-bit integers (0 to 255)
uint16 the set of all unsigned 16-bit integers (0 to 65535)
uint32 the set of all unsigned 32-bit integers (0 to 4294967295)
uint64 the set of all unsigned 64-bit integers (0 to 18446744073709551615)
int8 the set of all signed 8-bit integers (-128 to 127)
int16 the set of all signed 16-bit integers (-32768 to 32767)
int32 the set of all signed 32-bit integers (-2147483648 to 2147483647)
int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
float32 the set of all IEEE 754 32-bit floating-point numbers
float64 the set of all IEEE 754 64-bit floating-point numbers
complex64 the set of all complex numbers with float32 real and imaginary parts
complex128 the set of all complex numbers with float64 real and imaginary parts
byte alias for uint8
rune alias for int32
nビット整数の値はnビット幅であり、二の補数算術を使用して表現されます。
実装固有のサイズを持つ事前宣言された整数型のセットもあります:
uint either 32 or 64 bits
int same size as uint
uintptr an unsigned integer large enough to store the uninterpreted bits of a pointer value
ポータビリティの問題を避けるために、すべての数値型は定義された型であり、したがってbyte
を除いて異なります。byte
はuint8
のエイリアスであり、rune
はint32
のエイリアスです。異なる数値型が式や代入で混在する場合、明示的な変換が必要です。たとえば、int32
とint
は、特定のアーキテクチャで同じサイズを持っている場合でも、同じ型ではありません。
文字列型
文字列型は、文字列値のセットを表します。文字列値は(空である可能性のある)バイトのシーケンスです。バイトの数は文字列の長さと呼ばれ、決して負にはなりません。文字列は不変です:一度作成されると、文字列の内容を変更することは不可能です。事前宣言された文字列型はstring
であり、これは定義された型です。
文字列s
の長さは、組み込み関数len
を使用して発見できます。文字列が定数である場合、長さはコンパイル時定数です。文字列のバイトには、整数インデックス0からlen(s)-1
までアクセスできます。そのような要素のアドレスを取得することは不正です。s[i]
が文字列のi
番目のバイトである場合、&s[i]
は無効です。
配列型
配列は、単一の型の要素の番号付きシーケンスであり、要素型と呼ばれます。要素の数は配列の長さと呼ばれ、決して負にはなりません。
= "[" "]" .
= .
= .
長さは配列の型の一部であり、非負の定数として評価されなければなりません。配列a
の長さは、組み込み関数len
を使用して発見できます。要素には、整数インデックス0からlen(a)-1
までアクセスできます。配列型は常に1次元ですが、複数次元型を形成するために構成されることがあります。
[32]byte
[2*N] struct { x, y int32 }
[1000]*float64
[3][5]int
[2][2][2]float64 // same as [2]([2]([2]float64))
配列型T
は、T
型の要素を持つことはできません。また、T
をコンポーネントとして含む型を持つこともできません。これらの含まれる型が配列または構造体型のみである場合、直接的または間接的に。
// invalid array types
type (
T1 [10]T1 // element type of T1 is T1
T2 [10]struct{ f T2 } // T2 contains T2 as component of a struct
T3 [10]T4 // T3 contains T3 as component of a struct in T4
T4 struct{ f T3 } // T4 contains T4 as component of array T3 in a struct
)
// valid array types
type (
T5 [10]*T5 // T5 contains T5 as component of a pointer
T6 [10]func() T6 // T6 contains T6 as component of a function type
T7 [10]struct{ f []T7 } // T7 contains T7 as component of a slice in a struct
)
スライス型
スライスは、基になる配列の連続したセグメントの記述子であり、その配列からの要素の番号付きシーケンスへのアクセスを提供します。スライスタイプは、その要素型の配列のすべてのスライスのセットを示します。要素の数はスライスの長さと呼ばれ、決して負にはなりません。初期化されていないスライスの値はnil
です。
= "[" "]" .
スライスs
の長さは、組み込み関数len
を使用して発見できます。配列とは異なり、実行中に変更される可能性があります。要素には、整数インデックス0からlen(s)-1
までアクセスできます。特定の要素のスライスインデックスは、基になる配列の同じ要素のインデックスよりも小さい場合があります。
スライスは、一度初期化されると、その要素を保持する基になる配列に常に関連付けられます。したがって、スライスはその配列および同じ配列の他のスライスとストレージを共有します。対照的に、異なる配列は常に異なるストレージを表します。
スライスの基になる配列は、スライスの終わりを超えて拡張される場合があります。容量は、その範囲の測定値です:スライスの長さとスライスを超えた配列の長さの合計です。その容量までの長さのスライスは、元のスライスからスライスを作成することによって作成できます。スライスa
の容量は、組み込み関数cap(a)
を使用して発見できます。
特定の要素型T
の新しい初期化されたスライス値は、組み込み関数make
を使用して作成できます。この関数は、スライスタイプと長さおよびオプションで容量を指定するパラメータを受け取ります。make
で作成されたスライスは、常に新しい隠れた配列を割り当て、その返されたスライス値が参照します。つまり、実行すると
make([]T, length, capacity)
は、配列を割り当ててスライスするのと同じスライスを生成します。したがって、これらの2つの式は等価です:
make([]int, 50, 100)
new([100]int)[0:50]
配列と同様に、スライスは常に1次元ですが、高次元オブジェクトを構成するために構成されることがあります。配列の配列では、内部配列は構造上常に同じ長さですが、スライスのスライス(または配列のスライス)では、内部の長さは動的に変化する可能性があります。さらに、内部スライスは個別に初期化する必要があります。
Struct types
A struct is a sequence of named elements, called fields, each of which has a name and a type. Field names may be specified explicitly (IdentifierList) or implicitly (EmbeddedField). Within a struct, non-blank field names must be unique.
= "struct" "{" { ";" } "}" .
= ( | ) [ ] .
= [ "*" ] [ ] .
= .
// An empty struct.
struct {}
// A struct with 6 fields.
struct {
x, y int
u float32
_ float32 // padding
A *[]int
F func()
}
A field declared with a type but no explicit field name is called an embedded field. An embedded field must be specified as a type name T
or as a pointer to a non-interface type name *T
, and T
itself may not be a pointer type. The unqualified type name acts as the field name.
// A struct with four embedded fields of types T1, *T2, P.T3 and *P.T4
struct {
T1 // field name is T1
*T2 // field name is T2
P.T3 // field name is T3
*P.T4 // field name is T4
x, y int // field names are x and y
}
The following declaration is illegal because field names must be unique in a struct type:
struct {
T // conflicts with embedded field *T and *P.T
*T // conflicts with embedded field T and *P.T
*P.T // conflicts with embedded field T and *T
}
A field or method f
of an embedded field in a struct x
is called promoted if x.f
is a legal selector that denotes that field or method f
.
Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.
Given a struct type S
and a named type T
, promoted methods are included in the method set of the struct as follows:
- If
S
contains an embedded fieldT
, the method sets ofS
and*S
both include promoted methods with receiverT
. The method set of*S
also includes promoted methods with receiver*T
. If
S
contains an embedded field*T
, the method sets ofS
and*S
both include promoted methods with receiverT
or*T
.A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. An empty tag string is equivalent to an absent tag. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored.
struct {
x, y float64 "" // an empty tag string is like an absent tag
name string "any string is permitted as a tag"
_ [4]byte "ceci n'est pas un champ de structure"
}
// A struct corresponding to a TimeStamp protocol buffer.
// The tag strings define the protocol buffer field numbers;
// they follow the convention outlined by the reflect package.
struct {
microsec uint64 `protobuf:"1"`
serverIP6 uint64 `protobuf:"2"`
}
A struct type T
may not contain a field of type T
, or of a type containing T
as a component, directly or indirectly, if those containing types are only array or struct types.
// invalid struct types
type (
T1 struct{ T1 } // T1 contains a field of T1
T2 struct{ f [10]T2 } // T2 contains T2 as component of an array
T3 struct{ T4 } // T3 contains T3 as component of an array in struct T4
T4 struct{ f [10]T3 } // T4 contains T4 as component of struct T3 in an array
)
// valid struct types
type (
T5 struct{ f *T5 } // T5 contains T5 as component of a pointer
T6 struct{ f func() T6 } // T6 contains T6 as component of a function type
T7 struct{ f [10][]T7 } // T7 contains T7 as component of a slice in an array
)
ポインタ型
ポインタ型は、特定の型のすべての変数へのポインタの集合を示し、その型をポインタの基本型と呼びます。初期化されていないポインタの値はnil
です。
= "*" .
= .
*Point
*[4]int
関数型
関数型は、同じパラメータ型と結果型を持つすべての関数の集合を示します。関数型の初期化されていない変数の値はnil
です。
= "func" .
= [ ] .
= | .
= "(" [ [ "," ] ] ")" .
= { "," } .
= [ ] [ "..." ] .
パラメータまたは結果のリスト内では、名前(IdentifierList)はすべて存在するか、すべて存在しない必要があります。存在する場合、各名前は指定された型の1つの項目(パラメータまたは結果)を表し、署名内のすべての非空白の名前は一意でなければなりません。存在しない場合、各型はその型の1つの項目を表します。パラメータおよび結果リストは常に括弧で囲まれますが、名前のない結果が正確に1つだけある場合は、括弧なしの型として書くことができます。
関数シグネチャの最後の受け入れパラメータは、...
で接頭辞が付けられた型を持つことがあります。そのようなパラメータを持つ関数は可変引数と呼ばれ、そのパラメータに対してゼロまたはそれ以上の引数で呼び出すことができます。
func()
func(x int) int
func(a, _ int, z float32) bool
func(a, b int, z float32) (bool)
func(prefix string, values ...int)
func(a, b int, z float64, opt ...interface{}) (success bool)
func(int, int, float64) (float64, *[]int)
func(n int) func(p *T)
インターフェース型
インターフェース型は型集合を定義します。インターフェース型の変数は、インターフェースの型集合にある任意の型の値を格納できます。そのような型はインターフェースを実装すると言います。インターフェース型の初期化されていない変数の値はnil
です。
= "interface" "{" { ";" } "}" .
= | .
= .
= .
= { "|" } .
= | .
= "~" .
インターフェース型はインターフェース要素のリストによって指定されます。インターフェース要素はメソッドまたは型要素のいずれかであり、型要素は1つ以上の型項目の和集合です。型項目は単一の型または単一の基礎型です。
基本インターフェース
最も基本的な形のインターフェースは、(空である可能性のある)メソッドのリストを指定します。そのようなインターフェースによって定義される型集合は、すべてのメソッドを実装する型の集合であり、対応するメソッド集合はインターフェースによって指定されたメソッドで構成されます。メソッドのリストによって完全に定義できる型集合を持つインターフェースは基本インターフェースと呼ばれます。
// A simple File interface.
interface {
Read([]byte) (int, error)
Write([]byte) (int, error)
Close() error
}
明示的に指定された各メソッドの名前は一意であり、空白であってはなりません。
interface {
String() string
String() string // illegal: String not unique
_(x int) // illegal: method must have non-blank name
}
複数の型がインターフェースを実装することができます。たとえば、2つの型S1
とS2
がメソッド集合を持っている場合、
func (p T) Read(p []byte) (n int, err error)
func (p T) Write(p []byte) (n int, err error)
func (p T) Close() error
(ここでT
はS1
またはS2
のいずれかを表します)File
インターフェースはS1
とS2
の両方によって実装されます。他のメソッドS1
とS2
が何を持っているか、または共有しているかに関係なく。
インターフェースの型集合のメンバーであるすべての型は、そのインターフェースを実装します。任意の型は複数の異なるインターフェースを実装することができます。たとえば、すべての型は空のインターフェースを実装します。これはすべての(非インターフェース)型の集合を表します:
interface{}
便利のために、事前に宣言された型any
は空のインターフェースのエイリアスです。[Go 1.18]
同様に、次のインターフェース仕様を考慮してください。これは、Locker
というインターフェースを定義するためにtype declaration内に現れます:
type Locker interface {
Lock()
Unlock()
}
``````bash
func (p T) Lock() { … }
func (p T) Unlock() { … }
`
<a name="Embedded_interfaces"></a>
#### 埋め込みインターフェース
やや一般的な形で、インターフェース`````T`````は、(資格のある)インターフェース型名`````E`````をインターフェース要素として使用することができます。これは、`````E`````を`````T`````に*埋め込む*と呼ばれます[[Go 1.14](#Go_1.14)]。`````T`````の型集合は、`````T`````の明示的に宣言されたメソッドによって定義された型集合と、`````T`````の埋め込まれたインターフェースの型集合の*交差*です。言い換えれば、`````T`````の型集合は、`````T`````の明示的に宣言されたすべてのメソッドと、`````E`````のすべてのメソッドを実装するすべての型の集合です[[Go 1.18](#Go_1.18)]。
``````bash
type Reader interface {
Read(p []byte) (n int, err error)
Close() error
}
type Writer interface {
Write(p []byte) (n int, err error)
Close() error
}
// ReadWriter's methods are Read, Write, and Close.
type ReadWriter interface {
Reader // includes methods of Reader in ReadWriter's method set
Writer // includes methods of Writer in ReadWriter's method set
}
`
インターフェースを埋め込むとき、同じ名前のメソッドは同一のシグネチャを持たなければなりません。
type ReadCloser interface {
Reader // includes methods of Reader in ReadCloser's method set
Close() // illegal: signatures of Reader.Close and Close are different
}
一般インターフェース
最も一般的な形では、インターフェース要素は任意の型項目T
、または基礎型T
を指定する~T
の形式の項目、または項目の和t1|t2|…|tn
のいずれかである可能性があります[Go 1.18]。メソッド仕様とともに、これらの要素はインターフェースの型集合を次のように正確に定義することを可能にします:
- 空のインターフェースの型集合は、すべての非インターフェース型の集合です。
- 非空インターフェースの型集合は、そのインターフェース要素の型集合の交差です。
- メソッド仕様の型集合は、そのメソッドを含むすべての非インターフェース型の集合です。
- 非インターフェース型項目の型集合は、その型のみを含む集合です。
~T
の形式の項目の型集合は、基礎型がT
であるすべての型の集合です。- 項目の和
t1|t2|…|tn
の型集合は、項目の型集合の和です。
「すべての非インターフェース型の集合」という定義は、現在のプログラムで宣言されたすべての(非インターフェース)型だけでなく、すべての可能なプログラムのすべての可能な型を指し、したがって無限です。同様に、特定のメソッドを実装するすべての非インターフェース型の集合が与えられた場合、それらの型のメソッド集合の交差は、たとえ現在のプログラム内のすべての型がそのメソッドを別のメソッドとペアにする場合でも、正確にそのメソッドを含みます。
構造上、インターフェースの型集合には決してインターフェース型が含まれません。
// An interface representing only the type int.
interface {
int
}
// An interface representing all types with underlying type int.
interface {
~int
}
// An interface representing all types with underlying type int that implement the String method.
interface {
~int
String() string
}
// An interface representing an empty type set: there is no type that is both an int and a string.
interface {
int
string
}
``````bash
type MyInt int
interface {
~[]byte // the underlying type of []byte is itself
~MyInt // illegal: the underlying type of MyInt is not MyInt
~error // illegal: error is an interface
}
`
和の要素は型集合の和を示します:
// The Float interface represents all floating-point types
// (including any named types whose underlying types are
// either float32 or float64).
type Float interface {
~float32 | ~float64
}
``````bash
interface {
P // illegal: P is a type parameter
int | ~P // illegal: P is a type parameter
~int | MyInt // illegal: the type sets for ~int and MyInt are not disjoint (~int includes MyInt)
float32 | Float // overlapping type sets but Float is an interface
}
`
実装制限:和(1つ以上の項目を持つ)は、事前に宣言された識別子comparable
またはメソッドを指定するインターフェース、またはメソッドを指定するインターフェースを埋め込むことはできません。
基本でないインターフェースは、型制約としてのみ使用できるか、制約として使用される他のインターフェースの要素として使用できます。値や変数の型、または他の非インターフェース型の構成要素として使用することはできません。
var x Float // illegal: Float is not a basic interface
var x interface{} = Float(nil) // illegal
type Floatish struct {
f Float // illegal
}
インターフェース型T
は、T
を含む、またはT
を埋め込む型要素を直接または間接的に埋め込むことはできません。
// illegal: Bad may not embed itself
type Bad interface {
Bad
}
// illegal: Bad1 may not embed itself using Bad2
type Bad1 interface {
Bad2
}
type Bad2 interface {
Bad1
}
// illegal: Bad3 may not embed a union containing Bad3
type Bad3 interface {
~int | ~string | Bad3
}
// illegal: Bad4 may not embed an array containing Bad4 as element type
type Bad4 interface {
[10]Bad4
}
インターフェースの実装
型T
は、インターフェースI
を実装します。
T
はインターフェースでなく、I
の型集合の要素であるか、またはT
はインターフェースであり、T
の型集合がI
の型集合の部分集合である場合。
マップ型
マップは、要素型と呼ばれる1つの型の要素の無秩序なグループであり、キー型と呼ばれる別の型の一意のキーの集合によってインデックス付けされます。初期化されていないマップの値はnil
です。
= "map" "[" "]" .
= .
比較演算子==
と!=
は、キー型のオペランドに対して完全に定義されている必要があります。したがって、キー型は関数、マップ、またはスライスであってはなりません。キー型がインターフェース型である場合、これらの比較演算子は動的キー値に対して定義されている必要があります。失敗すると、ランタイムパニックが発生します。
map[string]int
map[*T]struct{ x, y float64 }
map[string]interface{}
マップ要素の数は、その長さと呼ばれます。マップm
の場合、組み込み関数len
を使用して発見でき、実行中に変更される可能性があります。要素は、代入を使用して実行中に追加され、インデックス式で取得されます。要素は、delete
およびclear
の組み込み関数で削除できます。
新しい空のマップ値は、組み込み関数make
を使用して作成され、マップ型とオプションの容量ヒントを引数として取ります:
make(map[string]int)
make(map[string]int, 100)
初期容量はそのサイズを制限しません:マップは、格納されているアイテムの数に応じて成長し、nil
マップを除きます。nil
マップは、空のマップと同等ですが、要素を追加することはできません。
チャネル型
チャネルは、並行して実行される関数が指定された要素型の値を送信および受信するためのメカニズムを提供します。初期化されていないチャネルの値はnil
です。
= ( "chan" | "chan" "<-" | "<-" "chan" ) .
オプションの<-
演算子は、チャネルの方向、送信または受信を指定します。方向が指定されている場合、チャネルは方向性であり、そうでない場合は双方向です。チャネルは、代入または明示的な変換によって、送信または受信のみに制約される場合があります。
chan T // can be used to send and receive values of type T
chan<- float64 // can only be used to send float64s
<-chan int // can only be used to receive ints
``````bash
chan<- chan int // same as chan<- (chan int)
chan<- <-chan int // same as chan<- (<-chan int)
<-chan <-chan int // same as <-chan (<-chan int)
chan (<-chan int)
`
新しい初期化されたチャネル値は、組み込み関数make
を使用して作成され、チャネル型とオプションの容量を引数として取ります:
make(chan int, 100)
容量は、要素の数で、チャネル内のバッファのサイズを設定します。容量がゼロまたは存在しない場合、チャネルはバッファなしであり、送信者と受信者の両方が準備が整ったときのみ通信が成功します。そうでない場合、チャネルはバッファ付きであり、バッファが満杯でない場合(送信)または空でない場合(受信)にブロックなしで通信が成功します。nil
チャネルは、通信の準備ができていないことはありません。
チャネルは、組み込み関数close
を使用して閉じることができます。受信演算子の多値代入形式は、受信した値がチャネルが閉じる前に送信されたかどうかを報告します。
単一のチャネルは、送信文、受信操作、および組み込み関数cap
およびlen
への呼び出しで、任意の数のゴルーチンによって使用され、さらなる同期なしに使用されます。チャネルは先入れ先出しのキューとして機能します。たとえば、1つのゴルーチンがチャネルに値を送信し、2つ目のゴルーチンがそれらを受信する場合、値は送信された順序で受信されます。
型と値の特性
基礎型
各型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) { … }
<a name="Core_types"></a>
### コア型
各非インターフェース型`````T`````には*コア型*があり、これは`````T`````の[基礎型](#Underlying_types)と同じです。
インターフェース`````T`````には、次の条件のいずれかが満たされる場合にコア型があります:
- 1*.* 単一の型`````U`````があり、これは`````T`````の[type set](#Interface_types)内のすべての型の[基礎型](#Underlying_types)です。
- 2*.* `````T`````の型集合には、同一の要素型`````E`````を持つ[チャネル型](#Channel_types)のみが含まれ、すべての方向性チャネルが同じ方向を持っています。
他のインターフェースにはコア型はありません。
インターフェースのコア型は、満たされる条件に応じて、次のいずれかです:
- 1*.* 型`````U`````; または
- 2*.* `````T`````が双方向チャネルのみを含む場合、または方向性チャネルの方向に応じて`````chan<- E`````または`````<-chan E`````の型。
定義上、コア型は[定義型](#Type_definitions)、[型パラメータ](#Type_parameter_declarations)、または[インターフェース型](#Interface_types)ではありません。
コア型を持つインターフェースの例:
``````bash
type Celsius float32
type Kelvin float32
interface{ int } // int
interface{ Celsius|Kelvin } // float32
interface{ ~chan int } // chan int
interface{ ~chan int|~chan<- int } // chan<- int
interface{ ~[]*data; String() string } // []*data
`
コア型を持たないインターフェースの例:
interface{} // no single underlying type
interface{ Celsius|float64 } // no single underlying type
interface{ chan int | chan<- string } // channels have different element types
interface{ <-chan int | chan<- int } // directional channels have different directions
一部の操作(スライス式、append
およびcopy
)は、バイトスライスや文字列を受け入れるやや緩い形式のコア型に依存しています。具体的には、T
の型集合内のすべての型の基礎型が[]byte
とstring
の2つの型である場合、T
のコア型はbytestring
と呼ばれます。
``````bash
interface{ int } // int (same as ordinary core type)
interface{ []byte | string } // bytestring
interface{ ~[]byte | myString } // bytestring
`
<a name="Type_identity"></a>
### 型の同一性
二つの型は、*同一*または*異なる*です。
[名前付き型](#Types)は、他のどの型とも常に異なります。そうでない場合、二つの型は、[基礎](#Types)型リテラルが構造的に同等である場合に同一です。つまり、同じリテラル構造を持ち、対応するコンポーネントが同一の型を持つ必要があります。詳細は以下の通りです:
- 二つの配列型は、要素型が同一であり、配列の長さが同じであれば同一です。
- 二つのスライスタイプは、要素型が同一であれば同一です。
- 二つの構造体型は、フィールドの順序が同じであり、対応するフィールドが同じ名前を持ち、同一の型および同一のタグを持つ場合に同一です。[非エクスポート](#Exported_identifiers)フィールド名は、異なるパッケージからは常に異なります。
- 二つのポインタ型は、基礎型が同一であれば同一です。
- 二つの関数型は、パラメータと結果の数が同じで、対応するパラメータと結果の型が同一であり、両方の関数が可変長引数であるか、どちらもそうでない場合に同一です。パラメータと結果の名前は一致する必要はありません。
- 二つのインターフェース型は、同じ型セットを定義している場合に同一です。
- 二つのマップ型は、キー型と要素型が同一であれば同一です。
- 二つのチャネル型は、要素型が同一であり、同じ方向を持つ場合に同一です。
- 二つの[インスタンス化された](#Instantiations)型は、定義された型とすべての型引数が同一であれば同一です。
宣言が与えられた場合
``````bash
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 A5
B0
と B1
は異なります。なぜなら、異なるtype definitionsによって作成された新しい型だからです。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
の型V
またはT
が型パラメータである場合、x
は型T
の変数に代入可能です。次のいずれかの条件が適用されます: x
は事前宣言された識別子nil
であり、T
は型パラメータであり、x
はT
の型セット内の各型に代入可能です。V
は名前付き型ではなく、T
は型パラメータであり、x
はT
の型セット内の各型に代入可能です。V
は型パラメータであり、T
は名前付き型ではなく、V
の型セット内の各型の値はT
に代入可能です。
表現可能性
無型定数 x
は、型 T
の値によって表現可能です。ここで、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 is representable by a value of T because
'a' byte 97 is in the set of byte values
97 rune rune is an alias for int32, and 97 is in the set of 32-bit integers
"foo" string "foo" is in the set of string values
1024 int16 1024 is in the set of 16-bit integers
42.0 byte 42 is in the set of unsigned 8-bit integers
1e10 uint64 10000000000 is in the set of unsigned 64-bit integers
2.718281828459045 float32 2.718281828459045 rounds to 2.7182817 which is in the set of float32 values
-1e-1000 float64 -1e-1000 rounds to IEEE -0.0 which is further simplified to 0.0
0i int 0 is an integer value
(42 + 0i) float32 42.0 (with zero imaginary part) is in the set of float32 values
x T x is not representable by a value of T because
0 bool 0 is not in the set of boolean values
'a' string 'a' is a rune, it is not in the set of string values
1024 byte 1024 is not in the set of unsigned 8-bit integers
-1 uint16 -1 is not in the set of unsigned 16-bit integers
1.1 int 1.1 is not an integer value
42i float32 (0 + 42i) is not in the set of float32 values
1e1000 float64 1e1000 overflows to IEEE +Inf after rounding
メソッドセット
型のメソッドセットは、その型のオペランドで呼び出すことができるメソッドを決定します。すべての型には、(空である可能性のある)メソッドセットが関連付けられています:
- 定義型のメソッドセット
T
は、受信者型T
で宣言されたすべてのメソッドで構成されます。 - 定義型
T
へのポインタのメソッドセット(T
がポインタでもインターフェースでもない場合)は、受信者*T
またはT
で宣言されたすべてのメソッドのセットです。 インターフェース型のメソッドセットは、インターフェースの型セット内の各型のメソッドセットの交差点です(結果のメソッドセットは通常、インターフェース内で宣言されたメソッドのセットです)。
構造体(および構造体へのポインタ)に埋め込まれたフィールドに関しては、構造体型のセクションで説明されている追加のルールが適用されます。他のすべての型は空のメソッドセットを持ちます。
ブロック
ブロックは、対応する波括弧内の宣言と文の空でないシーケンスです。
= "{" "}" .
= { ";" } .
ソースコード内の明示的なブロックに加えて、暗黙のブロックもあります:
- 1. ユニバースブロックは、すべてのGoソーステキストを含みます。
- 2. 各パッケージには、そのパッケージのすべてのGoソーステキストを含むパッケージブロックがあります。
- 3. 各ファイルには、そのファイル内のすべてのGoソーステキストを含むファイルブロックがあります。
- 4. 各“if”、“for”、および“switch”文は、それぞれ独自の暗黙のブロックに含まれると見なされます。
5. 各“switch”または“select”文の各節は、暗黙のブロックとして機能します。
ブロックはネストされ、スコープに影響を与えます。
宣言とスコープ
宣言は、非空白の識別子を定数、型、型パラメータ、変数、関数、ラベル、またはパッケージにバインドします。プログラム内のすべての識別子は宣言されなければなりません。同じブロック内で同じ識別子を二度宣言することはできず、ファイルとパッケージブロックの両方で宣言することはできません。
空白識別子は、宣言内で他の識別子のように使用できますが、バインディングを導入せず、したがって宣言されません。パッケージブロック内では、識別子 init
はinit
関数の宣言にのみ使用でき、空白識別子のように新しいバインディングを導入しません。
= | | .
= | | .
宣言された識別子のスコープは、その識別子が指定された定数、型、変数、関数、ラベル、またはパッケージを示すソーステキストの範囲です。
Goはブロックを使用して字句的にスコープを持ちます:
- 1. 事前宣言された識別子のスコープはユニバースブロックです。
- 2. 定数、型、変数、または関数(ただしメソッドではない)をトップレベル(任意の関数の外)で宣言した場合、そのスコープはパッケージブロックです。
- 3. インポートされたパッケージのパッケージ名のスコープは、インポート宣言を含むファイルのファイルブロックです。
- 4. メソッド受信者、関数パラメータ、または結果変数を示す識別子のスコープは、関数本体です。
- 5. 関数の型パラメータを示す識別子のスコープは、関数名の後から始まり、関数本体の終わりで終了します。
- 6. 型の型パラメータを示す識別子のスコープは、型名の後から始まり、TypeSpecの終わりで終了します。
- 7. 関数内で宣言された定数または変数の識別子のスコープは、ConstSpecまたはVarSpec(短い変数宣言の場合はShortVarDecl)の終わりから始まり、最も内側の含まれるブロックの終わりで終了します。
8. 関数内で宣言された型識別子のスコープは、TypeSpec内の識別子から始まり、最も内側の含まれるブロックの終わりで終了します。
ブロック内で宣言された識別子は、内側のブロックで再宣言できます。内側の宣言の識別子がスコープ内にある間、それは内側の宣言によって宣言されたエンティティを示します。
パッケージ句は宣言ではありません。パッケージ名はどのスコープにも現れません。その目的は、同じパッケージに属するファイルを識別し、インポート宣言のデフォルトのパッケージ名を指定することです。
ラベルスコープ
ラベルはラベル付き文によって宣言され、“break”、“continue”、および“goto”文で使用されます。使用されないラベルを定義することは違法です。他の識別子とは異なり、ラベルはブロックスコープを持たず、ラベルでない識別子と衝突しません。ラベルのスコープは、宣言された関数の本体であり、ネストされた関数の本体は含まれません。
空白識別子
空白識別子は、アンダースコア文字 _
で表されます。これは、通常の(非空白)識別子の代わりに匿名のプレースホルダーとして機能し、宣言、オペランド、および代入文で特別な意味を持ちます。
事前宣言された識別子
次の識別子は、ユニバースブロック内で暗黙的に宣言されます [Go 1.18] [Go 1.21]:
Types:
any bool byte comparable
complex64 complex128 error float32 float64
int int8 int16 int32 int64 rune string
uint uint8 uint16 uint32 uint64 uintptr
Constants:
true false iota
Zero value:
nil
Functions:
append cap clear close complex copy delete imag len
make max min new panic print println real recover
エクスポートされた識別子
識別子は、他のパッケージからのアクセスを許可するためにエクスポートされる場合があります。識別子は、次の両方の条件を満たす場合にエクスポートされます:
識別子の一意性
識別子のセットが与えられた場合、識別子は一意と呼ばれ、セット内の他のすべての識別子と異なる場合です。二つの識別子は、異なるスペルであるか、異なるパッケージに存在し、エクスポートされていない場合に異なります。そうでなければ、同じです。
定数宣言
定数宣言は、識別子のリスト(定数の名前)を定数式の値にバインドします。識別子の数は式の数と等しくなければならず、左側のn番目の識別子は、右側のn番目の式の値にバインドされます。
= "const" ( | "(" { ";" } ")" ) .
= [ [ ] "=" ] .
= { "," } .
= { "," } .
型が指定されている場合、すべての定数は指定された型を取り、式はその型に代入可能でなければなりません。型は型パラメータであってはなりません。型が省略されている場合、定数は対応する式の個々の型を取ります。式の値が無型定数である場合、宣言された定数は無型のままであり、定数識別子は定数値を示します。たとえば、式が浮動小数点リテラルである場合、定数識別子は浮動小数点定数を示します。たとえリテラルの小数部分がゼロであってもです。
const Pi float64 = 3.14159265358979323846
const zero = 0.0 // untyped floating-point constant
const (
size int64 = 1024
eof = -1 // untyped integer constant
)
const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", untyped integer and string constants
const u, v float32 = 0, 3 // u = 0.0, v = 3.0
括弧付きの const
宣言リスト内では、最初のConstSpec以外のすべての式リストを省略できます。このような空のリストは、最初の前の非空の式リストとその型(もしあれば)のテキスト置換に相当します。したがって、式リストを省略することは、前のリストを繰り返すことに相当します。識別子の数は、前のリストの式の数と等しくなければなりません。iota
定数ジェネレーターと組み合わせることで、このメカニズムは連続値の軽量宣言を可能にします:
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Partyday
numberOfDays // this constant is not exported
)
アイオタ
定数宣言内で、事前宣言された識別子 iota
は、連続する無型整数定数を表します。その値は、その定数宣言内のそれぞれのConstSpecのインデックスで、ゼロから始まります。関連する定数のセットを構築するために使用できます:
const (
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const (
a = 1 << iota // a == 1 (iota == 0)
b = 1 << iota // b == 2 (iota == 1)
c = 3 // c == 3 (iota == 2, unused)
d = 1 << iota // d == 8 (iota == 3)
)
const (
u = iota * 42 // u == 0 (untyped integer constant)
v float64 = iota * 42 // v == 42.0 (float64 constant)
w = iota * 42 // w == 84 (untyped integer constant)
)
const x = iota // x == 0
const y = iota // y == 0
定義により、同じConstSpec内でのiota
の複数の使用はすべて同じ値を持ちます:
const (
bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 (iota == 0)
bit1, mask1 // bit1 == 2, mask1 == 1 (iota == 1)
_, _ // (iota == 2, unused)
bit3, mask3 // bit3 == 8, mask3 == 7 (iota == 3)
)
この最後の例は、最後の非空の式リストの暗黙の繰り返しを利用しています。
型宣言
型宣言は、識別子、型名を型にバインドします。型宣言には、エイリアス宣言と型定義の二つの形式があります。
= "type" ( | "(" { ";" } ")" ) .
= | .
エイリアス宣言
エイリアス宣言は、識別子を指定された型にバインドします [Go 1.9]。
= "=" .
識別子のスコープ内では、それは型のエイリアスとして機能します。
type (
nodeList = []*Node // nodeList and []*Node are identical types
Polar = polar // Polar and polar denote identical types
)
型定義
型定義は、指定された型と同じ基礎型および操作を持つ新しい異なる型を作成し、識別子、型名をそれにバインドします。
= [ ] .
新しい型は定義型と呼ばれます。それは、作成元の型を含む他のどの型とも異なるです。
type (
Point struct{ x, y float64 } // Point and struct{ x, y float64 } are different types
polar Point // polar and Point denote different types
)
type TreeNode struct {
left, right *TreeNode
value any
}
type Block interface {
BlockSize() int
Encrypt(src, dst []byte)
Decrypt(src, dst []byte)
}
定義型には、関連付けられたメソッドを持つことができます。指定された型にバインドされたメソッドを継承することはありませんが、インターフェース型または合成型の要素のメソッドセットは変更されません:
// A Mutex is a data type with two methods, Lock and Unlock.
type Mutex struct { /* Mutex fields */ }
func (m *Mutex) Lock() { /* Lock implementation */ }
func (m *Mutex) Unlock() { /* Unlock implementation */ }
// NewMutex has the same composition as Mutex but its method set is empty.
type NewMutex Mutex
// The method set of PtrMutex's underlying type *Mutex remains unchanged,
// but the method set of PtrMutex is empty.
type PtrMutex *Mutex
// The method set of *PrintableMutex contains the methods
// Lock and Unlock bound to its embedded field Mutex.
type PrintableMutex struct {
Mutex
}
// MyBlock is an interface type that has the same method set as Block.
type MyBlock Block
型定義は、異なるブール型、数値型、または文字列型を定義し、それにメソッドを関連付けるために使用できます:
type TimeZone int
const (
EST TimeZone = -(5 + iota)
CST
MST
PST
)
func (tz TimeZone) String() string {
return fmt.Sprintf("GMT%+dh", tz)
}
型定義が型パラメータを指定する場合、型名はジェネリック型を示します。ジェネリック型は、使用されるときにインスタンス化されなければなりません。
type List[T any] struct {
next *List[T]
value T
}
型定義内で、指定された型は型パラメータであってはなりません。
type T[P any] P // illegal: P is a type parameter
func f[T any]() {
type L T // illegal: T is a type parameter declared by the enclosing function
}
ジェネリック型にもメソッドが関連付けられる場合があります。この場合、メソッド受信者は、ジェネリック型定義に存在する型パラメータの数と同じ数の型パラメータを宣言しなければなりません。
// The method Len returns the number of elements in the linked list l.
func (l *List[T]) Len() int { … }
型パラメータ宣言
型パラメータリストは、ジェネリック関数または型宣言の型パラメータを宣言します。型パラメータリストは、通常の関数パラメータリストのように見えますが、型パラメータ名はすべて存在し、リストは括弧ではなく角括弧で囲まれています [Go 1.18]。
= "[" [ "," ] "]" .
= { "," } .
= .
リスト内のすべての非空白名は一意でなければなりません。各名前は型パラメータを宣言し、それは宣言内の(まだ)未知の型のプレースホルダーとして機能する新しい異なる名前付き型です。型パラメータは、ジェネリック関数または型のインスタンス化時に型引数に置き換えられます。
[P any]
[S interface{ ~[]byte|string }]
[S ~[]E, E any]
[P Constraint[int]]
[_ any]
各通常の関数パラメータがパラメータ型を持つように、各型パラメータには対応する(メタ)型があり、それはその型制約と呼ばれます。
型パラメータリストが、型パラメータ P
を制約 C
で宣言する場合、テキスト P C
が有効な式を形成する場合、解析の曖昧さが生じます:
type T[P *C] …
type T[P (C)] …
type T[P *C|Q] …
…
これらの稀なケースでは、型パラメータリストは式と区別できず、型宣言は配列型宣言として解析されます。曖昧さを解決するために、制約をインターフェースに埋め込むか、末尾にカンマを使用します:
type T[P interface{*C}] …
type T[P *C,] …
型パラメータは、ジェネリック型に関連付けられたメソッド宣言の受信者仕様によっても宣言できます。
ジェネリック型 T
の型パラメータリスト内では、型制約はT
を(直接的または間接的に、他のジェネリック型の型パラメータリストを通じて)参照することはできません。
type T1[P T1[P]] … // illegal: T1 refers to itself
type T2[P interface{ T2[int] }] … // illegal: T2 refers to itself
type T3[P interface{ m(T3[int])}] … // illegal: T3 refers to itself
type T4[P T5[P]] … // illegal: T4 refers to T5 and
type T5[P T4[P]] … // T5 refers to T4
type T6[P int] struct{ f *T6[P] } // ok: reference to T6 is not in type parameter list
型制約
型制約は、対応する型パラメータの許可される型引数のセットを定義し、その型パラメータの値がサポートする操作を制御するインターフェースです [Go 1.18]。
= .
制約が interface{E}
の形のインターフェースリテラルであり、E
が埋め込まれた型要素(メソッドではない)である場合、型パラメータリスト内では、囲む interface{ … }
を省略することができます。
[T []P] // = [T interface{[]P}]
[T ~int] // = [T interface{~int}]
[T int|string] // = [T interface{int|string}]
type Constraint ~int // illegal: ~int is not in a type parameter list
事前宣言されたインターフェース型 comparable
は、厳密に比較可能なすべての非インターフェース型のセットを示します [Go 1.18]。
型パラメータでないインターフェースは比較可能ですが、厳密に比較可能ではないため、comparable
を実装しません。しかし、comparable
を満たします。
int // implements comparable (int is strictly comparable)
[]byte // does not implement comparable (slices cannot be compared)
interface{} // does not implement comparable (see above)
interface{ ~int | ~string } // type parameter only: implements comparable (int, string types are strictly comparable)
interface{ comparable } // type parameter only: implements comparable (comparable implements itself)
interface{ ~int | ~[]byte } // type parameter only: does not implement comparable (slices are not comparable)
interface{ ~struct{ any } } // type parameter only: does not implement comparable (field any is not strictly comparable)
comparable
インターフェースおよび comparable
を(直接的または間接的に)埋め込むインターフェースは、型制約としてのみ使用できます。それらは、値や変数の型、または他の非インターフェース型のコンポーネントにはなれません。
型制約を満たす
型引数 T
は、型制約 C
を満たす場合、T
が C
によって定義された型セットの要素である。すなわち、T
が C
を実装する場合です。例外として、厳密に比較可能な型制約は、比較可能(必ずしも厳密に比較可能でない)型引数によっても満たされる場合があります [Go 1.20]。より正確には:
型 T は、制約 C
を満たす場合、
T
がC
を実装する; またはC
はinterface{ comparable; E }
の形で書くことができ、E
は基本インターフェースであり、T
は比較可能であり、E
を実装する。
type argument type constraint // constraint satisfaction
int interface{ ~int } // satisfied: int implements interface{ ~int }
string comparable // satisfied: string implements comparable (string is strictly comparable)
[]byte comparable // not satisfied: slices are not comparable
any interface{ comparable; int } // not satisfied: any does not implement interface{ int }
any comparable // satisfied: any is comparable and implements the basic interface any
struct{f any} comparable // satisfied: struct{f any} is comparable and implements the basic interface any
any interface{ comparable; m() } // not satisfied: any does not implement the basic interface interface{ m() }
interface{ m() } interface{ comparable; m() } // satisfied: interface{ m() } is comparable and implements the basic interface interface{ m() }
制約満足ルールの例外により、型パラメータ型のオペランドを比較すると、実行時にパニックが発生する可能性があります(比較可能な型パラメータは常に厳密に比較可能です)。
変数宣言
変数宣言は、一つ以上の変数を作成し、それに対応する識別子をバインドし、各変数に型と初期値を与えます。
= "var" ( | "(" { ";" } ")" ) .
= ( [ "=" ] | "=" ) .
var i int
var U, V, W float64
var k = 0
var x, y float32 = -1, -2
var (
i int
u, v, s = 2.0, 3.0, "bar"
)
var re, im = complexSqrt(-1)
var _, found = entries[name] // map lookup; only interested in "found"
式のリストが与えられた場合、変数は代入文のルールに従って式で初期化されます。そうでない場合、各変数はそのゼロ値で初期化されます。
型が指定されている場合、各変数にはその型が与えられます。そうでない場合、各変数には代入の対応する初期化値の型が与えられます。その値が無型定数である場合、最初にそのデフォルト型に暗黙的に変換されます。無型ブール値である場合、最初に型 bool
に暗黙的に変換されます。事前宣言された値 nil
は、明示的な型のない変数を初期化するために使用できません。
var d = math.Sin(0.5) // d is float64
var i = 42 // i is int
var t, ok = x.(T) // t is T, ok is bool
var n = nil // illegal
実装制限: コンパイラは、変数が決して使用されない場合、関数本体内で変数を宣言することを違法にすることがあります。
短い変数宣言
短い変数宣言は、次の構文を使用します:
= ":=" .
これは、初期化子式を持つ通常の変数宣言の省略形ですが、型はありません:
"var" IdentifierList "=" ExpressionList .
i, j := 0, 10
f := func() int { return 7 }
ch := make(chan int)
r, w, _ := os.Pipe() // os.Pipe() returns a connected pair of Files and an error, if any
_, y, _ := coord(p) // coord() returns three values; only interested in y coordinate
通常の変数宣言とは異なり、短い変数宣言は、元々同じブロック内で同じ型で宣言された場合に限り、変数を再宣言することができます。少なくとも一つの非空白変数が新しいものである必要があります。その結果、再宣言は多変数の短い宣言にのみ現れることができます。再宣言は新しい変数を導入するのではなく、元の変数に新しい値を割り当てるだけです。:=
の左側の非空白変数名は一意でなければなりません。
field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset) // redeclares offset
x, y, x := 1, 2, 3 // illegal: x repeated on left side of :=
短い変数宣言は、関数内でのみ現れることができます。“if”、“for”、または“switch”文の初期化子などのいくつかの文脈では、ローカル一時変数を宣言するために使用できます。
関数宣言
関数宣言は、識別子、関数名を関数にバインドします。
= "func" [ ] [ ] .
= .
= .
関数のシグネチャが結果パラメータを宣言している場合、関数本体の文リストは終了文で終わらなければなりません。
func IndexRune(s string, r rune) int {
for i, c := range s {
if c == r {
return i
}
}
// invalid: missing return statement
}
関数宣言が型パラメータを指定する場合、関数名はジェネリック関数を示します。ジェネリック関数は、呼び出す前にインスタンス化されなければなりません。
func min[T ~int|~float64](x, y T) T {
if x < y {
return x
}
return y
}
型パラメータのない関数宣言は、本文を省略できます。このような宣言は、Goの外部で実装された関数のシグネチャを提供します。たとえば、アセンブリルーチンなどです。
func flushICache(begin, end uintptr) // implemented externally
メソッド宣言
メソッドはレシーバーを持つ関数です。メソッド宣言は識別子、メソッド名をメソッドにバインドし、メソッドをレシーバーのベースタイプに関連付けます。
= "func" [ ] .
= .
レシーバーはメソッド名の前にある追加のパラメーターセクションで指定されます。そのパラメーターセクションは、レシーバーである単一の非可変パラメーターを宣言しなければなりません。その型は定義された型T
または定義された型へのポインタT
でなければならず、可能であれば角括弧で囲まれた型パラメーター名のリスト[P1, P2, …]
が続くことがあります。T
はレシーバーのベースタイプと呼ばれます。レシーバーベースタイプはポインタまたはインターフェース型であってはならず、メソッドと同じパッケージで定義されている必要があります。メソッドはそのレシーバーベースタイプにバインドされていると言われ、メソッド名は型T
または*T
のセレクタ内でのみ可視です。
非空白レシーバー識別子は、メソッドシグネチャ内で一意でなければなりません。レシーバーの値がメソッドの本体内で参照されない場合、その識別子は宣言から省略できます。これは一般的に関数とメソッドのパラメーターにも当てはまります。
ベースタイプに対して、バインドされたメソッドの非空白名は一意でなければなりません。ベースタイプが構造体型である場合、非空白のメソッド名とフィールド名は異なる必要があります。
定義された型Point
に対して、宣言
func (p *Point) Length() float64 {
return math.Sqrt(p.x * p.x + p.y * p.y)
}
func (p *Point) Scale(factor float64) {
p.x *= factor
p.y *= factor
}
はメソッドLength
とScale
を、レシーバー型*Point
でベースタイプPoint
にバインドします。
レシーバーベースタイプがジェネリック型である場合、レシーバー仕様はメソッドが使用する対応する型パラメーターを宣言しなければなりません。これにより、レシーバー型パラメーターがメソッドで利用可能になります。文法的には、この型パラメーター宣言はレシーバーベースタイプのインスタンス化のように見えます:型引数は宣言される型パラメーターを示す識別子でなければならず、レシーバーベースタイプの各型パラメーターに対して1つ必要です。型パラメーター名はレシーバーベースタイプ定義内の対応するパラメーター名と一致する必要はなく、すべての非空白パラメーター名はレシーバーパラメーターセクションとメソッドシグネチャ内で一意でなければなりません。レシーバー型パラメーターの制約はレシーバーベースタイプ定義によって暗示されます:対応する型パラメーターには対応する制約があります。
type Pair[A, B any] struct {
a A
b B
}
func (p Pair[A, B]) Swap() Pair[B, A] { … } // receiver declares A, B
func (p Pair[First, _]) First() First { … } // receiver declares First, corresponds to A in Pair
式
式は、オペランドに演算子と関数を適用することによって値の計算を指定します。
オペランド
オペランドは式の基本的な値を示します。オペランドはリテラル、(おそらく修飾された)非空白識別子で、定数、変数、または関数を示すか、括弧で囲まれた式である可能性があります。
= | [ ] | "(" ")" .
= | | .
= | | | | .
= | .
オペランド名はジェネリック関数を示す場合、型引数のリストが続くことがあります;その結果、オペランドはインスタンス化された関数です。
空白識別子は代入文の左側にのみオペランドとして現れることができます。
実装制限:オペランドの型が型パラメーターで空のtype setを持つ場合、コンパイラはエラーを報告する必要はありません。そのような型パラメーターを持つ関数はインスタンス化できず、試みるとインスタンス化サイトでエラーが発生します。
修飾された識別子
修飾された識別子は、パッケージ名のプレフィックスで修飾された識別子です。パッケージ名と識別子の両方は空白であってはなりません。
= "." .
修飾された識別子は、異なるパッケージ内の識別子にアクセスします。そのパッケージはインポートされている必要があります。識別子はエクスポートされたもので、そのパッケージのパッケージブロック内で宣言されている必要があります。
math.Sin // denotes the Sin function in package math
複合リテラル
複合リテラルは評価されるたびに新しい複合値を構築します。リテラルの型の後に波括弧で囲まれた要素のリストが続きます。各要素は、対応するキーの前にオプションで置かれることがあります。
= .
= | | "[" "..." "]" |
| | [ ] .
= "{" [ [ "," ] ] "}" .
= { "," } .
= [ ":" ] .
= | | .
= .
= | .
リテラル型のコア型T
は、構造体、配列、スライス、またはマップ型でなければなりません(構文は、型がTypeNameとして与えられる場合を除いて、この制約を強制します)。要素とキーの型は、型T
のそれぞれのフィールド、要素、およびキーの型に代入可能でなければなりません;追加の変換はありません。キーは、構造体リテラルの場合はフィールド名、配列およびスライスリテラルの場合はインデックス、マップリテラルの場合はキーとして解釈されます。マップリテラルの場合、すべての要素にはキーが必要です。同じフィールド名または定数キー値を持つ複数の要素を指定することはエラーです。非定数マップキーについては、評価順序のセクションを参照してください。
構造体リテラルに対しては、次のルールが適用されます:
- キーは構造体型で宣言されたフィールド名でなければなりません。
- キーを含まない要素リストは、フィールドが宣言された順序で各構造体フィールドの要素をリストする必要があります。
- いずれかの要素にキーがある場合、すべての要素にキーが必要です。
- キーを含む要素リストは、各構造体フィールドの要素を持つ必要はありません。省略されたフィールドはそのフィールドのゼロ値を取得します。
- リテラルは要素リストを省略することができます;そのようなリテラルはその型のゼロ値に評価されます。
異なるパッケージに属する構造体の非エクスポートフィールドに要素を指定することはエラーです。
宣言が与えられた場合
type Point3D struct { x, y, z float64 }
type Line struct { p, q Point3D }
次のように書くことができます:
origin := Point3D{} // zero value for Point3D
line := Line{origin, Point3D{y: -4, z: 12.3}} // zero value for line.q.x
配列およびスライスリテラルに対しては、次のルールが適用されます:
- 各要素には、配列内の位置を示す整数インデックスが関連付けられています。
- キーを持つ要素は、そのキーをインデックスとして使用します。キーは、型
int
の値によって表現可能な非負の定数でなければならず、型が指定されている場合は整数型でなければなりません。 キーを持たない要素は、前の要素のインデックスに1を加えたものを使用します。最初の要素にキーがない場合、そのインデックスはゼロです。
複合リテラルのアドレスを取得することは、リテラルの値で初期化された一意の変数へのポインタを生成します。
var pointer *Point3D = &Point3D{y: 1000}
スライスまたはマップ型のゼロ値は、同じ型の初期化されたが空の値とは異なることに注意してください。したがって、空のスライスまたはマップ複合リテラルのアドレスを取得することは、newで新しいスライスまたはマップ値を割り当てることと同じ効果を持ちません。
p1 := &[]int{} // p1 points to an initialized, empty slice with value []int{} and length 0
p2 := new([]int) // p2 points to an uninitialized slice with value nil and length 0
配列リテラルの長さは、リテラル型で指定された長さです。リテラルに提供される要素が長さよりも少ない場合、欠落した要素は配列要素型のゼロ値に設定されます。インデックス値が配列のインデックス範囲外の要素を提供することはエラーです。表記...
は、最大要素インデックスに1を加えた配列の長さを指定します。
buffer := [10]string{} // len(buffer) == 10
intSet := [6]int{1, 2, 3, 5} // len(intSet) == 6
days := [...]string{"Sat", "Sun"} // len(days) == 2
スライスリテラルは、基礎となる配列リテラル全体を記述します。したがって、スライスリテラルの長さと容量は、最大要素インデックスに1を加えたものです。スライスリテラルは次の形式を持ちます:
[]T{x1, x2, … xn}
これは、配列に適用されるスライス操作の省略形です:
tmp := [n]T{x1, x2, … xn}
tmp[0 : n]
配列、スライス、またはマップ型T
の複合リテラル内では、要素またはマップキーがそれ自体が複合リテラルである場合、T
の要素またはキー型と同じである場合は、対応するリテラル型を省略できます。同様に、複合リテラルのアドレスである要素またはキーは、要素またはキー型が*T
である場合、&T
を省略できます。
[...]Point{{1.5, -3.5}, {0, 0}} // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}}
[][]int{{1, 2, 3}, {4, 5}} // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
[][]Point{{{0, 1}, {1, 2}}} // same as [][]Point{[]Point{Point{0, 1}, Point{1, 2}}}
map[string]Point{"orig": {0, 0}} // same as map[string]Point{"orig": Point{0, 0}}
map[Point]string{{0, 0}: "orig"} // same as map[Point]string{Point{0, 0}: "orig"}
type PPoint *Point
[2]*Point{{1.5, -3.5}, {}} // same as [2]*Point{&Point{1.5, -3.5}, &Point{}}
[2]PPoint{{1.5, -3.5}, {}} // same as [2]PPoint{PPoint(&Point{1.5, -3.5}), PPoint(&Point{})}
複合リテラルがキーワード[#Keywords]とブロックの開き波括弧の間にオペランドとして現れる場合、解析の曖昧さが生じます。この場合、複合リテラルは括弧、角括弧、または波括弧で囲まれていない場合、リテラルの開き波括弧は文のブロックを導入するものとして誤って解析されます。曖昧さを解消するために、複合リテラルは括弧内に現れる必要があります。
if x == (T{a,b,c}[i]) { … }
if (x == T{a,b,c}[i]) { … }
有効な配列、スライス、およびマップリテラルの例:
// list of prime numbers
primes := []int{2, 3, 5, 7, 9, 2147483647}
// vowels[ch] is true if ch is a vowel
vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true}
// the array [10]float32{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1}
filter := [10]float32{-1, 4: -0.1, -0.1, 9: -1}
// frequencies in Hz for equal-tempered scale (A4 = 440Hz)
noteFrequency := map[string]float32{
"C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83,
"G0": 24.50, "A0": 27.50, "B0": 30.87,
}
関数リテラル
関数リテラルは匿名の関数を表します。関数リテラルは型パラメーターを宣言することはできません。
= "func" .
func(a, b int, z float64) bool { return a*b < int(z) }
関数リテラルは変数に割り当てることができるか、直接呼び出すことができます。
f := func(x, y int) int { return x + y }
func(ch chan int) { ch <- ACK }(replyChan)
関数リテラルはクロージャです:それらは周囲の関数で定義された変数を参照することができます。それらの変数は、周囲の関数と関数リテラルの間で共有され、アクセス可能な限り生存します。
主な式
主な式は、単項および二項式のオペランドです。
=
|
|
|
|
|
|
|
.
= "." .
= "[" [ "," ] "]" .
= "[" [ ] ":" [ ] "]" |
"[" [ ] ":" ":" "]" .
= "." "(" ")" .
= "(" [ ( | [ "," ] ) [ "..." ] [ "," ] ] ")" .
x
2
(s + ".txt")
f(3.1415, true)
Point{1, 2}
m["foo"]
s[i : j + 1]
obj.color
f.p[i].x()
セレクタ
x.f
は値x
のフィールドまたはメソッドf
を示します(または時には*x
;以下を参照)。識別子f
は(フィールドまたはメソッドの)セレクタと呼ばれ、空白識別子であってはなりません。セレクター式の型はf
の型です。x
がパッケージ名である場合は、修飾された識別子のセクションを参照してください。
セレクタf
は、型T
のフィールドまたはメソッドf
を示すか、またはT
のネストされた埋め込みフィールドのフィールドまたはメソッドf
を参照することがあります。f
に到達するためにトラバースされる埋め込みフィールドの数は、T
におけるその深さと呼ばれます。f
がT
で宣言されたフィールドまたはメソッドの深さはゼロです。f
がA
の埋め込みフィールドで宣言されたフィールドまたはメソッドの深さは、f
のA
における深さに1を加えたものです。
セレクタに適用されるルールは次のとおりです:
- 1. 型
T
または*T
の値x
に対して、T
がポインタまたはインターフェース型でない場合、x.f
はT
内で最も浅い深さにあるそのようなf
を示します。最も浅い深さにある一つのf
が正確に存在しない場合、セレクター式は不正です。 - 2. 型
I
の値x
に対して、I
がインターフェース型である場合、x.f
はx
の動的値の実際のメソッドf
を示します。f
という名前のメソッドがI
のメソッドセットに存在しない場合、セレクター式は不正です。 - 3. 例外として、
x
の型が定義されたポインタ型であり、(*x).f
がフィールド(ただしメソッドではない)を示す有効なセレクター式である場合、x.f
は(*x).f
の省略形です。 - 4. その他のすべての場合、
x.f
は不正です。 - 5.
x
がポインタ型でnil
の値を持ち、x.f
が構造体フィールドを示す場合、x.f
に代入または評価するとランタイムパニックが発生します。 6.
x
がインターフェース型でnil
の値を持つ場合、メソッドx.f
を呼び出すまたは評価することはランタイムパニックを引き起こします。例えば、次の宣言が与えられた場合:
type T0 struct {
x int
}
func (*T0) M0()
type T1 struct {
y int
}
func (T1) M1()
type T2 struct {
z int
T1
*T0
}
func (*T2) M2()
type Q *T2
var t T2 // with t.T0 != nil
var p *T2 // with p != nil and (*p).T0 != nil
var q Q = p
次のように書くことができます:
t.z // t.z
t.y // t.T1.y
t.x // (*t.T0).x
p.z // (*p).z
p.y // (*p).T1.y
p.x // (*(*p).T0).x
q.x // (*(*q).T0).x (*q).x is a valid field selector
p.M0() // ((*p).T0).M0() M0 expects *T0 receiver
p.M1() // ((*p).T1).M1() M1 expects T1 receiver
p.M2() // p.M2() M2 expects *T2 receiver
t.M2() // (&t).M2() M2 expects *T2 receiver, see section on Calls
しかし、次のように書くことは無効です:
q.M0() // (*q).M0 is valid but not a field selector
メソッド式
もしM
が型T
のメソッドセットにあり、T.M
はメソッドのレシーバーである追加の引数を前置した同じ引数で通常の関数として呼び出すことができる関数です。
= "." .
= .
構造体型T
を考え、2つのメソッドMv
(そのレシーバーは型T
)とMp
(そのレシーバーは型*T
)を持ちます。
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
var t T
式
T.Mv
はMv
に相当する関数を生成しますが、最初の引数として明示的なレシーバーを持ちます;そのシグネチャは
func(tv T, a int) int
その関数は通常の方法で明示的なレシーバーを持って呼び出すことができるため、これらの5つの呼び出しは等価です:
t.Mv(7)
T.Mv(t, 7)
(T).Mv(t, 7)
f1 := T.Mv; f1(t, 7)
f2 := (T).Mv; f2(t, 7)
同様に、式
(*T).Mp
はMp
を表す関数値を生成し、そのシグネチャは
func(tp *T, f float32) float32
値レシーバーを持つメソッドの場合、明示的なポインタレシーバーを持つ関数を導出することができるため、
(*T).Mv
はMv
を表す関数値を生成し、そのシグネチャは
func(tv *T, a int) int
このような関数はレシーバーを通じて間接的に呼び出され、基礎となるメソッドに渡すための値を作成します;メソッドは関数呼び出しで渡されたアドレスの値を上書きしません。
最後のケース、ポインタレシーバーメソッドの値レシーバー関数は不正です。なぜなら、ポインタレシーバーメソッドは値型のメソッドセットに含まれないからです。
メソッドから導出された関数値は関数呼び出し構文で呼び出されます;レシーバーは呼び出しの最初の引数として提供されます。すなわち、f := T.Mv
が与えられた場合、f
はf(t, 7)
として呼び出され、t.f(7)
としては呼び出されません。レシーバーをバインドする関数を構築するには、関数リテラルまたはメソッド値を使用します。
インターフェース型のメソッドから関数値を導出することは合法です。結果の関数は、そのインターフェース型の明示的なレシーバーを取ります。
メソッド値
もし式x
が静的型T
を持ち、M
が型T
のメソッドセットにある場合、x.M
はメソッド値と呼ばれます。メソッド値x.M
は、x.M
のメソッド呼び出しと同じ引数で呼び出すことができる関数値です。式 x
はメソッド値の評価中に評価され保存され、保存されたコピーはその後の呼び出しでレシーバーとして使用されます。
type S struct { *T }
type T int
func (t T) M() { print(t) }
t := new(T)
s := S{T: t}
f := t.M // receiver *t is evaluated and stored in f
g := s.M // receiver *(s.T) is evaluated and stored in g
*t = 42 // does not affect stored receivers in f and g
型T
はインターフェース型または非インターフェース型である可能性があります。
上記のメソッド式の議論と同様に、構造体型T
を考え、2つのメソッドMv
(そのレシーバーは型T
)とMp
(そのレシーバーは型*T
)を持ちます。
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
var t T
var pt *T
func makeT() T
式
t.Mv
は型
func(int) int
``````の関数値を生成します。
これらの2つの呼び出しは等価です:
``````bash
t.Mv(7)
f := t.Mv; f(7)
同様に、式
pt.Mp
は型
func(float32) float32
``````の関数値を生成します。
[セレクタ](#Selectors)と同様に、値レシーバーを持つ非インターフェースメソッドへの参照は、ポインタを使用して自動的に逆参照されます:`````pt.Mv`````は`````(*pt).Mv`````に等価です。
[メソッド呼び出し](#Calls)と同様に、アドレス可能な値を使用してポインタレシーバーを持つ非インターフェースメソッドへの参照は、その値のアドレスを自動的に取得します:`````t.Mp`````は`````(&t).Mp`````に等価です。
``````bash
f := t.Mv; f(7) // like t.Mv(7)
f := pt.Mp; f(7) // like pt.Mp(7)
f := pt.Mv; f(7) // like (*pt).Mv(7)
f := t.Mp; f(7) // like (&t).Mp(7)
f := makeT().Mp // invalid: result of makeT() is not addressable
上記の例は非インターフェース型を使用していますが、インターフェース型の値からメソッド値を作成することも合法です。
var i interface { M(int) } = myVal
f := i.M; f(7) // like i.M(7)
インデックス式
次の形式の主な式
a[x]
は、x
でインデックス付けされた配列、配列へのポインタ、スライス、文字列、またはマップa
の要素を示します。値x
はそれぞれインデックスまたはマップキーと呼ばれます。次のルールが適用されます:
- インデックス`````x`````は無型定数でなければならず、その[コア型](#Core_types)は[整数](#Numeric_types)でなければなりません。
- 定数インデックスは非負であり、型`````int`````の値によって[表現可能](#Representability)でなければなりません。
- 無型の定数インデックスは型`````int`````を持ちます。
- インデックス`````x`````は範囲内である場合`````0 <= x < len(a)`````、そうでなければ範囲外です。
配列型[`````A`````]の`````a`````の場合:
- [定数](#Constants)インデックスは範囲内でなければなりません。
- 実行時に`````x`````が範囲外の場合、[ランタイムパニック](#Run_time_panics)が発生します。
- `````a[x]`````はインデックス`````x`````の配列要素であり、`````a[x]`````の型は`````A`````の要素型です。
配列型へのポインタ[`````a`````]の場合:
- `````a[x]`````は`````(*a)[x]`````の省略形です。
スライス型[`````S`````]の`````a`````の場合:
- 実行時に`````x`````が範囲外の場合、[ランタイムパニック](#Run_time_panics)が発生します。
- `````a[x]`````はインデックス`````x`````のスライス要素であり、`````a[x]`````の型は`````S`````の要素型です。
文字列型[`````a`````]の`````a`````の場合:
- 文字列`````a`````が定数である場合、定数インデックスは範囲内でなければなりません。
- 実行時に`````x`````が範囲外の場合、[ランタイムパニック](#Run_time_panics)が発生します。
- `````a[x]`````はインデックス`````x`````の非定数バイト値であり、`````a[x]`````の型は`````byte`````です。
- `````a[x]`````には代入できません。
マップ型[`````M`````]の`````a`````の場合:
- `````x`````の型は`````M`````のキー型に[代入可能](#Assignability)でなければなりません。
- マップにキー`````x`````を持つエントリがある場合、`````a[x]`````はキー`````x`````のマップ要素であり、`````a[x]`````の型は`````M`````の要素型です。
- マップが`````nil`````であるか、そのようなエントリを含まない場合、`````a[x]`````は`````M`````の要素型の[ゼロ値](#The_zero_value)です。
型パラメーター型[`````P`````]の`````a`````の場合:
- インデックス式`````a[x]`````は`````P`````の型セットのすべての型の値に対して有効でなければなりません。
- `````P`````の型セットのすべての型の要素型は同一でなければなりません。この文脈では、文字列型の要素型は`````byte`````です。
- `````P`````の型セットにマップ型がある場合、その型セット内のすべての型はマップ型であり、それぞれのキー型はすべて同一でなければなりません。
- `````a[x]`````は、インデックス`````x`````の配列、スライス、または文字列要素、または`````P`````でインスタンス化された型引数のキー`````x`````のマップ要素であり、`````a[x]`````の型は(同一の)要素型の型です。
- `````a[x]`````は、`````P`````の型セットに文字列型が含まれている場合、代入できません。
それ以外の場合、`````a[x]`````は不正です。
マップ`````a`````のインデックス式は、`````map[K]V`````の型で[代入文](#Assignment_statements)または特別な形式の初期化に使用されると、追加の無型ブール値を生成します。`````ok`````の値は、キー`````x`````がマップに存在する場合`````true`````であり、そうでない場合`````false`````です。
`````nil`````マップの要素に代入すると、[ランタイムパニック](#Run_time_panics)が発生します。
<a name="Slice_expressions"></a>
### スライス式
スライス式は、文字列、配列、配列へのポインタ、またはスライスからサブストリングまたはスライスを構築します。単純な境界を指定する形式と、容量の境界も指定する完全な形式の2つのバリエーションがあります。
#### 単純スライス式
主な式
``````bash
a[low : high]
`
はサブストリングまたはスライスを構築します。a
のコア型は、文字列、配列、配列へのポインタ、スライス、またはbytestring
でなければなりません。インデックスlow
とhigh
は、オペランドa
のどの要素が結果に現れるかを選択します。結果はインデックスが0から始まり、長さはhigh
-low
に等しくなります。配列a
をスライスした後、
a := [5]int{1, 2, 3, 4, 5}
s := a[1:4]
スライスs
は型[]int
、長さ3、容量4、要素
s[0] == 2
s[1] == 3
s[2] == 4
便利なことに、インデックスのいずれかを省略できます。省略されたlow
インデックスはゼロにデフォルトされ、欠落したhigh
インデックスはスライスされたオペランドの長さにデフォルトされます:
a[2:] // same as a[2 : len(a)]
a[:3] // same as a[0 : 3]
a[:] // same as a[0 : len(a)]
a
が配列へのポインタである場合、a[low : high]
は(*a)[low : high]
の省略形です。
配列または文字列の場合、インデックスは0
<= low
<= high
<= len(a)
の場合に範囲内です。そうでない場合は範囲外です。スライスの場合、上限インデックスはスライスの容量cap(a)
であり、長さではありません。定数インデックスは非負であり、型int
の値によって表現可能でなければなりません。配列または定数文字列の場合、定数インデックスも範囲内でなければなりません。両方のインデックスが定数である場合、low <= high
を満たさなければなりません。インデックスが実行時に範囲外である場合、ランタイムパニックが発生します。
無型文字列を除いて、スライスされたオペランドが文字列またはスライスである場合、スライス操作の結果はオペランドと同じ型の非定数値です。無型文字列オペランドの場合、結果は型string
の非定数値です。スライスされたオペランドが配列である場合、アドレス可能でなければならず、スライス操作の結果は配列と同じ要素型のスライスです。
有効なスライス式のスライスされたオペランドがnil
スライスである場合、結果はnil
スライスです。そうでない場合、結果がスライスである場合、オペランドと基礎となる配列を共有します。
var a [10]int
s1 := a[3:7] // underlying array of s1 is array a; &s1[2] == &a[5]
s2 := s1[1:4] // underlying array of s2 is underlying array of s1 which is array a; &s2[1] == &a[5]
s2[1] = 42 // s2[1] == s1[2] == a[5] == 42; they all refer to the same underlying array element
var s []int
s3 := s[:0] // s3 == nil
完全スライス式
主な式
a[low : high : max]
は、単純スライス式a[low : high]
と同じ型、長さ、要素を持つスライスを構築します。さらに、max - low
に設定することによって、結果のスライスの容量を制御します。最初のインデックスのみを省略できます;それは0にデフォルトされます。a
のコア型は、配列、配列へのポインタ、またはスライス(ただし文字列ではない)でなければなりません。配列a
をスライスした後、
a := [5]int{1, 2, 3, 4, 5}
t := a[1:3:5]
スライスt
は型[]int
、長さ2、容量4、要素
t[0] == 2
t[1] == 3
単純スライス式と同様に、a
が配列へのポインタである場合、a[low : high : max]
は(*a)[low : high : max]
の省略形です。スライスされたオペランドが配列である場合、アドレス可能でなければなりません。
インデックスは0 <= low <= high <= max <= cap(a)
の場合に範囲内であり、そうでない場合は範囲外です。定数インデックスは非負であり、型int
の値によって表現可能でなければなりません;配列の場合、定数インデックスも範囲内でなければなりません。複数のインデックスが定数である場合、存在する定数は互いに対して範囲内でなければなりません。インデックスが実行時に範囲外である場合、ランタイムパニックが発生します。
型アサーション
式 x
が インターフェース型 であり、型パラメータ ではない場合、型 T
に対して、主な式
x.(T)
は x
が nil
ではないことを主張し、x
に格納されている値が型 T
であることを主張します。記法 x.(T)
は 型アサーション と呼ばれます。
より正確には、T
がインターフェース型でない場合、x.(T)
は x
の動的型が 同一 であることを主張します。この場合、T
は x
の (インターフェース) 型を 実装 しなければなりません。そうでなければ、x
が型 T
の値を格納することは不可能なので、型アサーションは無効です。T
がインターフェース型である場合、x.(T)
は x
の動的型がインターフェース T
を 実装 していることを主張します。
型アサーションが成立する場合、式の値は x
に格納されている値であり、その型は T
です。型アサーションが偽である場合、ランタイムパニック が発生します。言い換えれば、x
の動的型は実行時にのみ知られていますが、正しいプログラムでは x.(T)
の型は T
であることが知られています。
var x interface{} = 7 // x has dynamic type int and value 7
i := x.(int) // i has type int and value 7
type I interface { m() }
func f(y I) {
s := y.(string) // illegal: string does not implement I (missing method m)
r := y.(io.Reader) // r has type io.Reader and the dynamic type of y must implement both I and io.Reader
…
}
代入文 または特別な形式の初期化で使用される型アサーション
v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
var v, ok interface{} = x.(T) // dynamic types of v and ok are T and bool
は、追加の型なしのブール値を生成します。アサーションが成立する場合、ok
の値は true
です。そうでない場合は false
であり、v
の値は型 T
の ゼロ値 です。この場合、ランタイムパニック は発生しません。
呼び出し
f(a1, a2, … an)
は引数 a1, a2, … an
を持つ f
を呼び出します。特別なケースを除いて、引数は F
のパラメータ型に 代入可能 な単一値の式でなければならず、関数が呼び出される前に評価されます。式の型は F
の結果型です。メソッド呼び出しは似ていますが、メソッド自体はメソッドの受信者型の値に対するセレクタとして指定されます。
math.Atan2(x, y) // function call
var pt *Point
pt.Scale(3.5) // method call with receiver pt
f
がジェネリック関数を示す場合、呼び出す前に インスタンス化 されなければなりません。
関数呼び出しでは、関数値と引数は 通常の順序 で評価されます。評価された後、呼び出しのパラメータは値として関数に渡され、呼び出された関数が実行を開始します。関数が返す戻りパラメータは、関数が返されたときに呼び出し元に値として渡されます。
nil
関数値を呼び出すと、ランタイムパニック が発生します。
特別なケースとして、関数またはメソッド g
の戻り値が別の関数またはメソッド f
のパラメータの数と個別に代入可能である場合、呼び出し f(g(parameters_of_g))
は f
を呼び出し、g
の戻り値を f
のパラメータに順番にバインドします。f
の呼び出しには g
の呼び出し以外のパラメータを含めてはならず、g
には少なくとも1つの戻り値が必要です。f
に最終 ...
パラメータがある場合、通常のパラメータの割り当て後に残った g
の戻り値が割り当てられます。
func Split(s string, pos int) (string, string) {
return s[0:pos], s[pos:]
}
func Join(s, t string) string {
return s + t
}
if Join(Split(value, len(value)/2)) != value {
log.Panic("test fails")
}
メソッド呼び出し x.m()
は、x
の (型の) メソッドセット に m
が含まれ、引数リストが m
のパラメータリストに代入可能である場合に有効です。x
が アドレス可能 であり、&x
のメソッドセットに m
が含まれている場合、x.m()
は (&x).m()
の短縮形です:
var p Point
p.Scale(3.5)
明示的なメソッド型は存在せず、メソッドリテラルもありません。
引数を…パラメータに渡す
もし f
が 可変長 で、最終パラメータ p
の型が ...T
である場合、f
内では p
の型は []T
と同等です。もし f
が p
に対して実際の引数なしで呼び出されると、p
に渡される値は nil
です。そうでない場合、渡される値は新しいスライス []T
の新しい基底配列を持ち、その連続する要素は実際の引数であり、すべてが T
に 代入可能 でなければなりません。したがって、スライスの長さと容量は p
にバインドされた引数の数であり、各呼び出しサイトで異なる場合があります。
関数と呼び出し
func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
が Greeting
内にある場合、who
は最初の呼び出しで nil
の値を持ち、2回目の呼び出しで []string{"Joe", "Anna", "Eileen"}
の値を持ちます。
最終引数がスライスタイプ []T
に代入可能で ...
に続く場合、それは ...T
パラメータの値として変更されずに渡されます。この場合、新しいスライスは作成されません。
スライス s
と呼び出し
s := []string{"James", "Jasmine"}
Greeting("goodbye:", s...)
が Greeting
内にある場合、who
は s
と同じ値を持ち、同じ基底配列を持ちます。
インスタンス化
ジェネリック関数または型は、型引数を型パラメータに置き換えることによって インスタンス化 されます [Go 1.18]。インスタンス化は2つのステップで進行します:
- 1. 各型引数は、ジェネリック宣言内の対応する型パラメータに置き換えられます。この置き換えは、型パラメータリスト自体やそのリスト内の任意の型を含む、関数または型宣言全体にわたって行われます。
2. 置き換え後、各型引数は対応する型パラメータの 制約 (必要に応じてインスタンス化) を 満たさなければなりません。そうでなければ、インスタンス化は失敗します。
型をインスタンス化すると、新しい非ジェネリック 名前付き型 が生成され、関数をインスタンス化すると新しい非ジェネリック関数が生成されます。
type parameter list type arguments after substitution
[P any] int int satisfies any
[S ~[]E, E any] []int, int []int satisfies ~[]int, int satisfies any
[P io.Writer] string illegal: string doesn't satisfy io.Writer
[P comparable] any any satisfies (but does not implement) comparable
ジェネリック関数を使用する場合、型引数は明示的に提供されるか、関数が使用されるコンテキストから部分的または完全に 推論 される場合があります。推論できる場合、型引数リストは次のような場合に完全に省略できます:
- 呼び出し が通常の引数で行われる場合、
- 変数に代入 される場合、型が既知の
- 別の関数への引数として渡される 場合、または
結果として返される 場合。
他のすべてのケースでは、(部分的な) 型引数リストが存在する必要があります。型引数リストが欠落しているか部分的な場合、すべての欠落した型引数は関数が使用されるコンテキストから推論可能でなければなりません。
// sum returns the sum (concatenation, for strings) of its arguments.
func sum[T ~int | ~float64 | ~string](x... T) T { … }
x := sum // illegal: the type of x is unknown
intSum := sum[int] // intSum has type func(x... int) int
a := intSum(2, 3) // a has value 5 of type int
b := sum[float64](2.0, 3) // b has value 5.0 of type float64
c := sum(b, -1) // c has value 4.0 of type float64
type sumFunc func(x... string) string
var f sumFunc = sum // same as var f sumFunc = sum[string]
f = sum // same as f = sum[string]
部分的な型引数リストは空であってはならず、少なくとも最初の引数は存在しなければなりません。このリストは、型引数の完全なリストの接頭辞であり、残りの引数は推論されることになります。大まかに言えば、型引数は「右から左」に省略されることがあります。
func apply[S ~[]E, E any](s S, f func(E) E) S { … }
f0 := apply[] // illegal: type argument list cannot be empty
f1 := apply[[]int] // type argument for S explicitly provided, type argument for E inferred
f2 := apply[[]string, string] // both type arguments explicitly provided
var bytes []byte
r := apply(bytes, func(byte) byte { … }) // both type arguments inferred from the function arguments
ジェネリック型の場合、すべての型引数は常に明示的に提供されなければなりません。
型推論
ジェネリック関数の使用は、関数が使用されるコンテキストから型引数の一部またはすべてを 推論 することができる場合に省略できます。型推論は、欠落している型引数を推論でき、インスタンス化 が推論された型引数で成功する場合に成功します。そうでない場合、型推論は失敗し、プログラムは無効になります。
型推論は、型のペア間の型関係を使用して推論を行います: たとえば、関数引数はそれぞれの関数パラメータに 代入可能 でなければならず、これにより引数の型とパラメータの型の間に関係が確立されます。これらの2つの型のいずれかが型パラメータを含む場合、型推論は代入可能性の関係が満たされるように型パラメータを置き換える型引数を探します。同様に、型推論は型引数がそれぞれの型パラメータの制約を 満たさなければならない という事実を利用します。
各マッチした型のペアは、1つまたは複数の型パラメータを含む 型方程式 に対応します。欠落している型引数を推論することは、対応する型パラメータの型方程式のセットを解くことを意味します。
たとえば、
// dedup returns a copy of the argument slice with any duplicate entries removed.
func dedup[S ~[]E, E comparable](S) S { … }
type Slice []int
var s Slice
s = dedup(s) // same as s = dedup[Slice, int](s)
変数 s
の型 Slice
は、プログラムが有効であるためには関数パラメータ型 S
に代入可能でなければなりません。複雑さを減らすために、型推論は代入の方向性を無視するため、Slice
と S
の間の型関係は (対称的な) 型方程式 Slice ≡A S
(またはその場合 S ≡A Slice
) を介して表現できます。ここで、A
は ≡A
において、LHS と RHS の型が代入可能性のルールに従って一致しなければならないことを示します (詳細については 型統一 のセクションを参照してください)。同様に、型パラメータ S
はその制約 ~[]E
を満たさなければなりません。これは S ≡C ~[]E
として表現でき、X ≡C Y
は「X
が制約 Y
を満たす」となります。これらの観察は、2つの方程式のセットに導きます
Slice ≡A S (1)
S ≡C ~[]E (2)
これにより、型パラメータ S
と E
を解くことができます。(1) からコンパイラは S
の型引数が Slice
であると推論できます。同様に、Slice
の基底型が []int
であり、[]int
が制約の []E
と一致しなければならないため、コンパイラは E
が int
であると推論できます。したがって、これら2つの方程式に対して、型推論は推論します
S ➞ Slice
E ➞ int
型方程式のセットが与えられた場合、解決すべき型パラメータは、インスタンス化が必要であり、明示的な型引数が提供されていない関数の型パラメータです。これらの型パラメータは 束縛された 型パラメータと呼ばれます。たとえば、上記の dedup
の例では、型パラメータ S
と E
は dedup
に束縛されています。ジェネリック関数呼び出しへの引数は、ジェネリック関数自体である場合があります。その関数の型パラメータは、束縛された型パラメータのセットに含まれます。関数引数の型は、他の関数 (たとえば、関数呼び出しを含むジェネリック関数) の型パラメータを含む場合があります。それらの型パラメータは型方程式にも現れる可能性がありますが、そのコンテキストでは束縛されていません。型方程式は常に束縛された型パラメータのみに対して解決されます。
型推論は、ジェネリック関数の呼び出しや、(明示的に関数型の) 変数へのジェネリック関数の代入をサポートします。これには、ジェネリック関数を他の (おそらくジェネリックでもある) 関数への引数として渡すことや、結果としてジェネリック関数を返すことが含まれます。型推論は、これらの各ケースに特有の方程式のセットで動作します。方程式は次のとおりです (型引数リストは明確にするために省略されています):
- 関数呼び出し
f(a0, a1, …)
でf
または関数引数ai
がジェネリック関数である場合:
各ペア(ai, pi)
の対応する関数引数とパラメータで、ai
が 型なし定数 でない場合、方程式typeof(pi) ≡A typeof(ai)
が生成されます。
もしai
が型なし定数cj
であり、typeof(pi)
が束縛型パラメータPk
である場合、ペア(cj, Pk)
は型方程式とは別に収集されます。 - ジェネリック関数
f
を (非ジェネリック) 関数型の変数v
に代入する場合の代入v = f
:typeof(v) ≡A typeof(f)
. 結果として (非ジェネリック) 結果変数
r
に返されるジェネリック関数f
の戻り文return …, f, …
の場合:typeof(r) ≡A typeof(f)
.さらに、各型パラメータ
Pk
と対応する型制約Ck
は型方程式Pk ≡C Ck
を生成します。型推論は、型オペランドから得られた型情報を型なし定数を考慮する前に優先します。したがって、推論は2つのフェーズで進行します:
1. 型方程式は 型統一 を使用して束縛型パラメータに対して解決されます。統一が失敗した場合、型推論は失敗します。
2. 型引数がまだ推論されていない束縛型パラメータ
Pk
に対して、同じ型パラメータを持つ1つ以上のペア(cj, Pk)
が収集された場合、すべてのペアの定数cj
の 定数の種類 を 定数式 と同様に決定します。Pk
の型引数は、決定された定数の種類の デフォルト型 です。定数の種類が矛盾するために決定できない場合、型推論は失敗します。これら2つのフェーズの後にすべての型引数が見つからなかった場合、型推論は失敗します。
2つのフェーズが成功した場合、型推論は各束縛型パラメータの型引数を決定しました:
Pk ➞ Ak
型引数 Ak
は、他の束縛型パラメータ Pk
を要素型として含む複合型である場合があります (または単に別の束縛型パラメータである場合もあります)。繰り返しの簡略化の過程で、各型引数内の束縛型パラメータは、それらの型パラメータに対するそれぞれの型引数で置き換えられ、各型引数が束縛型パラメータから解放されるまで続きます。
型引数が束縛型パラメータを介して自己参照の循環を含む場合、簡略化およびしたがって型推論は失敗します。そうでなければ、型推論は成功します。
型統一
型推論は 型統一 を通じて型方程式を解決します。型統一は、方程式の LHS と RHS の型を再帰的に比較し、いずれかまたは両方の型が束縛型パラメータを含む場合、LHS と RHS が一致するように型引数を探します (文脈に応じて同一または代入互換性を持つ)。そのため、型推論は束縛型パラメータから推論された型引数のマップを維持します。このマップは型統一中に参照され、更新されます。最初は、束縛型パラメータは知られていますが、マップは空です。型統一中に新しい型引数 A
が推論されると、型パラメータから引数への対応マッピング P ➞ A
がマップに追加されます。逆に、型を比較する際には、既知の型引数 (マップエントリが既に存在する型引数) が対応する型パラメータの代わりに置き換えられます。型推論が進むにつれて、マップはますます充実し、すべての方程式が考慮されるか、統一が失敗するまで続きます。型推論は、統一ステップが失敗せず、マップに各型パラメータのエントリがある場合に成功します。
たとえば、束縛型パラメータ P
を持つ型方程式が与えられた場合
[10]struct{ elem P, list []P } ≡A [10]struct{ elem string; list []string }
型推論は空のマップから始まります。統一は最初に LHS と RHS の型の最上位構造を比較します。両方が同じ長さの配列であり、要素型が統一される場合、統一されます。両方の要素型が構造体であり、同じ数のフィールドを持ち、同じ名前を持ち、フィールド型が統一される場合、統一されます。P
の型引数はまだ知られていないため (マップエントリはありません)、P
と string
を統一することでマッピング P ➞ string
がマップに追加されます。list
フィールドの型を統一するには、[]P
と []string
を統一する必要があり、したがって P
と string
を統一する必要があります。この時点で P
の型引数は既に知られているため (P
のマップエントリがあります)、その型引数 string
は P
の代わりに置き換えられます。string
が string
と同一であるため、この統一ステップも成功します。方程式の LHS と RHS の統一はこれで終了です。型推論は成功します。なぜなら、型方程式は1つだけで、統一ステップは失敗せず、マップは完全に充実しているからです。
統一は、2つの型が 同一、代入互換性、または単に構造的に等しい必要があるかどうかに応じて、厳密 および 緩やかな 統一の組み合わせを使用します。該当する 型統一ルール は、付録 に詳細に記載されています。
X ≡A Y
の形式の方程式では、X
と Y
が代入に関与する型である場合、最上位の型構造は緩やかに統一される可能性がありますが、要素型は厳密に一致し、代入のルールに従って一致しなければなりません。
P ≡C C
の形式の方程式では、P
が型パラメータであり、C
がその対応する制約である場合、統一ルールは少し複雑です:
C
が コア型core(C)
を持ち、P
が既知の型引数A
を持つ場合、core(C)
とA
は緩やかに統一されなければなりません。P
に既知の型引数がない場合、C
に基底型 (チルダ型) でない型項T
が正確に1つ含まれている場合、統一はマッピングP ➞ T
をマップに追加します。C
にコア型がない場合、P
に既知の型引数A
がある場合、A
はC
のすべてのメソッドを持たなければならず、もしあれば、対応するメソッド型は厳密に一致しなければなりません。型制約から型方程式を解決する際、1つの方程式を解決することで追加の型引数を推論でき、これにより他の方程式を解決できる場合があります。型推論は、新しい型引数が推論される限り、型統一を繰り返します。
演算子
演算子はオペランドを式に結合します。
= | .
= | .
= "||" | "&&" | | | .
= "==" | "!=" | "<" | "<=" | ">" | ">=" .
= "+" | "-" | "|" | "^" .
= "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" .
= "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
比較は 他の場所 で議論されています。他の二項演算子の場合、オペランドの型は 同一 でなければならず、操作がシフトまたは型なし 定数 を含む場合を除きます。定数のみを含む操作については、定数式 のセクションを参照してください。
シフト操作を除いて、1つのオペランドが型なし 定数 であり、もう1つのオペランドがそうでない場合、定数は暗黙的に 変換 され、他のオペランドの型に合わせられます。
シフト式の右オペランドは 整数型 [Go 1.13] であるか、型 uint
の値で表現可能な型なし定数でなければなりません。非定数シフト式の左オペランドが型なし定数である場合、最初にシフト式がその左オペランドだけに置き換えられた場合に仮定される型に暗黙的に変換されます。
var a [1024]byte
var s uint = 33
// The results of the following examples are given for 64-bit ints.
var i = 1<<s // 1 has type int
var j int32 = 1<<s // 1 has type int32; j == 0
var k = uint64(1<<s) // 1 has type uint64; k == 1<<33
var m int = 1.0<<s // 1.0 has type int; m == 1<<33
var n = 1.0<<s == j // 1.0 has type int32; n == true
var o = 1<<s == 2<<s // 1 and 2 have type int; o == false
var p = 1<<s == 1<<33 // 1 has type int; p == true
var u = 1.0<<s // illegal: 1.0 has type float64, cannot shift
var u1 = 1.0<<s != 0 // illegal: 1.0 has type float64, cannot shift
var u2 = 1<<s != 1.0 // illegal: 1 has type float64, cannot shift
var v1 float32 = 1<<s // illegal: 1 has type float32, cannot shift
var v2 = string(1<<s) // illegal: 1 is converted to a string, cannot shift
var w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression; w == 1<<33
var x = a[1.0<<s] // panics: 1.0 has type int, but 1<<33 overflows array bounds
var b = make([]byte, 1.0<<s) // 1.0 has type int; len(b) == 1<<33
// The results of the following examples are given for 32-bit ints,
// which means the shifts will overflow.
var mm int = 1.0<<s // 1.0 has type int; mm == 0
var oo = 1<<s == 2<<s // 1 and 2 have type int; oo == true
var pp = 1<<s == 1<<33 // illegal: 1 has type int, but 1<<33 overflows int
var xx = a[1.0<<s] // 1.0 has type int; xx == a[0]
var bb = make([]byte, 1.0<<s) // 1.0 has type int; len(bb) == 0
演算子の優先順位
単項演算子は最も高い優先順位を持ちます。++
および --
演算子は文を形成するため、式ではなく、演算子の階層の外にあります。その結果、文 *p++
は (*p)++
と同じです。
二項演算子には5つの優先順位レベルがあります。乗算演算子が最も強く、次に加算演算子、比較演算子、&&
(論理 AND)、最後に ||
(論理 OR) があります:
Precedence Operator
5 * / % << >> & &^
4 + - | ^
3 == != < <= > >=
2 &&
1 ||
同じ優先順位の二項演算子は左から右に結合します。たとえば、x / y * z
は (x / y) * z
と同じです。
+x // x
42 + a - b // (42 + a) - b
23 + 3*x[i] // 23 + (3 * x[i])
x <= f() // x <= f()
^a >> b // (^a) >> b
f() || g() // f() || g()
x == y+1 && <-chanInt > 0 // (x == (y+1)) && ((<-chanInt) > 0)
算術演算子
算術演算子は数値値に適用され、最初のオペランドと同じ型の結果を生成します。4つの標準算術演算子 (+
, -
, *
, /
) は 整数、浮動小数点、および 複素数 型に適用され、+
は 文字列 にも適用されます。ビット単位の論理およびシフト演算子は整数にのみ適用されます。
+ sum integers, floats, complex values, strings
- difference integers, floats, complex values
* product integers, floats, complex values
/ quotient integers, floats, complex values
% remainder integers
& bitwise AND integers
| bitwise OR integers
^ bitwise XOR integers
&^ bit clear (AND NOT) integers
<< left shift integer << integer >= 0
>> right shift integer >> integer >= 0
オペランドの型が 型パラメータ である場合、演算子はその型セット内の各型に適用されなければなりません。オペランドは、型パラメータが インスタンス化 される型引数の値として表され、演算はその型引数の精度で計算されます。たとえば、次の関数が与えられた場合:
func dotProduct[F ~float32|~float64](v1, v2 []F) F {
var s F
for i, x := range v1 {
y := v2[i]
s += x * y
}
return s
}
積 x * y
と加算 s += x * y
は、それぞれ float32
または float64
の精度で計算されます。
整数演算子
2つの整数値 x
と y
に対して、整数商 q = x / y
と余り r = x % y
は次の関係を満たします:
x = q*y + r and |r| < |y|
x / y
はゼロに向かって切り捨てられます (“切り捨て除算”)。
x y x / y x % y
5 3 1 2
-5 3 -1 -2
5 -3 -1 2
-5 -3 1 -2
このルールの唯一の例外は、被除数 x
が x
の int 型の最も負の値である場合、商 q = x / -1
は x
(および r = 0
) に等しくなります。これは二の補数 整数オーバーフロー によるものです:
x, q
int8 -128
int16 -32768
int32 -2147483648
int64 -9223372036854775808
除数が 定数 である場合、ゼロであってはなりません。除数が実行時にゼロである場合、ランタイムパニック が発生します。被除数が非負で、除数が定数の2の累乗である場合、除算は右シフトに置き換えられ、余りの計算はビット単位の AND 操作に置き換えられる場合があります:
x x / 4 x % 4 x >> 2 x & 3
11 2 3 2 3
-11 -2 -3 -3 1
シフト演算子は、左オペランドを右オペランドによって指定されたシフトカウントだけシフトします。このカウントは非負でなければなりません。シフトカウントが実行時に負である場合、ランタイムパニック が発生します。シフト演算子は、左オペランドが符号付き整数である場合は算術シフトを、符号なし整数である場合は論理シフトを実装します。シフトカウントに上限はありません。シフトは、左オペランドが n
回 1 でシフトされるかのように振る舞います。シフトカウントが n
の場合、x << 1
は x*2
と同じで、x >> 1
は x/2
と同じですが、負の無限大に向かって切り捨てられます。
整数オペランドに対して、単項演算子 +
, -
, および ^
は次のように定義されます:
+x is 0 + x
-x negation is 0 - x
^x bitwise complement is m ^ x with m = "all bits set to 1" for unsigned x
and m = -1 for signed x
整数オーバーフロー
符号なし整数 値に対して、操作 +
, -
, *
, および <<
は 2n の剰余で計算されます。ここで、n は符号なし整数の型のビット幅です。大まかに言えば、これらの符号なし整数操作はオーバーフロー時に高位ビットを破棄し、プログラムは「ラップアラウンド」に依存できます。
符号付き整数に対して、操作 +
, -
, *
, /
, および <<
は合法的にオーバーフローする可能性があり、結果の値は符号付き整数表現、操作、およびそのオペランドによって存在し、決定的に定義されます。オーバーフローは ランタイムパニック を引き起こしません。コンパイラは、オーバーフローが発生しないという仮定の下でコードを最適化することはできません。たとえば、x < x + 1
が常に真であると仮定することはできません。
浮動小数点演算子
浮動小数点および複素数に対して、+x
は x
と同じであり、-x
は x
の否定です。ゼロによる浮動小数点または複素数の除算の結果は、IEEE 754 標準を超えて指定されておらず、ランタイムパニック が発生するかどうかは実装に依存します。
実装は、複数の浮動小数点操作を単一の融合操作に結合し、文をまたいで、個別に命令を実行して丸めた値とは異なる結果を生成する場合があります。明示的な 浮動小数点型 変換 は、ターゲット型の精度に丸められ、その丸めを破棄する融合を防ぎます。
たとえば、一部のアーキテクチャは、x*y + z
を計算する「融合乗算加算」(FMA) 命令を提供し、中間結果 x*y
を丸めずに計算します。これらの例は、Go 実装がその命令を使用できる場合を示しています:
// FMA allowed for computing r, because x*y is not explicitly rounded:
r = x*y + z
r = z; r += x*y
t = x*y; r = t + z
*p = x*y; r = *p + z
r = x*y + float64(z)
// FMA disallowed for computing r, because it would omit rounding of x*y:
r = float64(x*y) + z
r = z; r += float64(x*y)
t = float64(x*y); r = t + z
文字列の連結
文字列は +
演算子または +=
代入演算子を使用して連結できます:
s := "hi" + string(c)
s += " and good bye"
文字列の加算は、オペランドを連結することによって新しい文字列を作成します。
比較演算子
比較演算子は二つのオペランドを比較し、型なしのブール値を返します。
== equal
!= not equal
< less
<= less or equal
> greater
>= greater or equal
いかなる比較においても、最初のオペランドは二番目のオペランドの型に代入可能でなければならず、その逆も同様です。
等価演算子 ==
と !=
は 比較可能 な型のオペランドに適用されます。順序演算子 <
、<=
、>
、および >=
は 順序付けられた 型のオペランドに適用されます。これらの用語と比較の結果は次のように定義されます:
- ブール型は比較可能です。二つのブール値は、両方が
true
であるか、または両方がfalse
である場合に等しいです。 - 整数型は比較可能であり、順序付けられています。二つの整数値は通常の方法で比較されます。
- 浮動小数点型は比較可能であり、順序付けられています。二つの浮動小数点値は IEEE 754 標準に従って比較されます。
- 複素型は比較可能です。二つの複素値
u
とv
は、両方がreal(u) == real(v)
かつimag(u) == imag(v)
である場合に等しいです。 - 文字列型は比較可能であり、順序付けられています。二つの文字列値はバイト単位で辞書式に比較されます。
- ポインタ型は比較可能です。二つのポインタ値は、同じ変数を指している場合、または両方が値
nil
を持つ場合に等しいです。異なるゼロサイズの変数へのポインタは等しい場合もあれば、そうでない場合もあります。 - チャンネル型は比較可能です。二つのチャンネル値は、同じ呼び出しによって作成された場合、または両方が値
nil
を持つ場合に等しいです。 - 型パラメータでないインターフェース型は比較可能です。二つのインターフェース値は、同一の動的型を持ち、等しい動的値を持つ場合、または両方が値
nil
を持つ場合に等しいです。 - 非インターフェース型
X
の値x
とインターフェース型T
の値t
は、型X
が比較可能であり、X
がT
を実装している場合に比較できます。t
の動的型がX
と同一であり、t
の動的値がx
に等しい場合、等しいです。 - 構造体型は、すべてのフィールド型が比較可能である場合に比較可能です。二つの構造体値は、対応する非空白フィールド値が等しい場合に等しいです。フィールドはソース順に比較され、二つのフィールド値が異なると比較は停止します(またはすべてのフィールドが比較されます)。
- 配列型は、配列要素型が比較可能である場合に比較可能です。二つの配列値は、対応する要素値が等しい場合に等しいです。要素は昇順のインデックス順に比較され、二つの要素値が異なると比較は停止します(またはすべての要素が比較されます)。
型パラメータは、厳密に比較可能である場合に比較可能です(以下を参照)。
二つの同一の動的型を持つインターフェース値の比較は、その型が比較可能でない場合、ランタイムパニックを引き起こします。この動作は、直接のインターフェース値の比較だけでなく、インターフェース値の配列やインターフェース値フィールドを持つ構造体の比較にも適用されます。
スライス、マップ、および関数型は比較可能ではありません。ただし、特別なケースとして、スライス、マップ、または関数値は、事前に宣言された識別子
nil
と比較されることがあります。ポインタ、チャンネル、およびインターフェース値をnil
と比較することも許可されており、上記の一般的なルールに従います。
const c = 3 < 4 // c is the untyped boolean constant true
type MyBool bool
var x, y int
var (
// The result of a comparison is an untyped boolean.
// The usual assignment rules apply.
b3 = x == y // b3 has type bool
b4 bool = x == y // b4 has type bool
b5 MyBool = x == y // b5 has type MyBool
)
型は 厳密に比較可能 である場合、比較可能であり、インターフェース型でなく、インターフェース型で構成されていない必要があります。具体的には:
- ブール、数値、文字列、ポインタ、およびチャンネル型は厳密に比較可能です。
- 構造体型は、すべてのフィールド型が厳密に比較可能である場合に厳密に比較可能です。
- 配列型は、配列要素型が厳密に比較可能である場合に厳密に比較可能です。
- 型パラメータは、型セット内のすべての型が厳密に比較可能である場合に厳密に比較可能です。
論理演算子
論理演算子はブール値に適用され、オペランドと同じ型の結果を返します。左側のオペランドが評価され、その条件が必要な場合に右側が評価されます。
&& conditional AND p && q is "if p then q else false"
|| conditional OR p || q is "if p then true else q"
! NOT !p is "not p"
アドレス演算子
型 T
のオペランド x
に対して、アドレス操作 &x
は x
への型 *T
のポインタを生成します。オペランドは アドレス可能 でなければならず、すなわち、変数、ポインタ間接参照、またはスライスインデックス操作である必要があります。または、アドレス可能な構造体オペランドのフィールドセレクタである必要があります。または、アドレス可能な配列の配列インデックス操作である必要があります。アドレス可能性の要件の例外として、x
は(おそらく括弧で囲まれた)複合リテラルである場合もあります。x
の評価がランタイムパニックを引き起こす場合、&x
の評価も同様に引き起こします。
型 *T
のポインタオペランド x
に対して、ポインタ間接参照 *x
は x
によって指される型 T
の変数を示します。x
が nil
の場合、*x
の評価を試みるとランタイムパニックが発生します。
&x
&a[f(2)]
&Point{2, 3}
*p
*pf(x)
var x *int = nil
*x // causes a run-time panic
&*x // causes a run-time panic
受信演算子
コア型がチャンネルであるオペランド ch
に対して、受信操作 <-ch
の値はチャンネル ch
から受信された値です。チャンネルの方向は受信操作を許可する必要があり、受信操作の型はチャンネルの要素型です。この式は、値が利用可能になるまでブロックされます。nil
チャンネルからの受信は永遠にブロックされます。 閉じたチャンネルでの受信操作は常に即座に進行でき、以前に送信された値が受信された後に要素型のゼロ値を返します。
v1 := <-ch
v2 = <-ch
f(<-ch)
<-strobe // wait until clock pulse and discard received value
代入文や特別な形式の初期化で使用される受信式は、通信が成功したかどうかを報告する追加の型なしブール結果を生成します。ok
の値は、受信された値がチャンネルへの成功した送信操作によって配信された場合は true
であり、チャンネルが閉じて空であるために生成されたゼロ値である場合は false
です。
変換
変換は、式の型を変換によって指定された型に変更します。変換はソース内に文字通り現れる場合もあれば、式が現れる文脈によって暗黙的に行われる場合もあります。
明示的 変換は、T(x)
の形式の式であり、T
は型で、x
は型 T
に変換可能な式です。
= "(" [ "," ] ")" .
型が演算子 *
または <-
で始まる場合、または型がキーワード func
で始まり、結果リストがない場合、曖昧さを避けるために必要に応じて括弧で囲む必要があります:
*Point(p) // same as *(Point(p))
(*Point)(p) // p is converted to *Point
<-chan int(c) // same as <-(chan int(c))
(<-chan int)(c) // c is converted to <-chan int
func()(x) // function signature func() x
(func())(x) // x is converted to func()
(func() int)(x) // x is converted to func() int
func() int(x) // x is converted to func() int (unambiguous)
定数値 x
は、x
が T
の値によって表現可能である場合、型 T
に変換できます。特別なケースとして、整数定数 x
は、非定数 x
と同じルールを使用して文字列型に明示的に変換できます。
定数を型パラメータでない型に変換すると、型付き定数が得られます。
uint(iota) // iota value of type uint
float32(2.718281828) // 2.718281828 of type float32
complex128(1) // 1.0 + 0.0i of type complex128
float32(0.49999999) // 0.5 of type float32
float64(-1e-1000) // 0.0 of type float64
string('x') // "x" of type string
string(0x266c) // "♬" of type string
myString("foo" + "bar") // "foobar" of type myString
string([]byte{'a'}) // not a constant: []byte{'a'} is not a constant
(*int)(nil) // not a constant: nil is not a constant, *int is not a boolean, numeric, or string type
int(1.2) // illegal: 1.2 cannot be represented as an int
string(65.0) // illegal: 65.0 is not an integer constant
定数を型パラメータに変換すると、その型の非定数値が得られ、値は型パラメータが具現化される型引数の値として表現されます。たとえば、次の関数があるとします:
func f[P ~float32|~float64]() {
… P(1.1) …
}
変換 P(1.1)
は、型 P
の非定数値を生成し、値 1.1
は float32
または float64
として表現され、f
の型引数に依存します。したがって、f
が float32
型で具現化される場合、式 P(1.1) + 1.2
の数値値は、対応する非定数 float32
加算と同じ精度で計算されます。
非定数値 x
は、次のいずれかの場合に型 T
に変換できます:
x
はT
に代入可能です。- 構造体タグを無視すると(以下を参照)、
x
の型とT
は型パラメータでなく、同一の基礎型を持ちます。 - 構造体タグを無視すると(以下を参照)、
x
の型とT
はポインタ型であり、名前付き型でなく、ポインタ基底型は型パラメータでなく、同一の基礎型を持ちます。 x
の型とT
は両方とも整数または浮動小数点型です。x
の型とT
は両方とも複素型です。x
は整数またはバイトまたはルーンのスライスであり、T
は文字列型です。x
は文字列であり、T
はバイトまたはルーンのスライスです。x
はスライスであり、T
は配列 [Go 1.20] または配列へのポインタ [Go 1.17] であり、スライスと配列型は同一の要素型を持ちます。さらに、
T
またはx
の型V
が型パラメータである場合、x
も次の条件のいずれかが適用される場合に型T
に変換できます:V
とT
の両方が型パラメータであり、V
の型セット内の各型の値がT
の型セット内の各型に変換可能です。V
のみが型パラメータであり、V
の型セット内の各型の値がT
に変換可能です。T
のみが型パラメータであり、x
がT
の型セット内の各型に変換可能です。構造体タグは、変換の目的で構造体型の同一性を比較する際に無視されます:
type Person struct {
Name string
Address *struct {
Street string
City string
}
}
var data *struct {
Name string `json:"name"`
Address *struct {
Street string `json:"street"`
City string `json:"city"`
} `json:"address"`
}
var person = (*Person)(data) // ignoring tags, the underlying types are identical
数値型間または文字列型との間の(非定数)変換には特定のルールが適用されます。これらの変換は x
の表現を変更し、ランタイムコストが発生する可能性があります。他のすべての変換は型を変更するだけで、x
の表現は変更しません。
ポインタと整数の間で変換するための言語的メカニズムはありません。パッケージ unsafe
は、制限された状況下でこの機能を実装します。
数値型間の変換
非定数数値の変換には、次のルールが適用されます:
- 1. 整数型間の変換の場合、値が符号付き整数である場合、暗黙的に無限精度に符号拡張されます。そうでない場合はゼロ拡張されます。その後、結果型のサイズに収まるように切り捨てられます。たとえば、
v := uint16(0x10F0)
の場合、uint32(int8(v)) == 0xFFFFFFF0
です。変換は常に有効な値を返し、オーバーフローの兆候はありません。 - 2. 浮動小数点数を整数に変換する場合、小数部分は破棄されます(ゼロに向かって切り捨て)。
3. 整数または浮動小数点数を浮動小数点型に変換する場合、または複素数を別の複素型に変換する場合、結果値は宛先型によって指定された精度に丸められます。たとえば、型
float32
の変数x
の値は、IEEE 754 32ビット数の精度を超える追加の精度を使用して保存される場合がありますが、float32(x) はx
の値を32ビット精度に丸めた結果を表します。同様に、x + 0.1
は32ビット以上の精度を使用する場合がありますが、float32(x + 0.1)
は使用しません。浮動小数点または複素値を含むすべての非定数変換において、結果型が値を表現できない場合、変換は成功しますが、結果値は実装依存です。
文字列型との間の変換
1. バイトのスライスを文字列型に変換すると、スライスの要素が連続するバイトを持つ文字列が得られます。
string([]byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø"
string([]byte{}) // ""
string([]byte(nil)) // ""
type bytes []byte
string(bytes{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø"
type myByte byte
string([]myByte{'w', 'o', 'r', 'l', 'd', '!'}) // "world!"
myString([]myByte{'\xf0', '\x9f', '\x8c', '\x8d'}) // "🌍"
2. ルーンのスライスを文字列型に変換すると、個々のルーン値を文字列に変換したものを連結した文字列が得られます。
string([]rune{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔"
string([]rune{}) // ""
string([]rune(nil)) // ""
type runes []rune
string(runes{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔"
type myRune rune
string([]myRune{0x266b, 0x266c}) // "\u266b\u266c" == "♫♬"
myString([]myRune{0x1f30e}) // "\U0001f30e" == "🌎"
3. 文字列型の値をバイト型のスライスに変換すると、文字列のバイトを持つ非nilスライスが得られます。
[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
[]byte("") // []byte{}
bytes("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
[]myByte("world!") // []myByte{'w', 'o', 'r', 'l', 'd', '!'}
[]myByte(myString("🌏")) // []myByte{'\xf0', '\x9f', '\x8c', '\x8f'}
4. 文字列型の値をルーン型のスライスに変換すると、文字列の個々のUnicodeコードポイントを含むスライスが得られます。
[]rune(myString("白鵬翔")) // []rune{0x767d, 0x9d6c, 0x7fd4}
[]rune("") // []rune{}
runes("白鵬翔") // []rune{0x767d, 0x9d6c, 0x7fd4}
[]myRune("♫♬") // []myRune{0x266b, 0x266c}
[]myRune(myString("🌐")) // []myRune{0x1f310}
5. 最後に、歴史的な理由から、整数値を文字列型に変換することができます。この形式の変換は、与えられた整数値のUnicodeコードポイントの(おそらくマルチバイトの)UTF-8表現を含む文字列を生成します。有効なUnicodeコードポイントの範囲外の値は
"\uFFFD"
に変換されます。string('a') // "a"
string(65) // "A"
string('\xf8') // "\u00f8" == "ø" == "\xc3\xb8"
string(-1) // "\ufffd" == "\xef\xbf\xbd"
type myString string
myString('\u65e5') // "\u65e5" == "日" == "\xe6\x97\xa5"
注意:この形式の変換は最終的に言語から削除される可能性があります。
go vet
ツールは、特定の整数から文字列への変換を潜在的なエラーとしてフラグ付けします。utf8.AppendRune
やutf8.EncodeRune
のようなライブラリ関数を代わりに使用するべきです。
スライスから配列または配列ポインタへの変換
スライスを配列に変換すると、スライスの基礎となる配列の要素を含む配列が得られます。同様に、スライスを配列ポインタに変換すると、スライスの基礎となる配列へのポインタが得られます。いずれの場合も、スライスの長さが配列の長さよりも短い場合、ランタイムパニックが発生します。
s := make([]byte, 2, 4)
a0 := [0]byte(s)
a1 := [1]byte(s[1:]) // a1[0] == s[1]
a2 := [2]byte(s) // a2[0] == s[0]
a4 := [4]byte(s) // panics: len([4]byte) > len(s)
s0 := (*[0]byte)(s) // s0 != nil
s1 := (*[1]byte)(s[1:]) // &s1[0] == &s[1]
s2 := (*[2]byte)(s) // &s2[0] == &s[0]
s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s)
var t []string
t0 := [0]string(t) // ok for nil slice t
t1 := (*[0]string)(t) // t1 == nil
t2 := (*[1]string)(t) // panics: len([1]string) > len(t)
u := make([]byte, 0)
u0 := (*[0]byte)(u) // u0 != nil
定数式
定数式は、定数オペランドのみを含むことができ、コンパイル時に評価されます。
型なしのブール、数値、および文字列定数は、それぞれブール、数値、または文字列型のオペランドを使用することが合法である場所でオペランドとして使用できます。
定数比較は常に型なしのブール定数を返します。定数シフト式の左側のオペランドが型なしの定数である場合、結果は整数定数になります。そうでない場合は、左側のオペランドと同じ型の定数になります。左側のオペランドは整数型でなければなりません。
型なし定数に対する他の操作は、同じ種類の型なし定数を生成します。すなわち、ブール、整数、浮動小数点、複素、または文字列定数です。二項演算の型なしオペランド(シフト以外)が異なる種類である場合、結果はこのリストの後に現れるオペランドの種類になります:整数、ルーン、浮動小数点、複素。たとえば、型なしの整数定数を型なしの複素定数で割ると、型なしの複素定数が得られます。
const a = 2 + 3.0 // a == 5.0 (untyped floating-point constant)
const b = 15 / 4 // b == 3 (untyped integer constant)
const c = 15 / 4.0 // c == 3.75 (untyped floating-point constant)
const Θ float64 = 3/2 // Θ == 1.0 (type float64, 3/2 is integer division)
const Π float64 = 3/2. // Π == 1.5 (type float64, 3/2. is float division)
const d = 1 << 3.0 // d == 8 (untyped integer constant)
const e = 1.0 << 3 // e == 8 (untyped integer constant)
const f = int32(1) << 33 // illegal (constant 8589934592 overflows int32)
const g = float64(2) >> 1 // illegal (float64(2) is a typed floating-point constant)
const h = "foo" > "bar" // h == true (untyped boolean constant)
const j = true // j == true (untyped boolean constant)
const k = 'w' + 1 // k == 'x' (untyped rune constant)
const l = "hi" // l == "hi" (untyped string constant)
const m = string(k) // m == "x" (type string)
const Σ = 1 - 0.707i // (untyped complex constant)
const Δ = Σ + 2.0e-4 // (untyped complex constant)
const Φ = iota*1i - 1/1i // (untyped complex constant)
組み込み関数 complex
を型なしの整数、ルーン、または浮動小数点定数に適用すると、型なしの複素定数が得られます。
const ic = complex(0, c) // ic == 3.75i (untyped complex constant)
const iΘ = complex(0, Θ) // iΘ == 1i (type complex128)
定数式は常に正確に評価されます。中間値や定数自体は、言語内の事前に宣言された型がサポートするよりもはるかに大きな精度を必要とする場合があります。次のような宣言は合法です:
const Huge = 1 << 100 // Huge == 1267650600228229401496703205376 (untyped integer constant)
const Four int8 = Huge >> 98 // Four == 4 (type int8)
定数の除算または剰余演算の除数はゼロであってはなりません:
3.14 / 0.0 // illegal: division by zero
型付き 定数の値は、常に定数型の値によって正確に表現可能でなければなりません。次の定数式は不正です:
uint(-1) // -1 cannot be represented as a uint
int(3.14) // 3.14 cannot be represented as an int
int64(Huge) // 1267650600228229401496703205376 cannot be represented as an int64
Four * 300 // operand 300 cannot be represented as an int8 (type of Four)
Four * 100 // product 400 cannot be represented as an int8 (type of Four)
単項ビット単位の補数演算子 ^
によって使用されるマスクは、非定数に対するルールに一致します:マスクは符号なし定数の場合はすべて1、符号付きおよび型なし定数の場合は-1です。
^1 // untyped integer constant, equal to -2
uint8(^1) // illegal: same as uint8(-2), -2 cannot be represented as a uint8
^uint8(1) // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE)
int8(^1) // same as int8(-2)
^int8(1) // same as -1 ^ int8(1) = -2
実装制限:コンパイラは、型なしの浮動小数点または複素定数式を計算する際に丸めを使用する場合があります。これは、定数に関するセクションの実装制限を参照してください。この丸めにより、型なしの浮動小数点定数式が整数コンテキストで無効になる可能性があります。無限精度で計算した場合に整数である場合でも、逆もまた然りです。
評価の順序
パッケージレベルでは、初期化依存関係が変数宣言内の個々の初期化式の評価順序を決定します。それ以外の場合、式、代入、または戻り文のオペランドを評価する際には、すべての関数呼び出し、メソッド呼び出し、受信操作、および二項論理演算が字句的に左から右の順序で評価されます。
たとえば、(関数ローカル)代入において
y[f()], ok = g(z || h(), i()+x[j()], <-c), k()
関数呼び出しと通信は、f()
、h()
(z
が false に評価される場合)、i()
、j()
、<-c
、g()
、および k()
の順に行われます。ただし、x
の評価とインデックス付け、および y
と z
の評価に対するこれらのイベントの順序は、字句的に要求される場合を除いて指定されていません。たとえば、g
はその引数が評価される前に呼び出すことはできません。
a := 1
f := func() int { a++; return a }
x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified
n := map[int]int{a: f()} // n may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
パッケージレベルでは、初期化依存関係が個々の初期化式に対する左から右のルールを上書きしますが、各式内のオペランドには適用されません:
var a, b, c = f() + v(), g(), sqr(u()) + v()
func f() int { return c }
func g() int { return a }
func sqr(x int) int { return x*x }
// functions u and v are independent of all other variables and functions
関数呼び出しは u()
、sqr()
、v()
、f()
、v()
、および g()
の順に行われます。
単一の式内の浮動小数点演算は、演算子の結合性に従って評価されます。明示的な括弧は、デフォルトの結合性を上書きすることによって評価に影響を与えます。式 x + (y + z)
では、加算 y + z
が x
を加える前に実行されます。
文
文は実行を制御します。
=
| | |
| | | | |
| | | | | |
.
= | | | | | .
終了文
終了文 は、ブロック内の制御の通常の流れを中断します。次の文は終了文です:
- 1. “return” または “goto” 文。
- 2. 組み込み関数
panic
の呼び出し。 - 3. 終了文で終わる文リストを持つブロック。
- 4. “if” 文 で、次の条件を満たす場合:
- “else” ブランチが存在し、
- 両方のブランチが終了文である。
- 5. “for” 文 で、次の条件を満たす場合:
- “for” 文を参照する “break” 文が存在せず、
- ループ条件が存在せず、
- “for” 文が範囲句を使用しない。
- 6. “switch” 文 で、次の条件を満たす場合:
- “switch” 文を参照する “break” 文が存在せず、
- デフォルトケースが存在し、
- 各ケースの文リスト(デフォルトを含む)が終了文で終わるか、またはラベル付きの“fallthrough” 文で終わる。
- 7. “select” 文 で、次の条件を満たす場合:
- “select” 文を参照する “break” 文が存在せず、
- 各ケースの文リスト(デフォルトが存在する場合はそれを含む)が終了文で終わる。
8. 終了文にラベルを付けたラベル付き文。
その他のすべての文は終了文ではありません。
文リストは、空でない場合、最後の非空文が終了文である場合に終了文で終わります。
空文
空文は何もしません。
= .
ラベル付き文
ラベル付き文は goto
、break
または continue
文のターゲットになることがあります。
= ":" .
= .
Error: log.Panic("error encountered")
式文
特定の組み込み関数を除いて、関数およびメソッドの呼び出しおよび受信操作は文の文脈に現れることができます。そのような文は括弧で囲むことができます。
= .
次の組み込み関数は文の文脈で許可されていません:
append cap complex imag len make new real
unsafe.Add unsafe.Alignof unsafe.Offsetof unsafe.Sizeof unsafe.Slice unsafe.SliceData unsafe.String unsafe.StringData
h(x+y)
f.Close()
<-ch
(<-ch)
len("foo") // illegal if len is the built-in function
送信文
送信文は、チャンネルに値を送信します。チャンネル式のコア型はチャンネルでなければならず、チャンネルの方向は送信操作を許可し、送信される値の型はチャンネルの要素型に代入可能でなければなりません。
= "<-" .
= .
チャンネルと値の式は、通信が始まる前に評価されます。通信は送信が進行できるまでブロックされます。バッファなしのチャンネルへの送信は、受信者が準備ができている場合に進行できます。バッファ付きチャンネルへの送信は、バッファに空きがある場合に進行できます。閉じたチャンネルへの送信は、ランタイムパニックを引き起こします。nil
チャンネルへの送信は永遠にブロックされます。
ch <- 3 // send value 3 to channel ch
インクリメント・デクリメント文
++ および — 文は、オペランドを型なしの定数 1
だけ増加または減少させます。代入と同様に、オペランドはアドレス可能であるか、マップインデックス式でなければなりません。
= ( "++" | "--" ) .
次の代入文は意味的に等価です:
IncDec statement Assignment
x++ x += 1
x-- x -= 1
代入文
代入 は、変数に格納されている現在の値を、式によって指定された新しい値に置き換えます。代入文は、単一の値を単一の変数に代入するか、または一致する数の変数に複数の値を代入することができます。
= .
= [ | ] "=" .
各左辺オペランドはアドレス可能でなければならず、マップインデックス式であるか、(=
代入のみの場合)空白識別子でなければなりません。オペランドは括弧で囲むことができます。
x = 1
*p = f()
a[i] = 23
(k) = <-ch // same as: k = <-ch
代入操作 x
op=
y
は、op が二項算術演算子である場合、x
=
x
op (y)
に相当しますが、x
は一度だけ評価されます。op=
構文は単一のトークンです。代入操作では、左辺および右辺の式リストはそれぞれ正確に一つの単一値式を含む必要があり、左辺の式は空白識別子であってはなりません。
a[i] <<= 2
i &^= 1<<n
タプル代入は、多値操作の個々の要素を変数のリストに代入します。二つの形式があります。最初の形式では、右辺オペランドは関数呼び出し、チャンネルまたはマップ操作、または型アサーションなどの単一の多値式です。左辺のオペランドの数は、値の数と一致しなければなりません。たとえば、f
が二つの値を返す関数である場合、
x, y = f()
最初の値を x
に、二番目の値を y
に代入します。二番目の形式では、左辺のオペランドの数は右辺の式の数と等しくなければならず、右辺のn番目の式は左辺のn番目のオペランドに代入されます:
one, two, three = '一', '二', '三'
空白識別子は、代入の右辺の値を無視する方法を提供します:
_ = x // evaluate x but ignore it
x, _ = f() // evaluate f() but ignore second result value
代入は二つの段階で進行します。最初に、インデックス式およびポインタ間接参照(セレクタ内の暗黙的なポインタ間接参照を含む)のオペランドが左辺と右辺の式で通常の順序で評価されます。次に、代入は左から右の順序で実行されます。
a, b = b, a // exchange a and b
x := []int{1, 2, 3}
i := 0
i, x[i] = 1, 2 // set i = 1, x[0] = 2
i = 0
x[i], i = 2, 1 // set x[0] = 2, i = 1
x[0], x[0] = 1, 2 // set x[0] = 1, then x[0] = 2 (so x[0] == 2 at end)
x[1], x[3] = 4, 5 // set x[1] = 4, then panic setting x[3] = 5.
type Point struct { x, y int }
var p *Point
x[2], p.x = 6, 7 // set x[2] = 6, then panic setting p.x = 7
i = 2
x = []int{3, 5, 7}
for i, x[i] = range x { // set i, x[2] = 0, x[0]
break
}
// after this loop, i == 0 and x is []int{3, 5, 3}
代入では、各値は、代入先のオペランドの型に代入可能でなければならず、次の特別なケースがあります:
- 1. 任意の型付き値は空白識別子に代入できます。
- 2. 型なし定数がインターフェース型の変数または空白識別子に代入される場合、定数は最初に暗黙的に変換され、そのデフォルト型に変換されます。
- 3. 型なしブール値がインターフェース型の変数または空白識別子に代入される場合、最初に型
bool
に暗黙的に変換されます。
If statements
“If” 文は、ブール式の値に基づいて2つの分岐の条件付き実行を指定します。式が真に評価される場合、”if” 分岐が実行され、それ以外の場合は、存在する場合、”else” 分岐が実行されます。
= "if" [ ";" ] [ "else" ( | ) ] .
if x > max {
x = max
}
式の前に単純な文が置かれることがあり、これは式が評価される前に実行されます。
if x := f(); x < y {
return x
} else if x > z {
return z
} else {
return y
}
Switch statements
“Switch” 文は、多方向の実行を提供します。式または型は、”switch” 内の “cases” と比較され、どの分岐を実行するかを決定します。
= | .
2つの形式があります:式スイッチと型スイッチ。式スイッチでは、ケースにはスイッチ式の値と比較される式が含まれます。型スイッチでは、ケースには特別に注釈されたスイッチ式の型と比較される型が含まれます。スイッチ式は、スイッチ文内で正確に1回評価されます。
Expression switches
式スイッチでは、スイッチ式が評価され、ケース式は定数である必要はなく、左から右、上から下に評価されます。スイッチ式と等しい最初のものが関連するケースの文の実行をトリガーし、他のケースはスキップされます。もしケースが一致せず、”default” ケースがある場合、その文が実行されます。デフォルトケースは最大1つ存在でき、”switch” 文のどこにでも現れることができます。スイッチ式が欠落している場合、それはブール値 true
に相当します。
= "switch" [ ";" ] [ ] "{" { } "}" .
= ":" .
= "case" | "default" .
スイッチ式が未型付定数に評価される場合、最初に暗黙的に 変換されてその デフォルト型 に変換されます。事前に宣言された未型付値 nil
はスイッチ式として使用できません。スイッチ式の型は 比較可能 でなければなりません。
ケース式が未型付の場合、最初に暗黙的に 変換されてスイッチ式の型に変換されます。各(おそらく変換された)ケース式 x
とスイッチ式の値 t
に対して、x == t
は有効な 比較 でなければなりません。
言い換えれば、スイッチ式は、明示的な型なしで一時変数 t
を宣言して初期化するために使用されたかのように扱われます。それは t
の値であり、各ケース式 x
が等しいかどうかがテストされます。
ケースまたはデフォルト句では、最後の非空文は、制御がこの句の終わりから次の句の最初の文に流れるべきであることを示す(おそらく ラベル付き) “fallthrough” 文 である可能性があります。そうでなければ、制御は “switch” 文の終わりに流れます。”fallthrough” 文は、式スイッチの最後の句以外のすべての最後の文として現れることができます。
スイッチ式の前に単純な文が置かれることがあり、これは式が評価される前に実行されます。
switch tag {
default: s3()
case 0, 1, 2, 3: s1()
case 4, 5, 6, 7: s2()
}
switch x := f(); { // missing switch expression means "true"
case x < 0: return -x
default: return x
}
switch {
case x < y: f1()
case x < z: f2()
case x == 4: f3()
}
実装制限:コンパイラは、同じ定数に評価される複数のケース式を許可しない場合があります。たとえば、現在のコンパイラは、ケース式に重複する整数、浮動小数点数、または文字列定数を許可しません。
Type switches
型スイッチは、値ではなく型を比較します。それ以外は、式スイッチに似ています。これは、キーワード type
を使用して型アサーションの形式を持つ特別なスイッチ式によってマークされます。
switch x.(type) {
// cases
}
ケースは、実際の型 T
を式 x
の動的型と一致させます。型アサーションと同様に、x
は インターフェース型 でなければならず、型パラメータ ではなく、ケースにリストされている各非インターフェース型 T
は x
の型を実装しなければなりません。型スイッチのケースにリストされている型はすべて 異なる でなければなりません。
= "switch" [ ";" ] "{" { } "}" .
= [ ":=" ] "." "(" "type" ")" .
= ":" .
= "case" | "default" .
TypeSwitchGuard には 短い変数宣言 を含めることができます。その形式が使用されると、変数は各句の 暗黙のブロック の TypeSwitchCase の最後で宣言されます。正確に1つの型をリストするケースでは、変数はその型を持ちます。それ以外の場合、変数は TypeSwitchGuard の式の型を持ちます。
型の代わりに、ケースは事前に宣言された識別子 nil
を使用できます。そのケースは、TypeSwitchGuard の式が nil
インターフェース値であるときに選択されます。nil
ケースは最大1つまで存在できます。
型 x
の式 interface{}
に対して、次の型スイッチ:
switch i := x.(type) {
case nil:
printString("x is nil") // type of i is type of x (interface{})
case int:
printInt(i) // type of i is int
case float64:
printFloat64(i) // type of i is float64
case func(int) float64:
printFunction(i) // type of i is func(int) float64
case bool, string:
printString("type is bool or string") // type of i is type of x (interface{})
default:
printString("don't know the type") // type of i is type of x (interface{})
}
は次のように書き換えることができます:
v := x // x is evaluated exactly once
if v == nil {
i := v // type of i is type of x (interface{})
printString("x is nil")
} else if i, isInt := v.(int); isInt {
printInt(i) // type of i is int
} else if i, isFloat64 := v.(float64); isFloat64 {
printFloat64(i) // type of i is float64
} else if i, isFunc := v.(func(int) float64); isFunc {
printFunction(i) // type of i is func(int) float64
} else {
_, isBool := v.(bool)
_, isString := v.(string)
if isBool || isString {
i := v // type of i is type of x (interface{})
printString("type is bool or string")
} else {
i := v // type of i is type of x (interface{})
printString("don't know the type")
}
}
型パラメータ または ジェネリック型 は、ケース内の型として使用できます。インスタンス化 の際にその型がスイッチ内の他のエントリを重複させる場合、最初に一致するケースが選択されます。
func f[P any](x any) int {
switch x.(type) {
case P:
return 0
case string:
return 1
case []P:
return 2
case []byte:
return 3
default:
return 4
}
}
var v1 = f[string]("foo") // v1 == 0
var v2 = f[byte]([]byte{}) // v2 == 2
型スイッチガードの前に単純な文が置かれることがあり、これはガードが評価される前に実行されます。
“fallthrough” 文は型スイッチでは許可されていません。
For statements
“for” 文は、ブロックの繰り返し実行を指定します。3つの形式があります:反復は単一の条件、”for” 句、または “range” 句によって制御される場合があります。
= "for" [ | | ] .
= .
For statements with single condition
最も単純な形式では、”for” 文はブール条件が真である限りブロックの繰り返し実行を指定します。条件は各反復の前に評価されます。条件が欠落している場合、それはブール値 true
に相当します。
for a < b {
a *= 2
}
For statements with for clause
“for” 文は ForClause によっても制御されますが、さらに init と post 文を指定することができます。これには、代入、インクリメント、またはデクリメント文が含まれます。init 文は 短い変数宣言 である場合がありますが、post 文はそうではありません。
= [ ] ";" [ ] ";" [ ] .
= .
= .
for i := 0; i < 10; i++ {
f(i)
}
非空の場合、init 文は最初の反復の条件を評価する前に1回実行されます。post 文はブロックの各実行後に実行されます(ブロックが実行された場合のみ)。ForClause の任意の要素は空であってもよいですが、セミコロン は条件が1つだけの場合を除いて必要です。条件が欠落している場合、それはブール値 true
に相当します。
for cond { S() } is the same as for ; cond ; { S() }
for { S() } is the same as for true { S() }
各反復には独自の宣言された変数(または変数)があり、[Go 1.22]。最初の反復で使用される変数は init 文によって宣言されます。各後続の反復で使用される変数は、post 文を実行する前に暗黙的に宣言され、前の反復の変数のその時点での値に初期化されます。
var を印刷します。 []func()
for i := 0; i < 5; i++ {
prints = append(prints, func() { println(i) })
i++
}
for _, p := range prints {
p()
}
prints
1
3
5
[Go 1.22] の前は、反復は1セットの変数を共有し、独自の変数を持っていませんでした。その場合、上記の例は
6
6
6
For statements with range clause
“for” 文は “range” 句を持つ場合、配列、スライス、文字列、またはマップのすべてのエントリ、チャネルで受信した値、ゼロから上限までの整数値 [Go 1.22]、またはイテレータ関数の yield 関数に渡された値 [Go 1.23] を反復します。各エントリに対して、反復値 を対応する 反復変数 に割り当て、次にブロックを実行します。
= [ "=" | ":=" ] "range" .
“range” 句の右側の式は range expression と呼ばれ、その コア型 は配列、配列へのポインタ、スライス、文字列、マップ、受信操作 を許可するチャネル、整数、または特定のシグネチャを持つ関数でなければなりません(以下を参照)。代入と同様に、左側に存在する場合、オペランドは アドレス可能 であるか、マップインデックス式でなければなりません。これらは反復変数を示します。範囲式が関数である場合、最大の反復変数の数は関数のシグネチャに依存します。範囲式がチャネルまたは整数である場合、最大1つの反復変数が許可されます。それ以外の場合、最大2つまで存在できます。最後の反復変数が ブランク識別子 である場合、範囲句はその識別子なしの同じ句に相当します。
範囲式 x
はループを開始する前に評価されます。ただし、1つの反復変数が存在し、x
または len(x)
が 定数 である場合、範囲式は評価されません。
左側の関数呼び出しは、各反復ごとに1回評価されます。各反復に対して、反復変数が存在する場合、反復値は次のように生成されます:
Range expression 1st value 2nd value
array or slice a [n]E, *[n]E, or []E index i int a[i] E
string s string type index i int see below rune
map m map[K]V key k K m[k] V
channel c chan E, <-chan E element e E
integer value n integer type, or untyped int value i see below
function, 0 values f func(func() bool)
function, 1 value f func(func(V) bool) value v V
function, 2 values f func(func(K, V) bool) key k K v V
- 1. 配列、配列へのポインタ、またはスライス値
a
の場合、インデックス反復値は増加順に生成され、要素インデックス0から始まります。反復変数が最大1つ存在する場合、範囲ループは0からlen(a)-1
までの反復値を生成し、配列やスライス自体にはインデックスを付けません。nil
スライスの場合、反復の数は0です。 - 2. 文字列値の場合、”range” 句はバイトインデックス0から始まる文字列内のUnicodeコードポイントを反復します。連続する反復では、インデックス値は文字列内の連続するUTF-8エンコードされたコードポイントの最初のバイトのインデックスとなり、2番目の値は型
rune
で、対応するコードポイントの値となります。反復が無効なUTF-8シーケンスに遭遇した場合、2番目の値は0xFFFD
、Unicode置換文字となり、次の反復では文字列内の1バイトが進みます。 - 3. マップに対する反復順序は指定されておらず、1回の反復から次の反復まで同じであることは保証されていません。まだ到達していないマップエントリが反復中に削除された場合、対応する反復値は生成されません。反復中にマップエントリが作成された場合、そのエントリは反復中に生成されるか、スキップされる可能性があります。選択は、作成された各エントリに対して異なる場合があり、1回の反復から次の反復まで異なる場合があります。マップが
nil
の場合、反復の数は0です。 - 4. チャネルの場合、生成される反復値は、チャネルで送信された連続する値であり、チャネルが 閉じられる まで続きます。チャネルが
nil
の場合、範囲式は永遠にブロックします。 - 5. 整数値
n
の場合、n
が 整数型 または未型付 整数定数 である場合、反復値0からn-1
までが増加順に生成されます。n
が整数型である場合、反復値はその型を持ちます。それ以外の場合、n
の型は、反復変数に割り当てられたかのように決定されます。具体的には、反復変数が既存の場合、反復値の型は反復変数の型であり、整数型でなければなりません。それ以外の場合、反復変数が “range” 句によって宣言されているか、存在しない場合、反復値の型はn
の デフォルト型 です。n
が0以下の場合、ループは反復を実行しません。 6. 関数
f
の場合、反復は新しく合成されたyield
関数を引数としてf
を呼び出すことによって進行します。yield
がf
が返る前に呼び出されると、yield
への引数が1回ループ本体を実行するための反復値になります。各連続するループ反復の後、yield
はtrueを返し、ループを続けるために再度呼び出される可能性があります。ループ本体が終了しない限り、”range” 句はこの方法で各yield
呼び出しに対して反復値を生成し続け、f
が返るまで続きます。ループ本体が終了した場合(たとえば、break
文によって)、yield
はfalseを返し、再度呼び出されるべきではありません。反復変数は、短い変数宣言 の形式を使用して “range” 句によって宣言される場合があります(
:=
)。この場合、彼らの スコープ は “for” 文のブロックであり、各反復には独自の新しい変数があります [Go 1.22](ForClause を持つ “for” 文も参照)。変数はそれぞれの反復値の型を持ちます。反復変数が “range” 句によって明示的に宣言されていない場合、既存でなければなりません。この場合、反復値は 代入文 のようにそれぞれの変数に割り当てられます。
var testdata *struct {
a *[7]int
}
for i, _ := range testdata.a {
// testdata.a is never evaluated; len(testdata.a) is constant
// i ranges from 0 to 6
f(i)
}
var a [10]string
for i, s := range a {
// type of i is int
// type of s is string
// s == a[i]
g(i, s)
}
var key string
var val interface{} // element type of m is assignable to val
m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
for key, val = range m {
h(key, val)
}
// key == last map key encountered in iteration
// val == map[key]
var ch chan Work = producer()
for w := range ch {
doWork(w)
}
// empty a channel
for range ch {}
// call f(0), f(1), ... f(9)
for i := range 10 {
// type of i is int (default type for untyped constant 10)
f(i)
}
// invalid: 256 cannot be assigned to uint8
var u uint8
for u = range 256 {
}
// invalid: 1e3 is a floating-point constant
for range 1e3 {
}
// fibo generates the Fibonacci sequence
fibo := func(yield func(x int) bool) {
f0, f1 := 0, 1
for yield(f0) {
f0, f1 = f1, f0+f1
}
}
// print the Fibonacci numbers below 1000:
for x := range fibo {
if x >= 1000 {
break
}
fmt.Printf("%d ", x)
}
// output: 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
// iteration support for a recursive tree data structure
type Tree[K cmp.Ordered, V any] struct {
left, right *Tree[K, V]
key K
value V
}
func (t *Tree[K, V]) walk(yield func(key K, val V) bool) bool {
return t == nil || t.left.walk(yield) && yield(t.key, t.value) && t.right.walk(yield)
}
func (t *Tree[K, V]) Walk(yield func(key K, val V) bool) {
t.walk(yield)
}
// walk tree t in-order
var t Tree[string, int]
for k, v := range t.Walk {
// process k, v
}
Go statements
“go” 文は、同じアドレス空間内で独立した同時制御スレッド、または goroutine として関数呼び出しの実行を開始します。
= "go" .
式は関数またはメソッド呼び出しでなければならず、括弧で囲むことはできません。組み込み関数の呼び出しは、式文 と同様に制限されています。
関数値とパラメータは、呼び出し元の goroutine で 通常通り評価 されますが、通常の呼び出しとは異なり、プログラムの実行は呼び出された関数が完了するのを待ちません。代わりに、関数は新しい goroutine で独立して実行を開始します。関数が終了すると、その goroutine も終了します。関数に戻り値がある場合、それらは関数が完了するときに破棄されます。
go Server()
go func(ch chan<- bool) { for { sleep(10); ch <- true }} (c)
Select statements
“select” 文は、可能な 送信 または 受信 操作のセットの中からどれを進めるかを選択します。これは、すべてのケースが通信操作を参照する “switch” 文に似ています。
= "select" "{" { } "}" .
= ":" .
= "case" ( | ) | "default" .
= [ "=" | ":=" ] .
= .
RecvStmt を持つケースは、RecvExpr の結果を1つまたは2つの変数に割り当てることができ、これらは 短い変数宣言 を使用して宣言できます。RecvExpr は(括弧で囲まれている可能性のある)受信操作でなければなりません。デフォルトケースは最大1つまで存在でき、ケースのリストのどこにでも現れることができます。
“select” 文の実行は、いくつかのステップで進行します:
- 1. 文のすべてのケースについて、受信操作のチャネルオペランドと送信文のチャネルおよび右辺式が、”select” 文に入るときに正確に1回評価されます。結果は、受信または送信するチャネルのセットと、送信する対応する値のセットです。その評価における副作用は、どの(もしあれば)通信操作が選択されるかに関係なく発生します。短い変数宣言または代入を持つ RecvStmt の左辺の式はまだ評価されていません。
- 2. 1つ以上の通信が進めることができる場合、進めることができる単一のものが均一な擬似ランダム選択によって選ばれます。そうでない場合、デフォルトケースがある場合、そのケースが選ばれます。デフォルトケースがない場合、”select” 文は、少なくとも1つの通信が進めることができるまでブロックします。
- 3. 選択されたケースがデフォルトケースでない限り、対応する通信操作が実行されます。
- 4. 選択されたケースが短い変数宣言または代入を持つ RecvStmt の場合、左辺の式が評価され、受信した値(または値)が割り当てられます。
5. 選択されたケースの文リストが実行されます。
nil
チャネルでの通信は決して進まないため、nil
チャネルのみを持つ select は永遠にブロックします。
var a []int
var c, c1, c2, c3, c4 chan int
var i1, i2 int
select {
case i1 = <-c1:
print("received ", i1, " from c1\n")
case c2 <- i2:
print("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
print("received ", i3, " from c3\n")
} else {
print("c3 is closed\n")
}
case a[f()] = <-c4:
// same as:
// case t := <-c4
// a[f()] = t
default:
print("no communication\n")
}
for { // send random sequence of bits to c
select {
case c <- 0: // note: no statement, no fallthrough, no folding of cases
case c <- 1:
}
}
select {} // block forever
Return statements
“return” 文は、関数 F
の実行を終了し、オプションで1つ以上の結果値を提供します。F
によって 遅延 された関数は、F
が呼び出し元に戻る前に実行されます。
= "return" [ ] .
結果型のない関数では、”return” 文は結果値を指定してはなりません。
func noResult() {
return
}
結果型を持つ関数から値を返す方法は3つあります:
1. 戻り値または値は、”return” 文に明示的にリストされることができます。各式は単一値でなければならず、関数の結果型の対応する要素に 代入可能 でなければなりません。
func simpleF() int {
return 2
}
func complexF1() (re float64, im float64) {
return -7.0, -4.0
}
- 2. “return” 文の式リストは、複数の値を持つ関数への単一の呼び出しである場合があります。その効果は、関数から返される各値がそれぞれの値の型を持つ一時変数に割り当てられ、その後、これらの変数をリストする “return” 文が続くというものです。この時点で、前のケースのルールが適用されます。
func complexF2() (re float64, im float64) {
return complexF1()
}
3. 式リストは、関数の結果型がその 結果パラメータ に名前を指定している場合は空であってもかまいません。結果パラメータは通常のローカル変数として機能し、関数は必要に応じてそれらに値を割り当てることができます。”return” 文はこれらの変数の値を返します。
func complexF3() (re float64, im float64) {
re = 7.0
im = 4.0
return
}
func (devnull) Write(p []byte) (n int, _ error) {
n = len(p)
return
}
宣言方法に関係なく、すべての結果値は関数へのエントリ時にその型の ゼロ値 に初期化されます。結果を指定する “return” 文は、遅延関数が実行される前に結果パラメータを設定します。
実装制限:異なるエンティティ(定数、型、または変数)が戻りの場所で スコープ にある場合、コンパイラは “return” 文で空の式リストを許可しない場合があります。
func f(n int) (res int, err error) {
if _, err := f(n-1); err != nil {
return // invalid return statement: err is shadowed
}
return
}
Break statements
“break” 文は、同じ関数内の最も内側の “for”、 “switch”、または “select” 文の実行を終了します。
= "break" [ ] .
ラベルがある場合、それは外側の “for”、”switch”、または “select” 文のものでなければならず、それが終了する実行のものです。
OuterLoop:
for i = 0; i < n; i++ {
for j = 0; j < m; j++ {
switch a[i][j] {
case nil:
state = Error
break OuterLoop
case item:
state = Found
break OuterLoop
}
}
}
Continue statements
“continue” 文は、最も内側の外側の “for” ループ の次の反復を開始し、ループブロックの終わりに制御を進めます。”for” ループは同じ関数内でなければなりません。
= "continue" [ ] .
ラベルがある場合、それは外側の “for” 文のものでなければならず、それが進む実行のものです。
RowLoop:
for y, row := range rows {
for x, data := range row {
if data == endOfRow {
continue RowLoop
}
row[x] = data + bias(x, y)
}
}
Goto statements
“goto” 文は、同じ関数内の対応するラベルを持つ文に制御を移します。
= "goto" .
goto Error
“goto” 文を実行することは、goto のポイントでスコープにない変数を スコープ に持ち込むことを引き起こしてはなりません。たとえば、この例:
goto L // BAD
v := 3
L:
は、ラベル L
へのジャンプが v
の作成をスキップするため、誤りです。
“goto” 文が ブロック の外にある場合、そのブロック内のラベルにジャンプすることはできません。たとえば、この例:
if n%2 == 1 {
goto L1
}
for n > 0 {
f()
n--
L1:
f()
n--
}
は、ラベル L1
が “for” 文のブロック内にあるため、goto
がないため、誤りです。
Fallthrough statements
“fallthrough” 文は、式 “switch” 文の次のケース句の最初の文に制御を移します。このような句の最後の非空文としてのみ使用できます。
= "fallthrough" .
Defer statements
“defer” 文は、周囲の関数が戻る瞬間に実行が遅延される関数を呼び出します。これは、周囲の関数が return 文 を実行した場合、関数本体の終わりに達した場合、または対応する goroutine が パニック に陥った場合です。
= "defer" .
式は関数またはメソッド呼び出しでなければならず、括弧で囲むことはできません。組み込み関数の呼び出しは、式文 と同様に制限されています。
“defer” 文が実行されるたびに、関数値と呼び出しのパラメータは 通常通り評価 され、新たに保存されますが、実際の関数は呼び出されません。代わりに、遅延された関数は、周囲の関数が戻る直前に、遅延された逆順で実行されます。つまり、周囲の関数が明示的な return 文 を通じて戻る場合、遅延された関数はその return 文によって設定された結果パラメータの後に実行されますが、関数が呼び出し元に戻る前に実行されます。遅延された関数値が nil
に評価されると、関数が呼び出されるときに パニック が発生し、”defer” 文が実行されるときではありません。
たとえば、遅延された関数が 関数リテラル であり、周囲の関数がスコープ内にある 名前付き結果パラメータ を持っている場合、遅延された関数はそれらの結果パラメータにアクセスして変更することができます。遅延された関数に戻り値がある場合、それらは関数が完了するときに破棄されます。(パニックの処理 に関するセクションも参照)。
lock(l)
defer unlock(l) // unlocking happens before surrounding function returns
// prints 3 2 1 0 before surrounding function returns
for i := 0; i <= 3; i++ {
defer fmt.Print(i)
}
// f returns 42
func f() (result int) {
defer func() {
// result is accessed after it was set to 6 by the return statement
result *= 7
}()
return 6
}
Built-in functions
組み込み関数は 事前に宣言された ものです。これらは他の関数と同様に呼び出されますが、そのうちのいくつかは最初の引数として式の代わりに型を受け入れます。
組み込み関数には標準のGo型がないため、呼び出し式 にのみ現れることができ、関数値として使用することはできません。
Appending to and copying slices
組み込み関数 append
と copy
は、一般的なスライス操作を支援します。両方の関数において、結果は引数によって参照されるメモリが重複しているかどうかに依存しません。
可変長引数 関数 append
は、スライス s
にゼロまたはそれ以上の値 x
を追加し、s
と同じ型の結果スライスを返します。s
の コア型 は、[]E
型のスライスでなければなりません。値 x
は ...E
型のパラメータに渡され、対応する パラメータ渡しルール が適用されます。特別なケースとして、s
のコア型が []byte
である場合、append
はコア型 bytestring
を持つ2番目の引数を受け入れ、...
の後に続きます。この形式は、バイトスライスまたは文字列のバイトを追加します。
append(s S, x ...E) S // core type of S is []E
s
の容量が追加の値を収容するのに十分でない場合、append
は、既存のスライス要素と追加の値の両方に適合する新しい十分に大きな基盤配列を 割り当て します。そうでない場合、append
は基盤配列を再利用します。
s0 := []int{0, 0}
s1 := append(s0, 2) // append a single element s1 is []int{0, 0, 2}
s2 := append(s1, 3, 5, 7) // append multiple elements s2 is []int{0, 0, 2, 3, 5, 7}
s3 := append(s2, s0...) // append a slice s3 is []int{0, 0, 2, 3, 5, 7, 0, 0}
s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 is []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
var t []interface{}
t = append(t, 42, 3.1415, "foo") // t is []interface{}{42, 3.1415, "foo"}
var b []byte
b = append(b, "bar"...) // append string contents b is []byte{'b', 'a', 'r' }
関数 copy
は、ソース src
から宛先 dst
へスライス要素をコピーし、コピーされた要素の数を返します。両方の引数の コア型 は、同一 の要素型を持つスライスでなければなりません。コピーされた要素の数は len(src)
と len(dst)
の最小値です。特別なケースとして、宛先のコア型が []byte
である場合、copy
はコア型 bytestring
を持つソース引数を受け入れます。この形式は、バイトスライスまたは文字列のバイトをバイトスライスにコピーします。
copy(dst, src []T) int
copy(dst []byte, src string) int
例:
var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
var s = make([]int, 6)
var b = make([]byte, 5)
n1 := copy(s, a[0:]) // n1 == 6, s is []int{0, 1, 2, 3, 4, 5}
n2 := copy(s, s[2:]) // n2 == 4, s is []int{2, 3, 4, 5, 4, 5}
n3 := copy(b, "Hello, World!") // n3 == 5, b is []byte("Hello")
Clear
組み込み関数 clear
は、マップ、スライス、または 型パラメータ 型の引数を取り、すべての要素を削除またはゼロにします [Go 1.21]。
Call Argument type Result
clear(m) map[K]T deletes all entries, resulting in an
empty map (len(m) == 0)
clear(s) []T sets all elements up to the length of
s to the zero value of T
clear(t) type parameter see below
clear
への引数の型が 型パラメータ である場合、その型セット内のすべての型はマップまたはスライスでなければならず、clear
は実際の型引数に対応する操作を実行します。
マップまたはスライスが nil
の場合、clear
はノーオペレーションです。
Close
引数 ch
の コア型 が チャネル である場合、組み込み関数 close
は、チャネルにもう値が送信されないことを記録します。ch
が受信専用チャネルである場合、エラーです。閉じられたチャネルに送信することや、閉じたチャネルを閉じることは ランタイムパニック を引き起こします。nil チャネルを閉じることも ランタイムパニック を引き起こします。close
を呼び出した後、以前に送信された値が受信されると、受信操作はブロックせずにチャネルの型のゼロ値を返します。複数の値を持つ 受信操作 は、受信した値とチャネルが閉じているかどうかの指示を返します。
複素数の操作
三つの関数が複素数を組み立てたり分解したりします。組み込み関数 complex
は浮動小数点の実部と虚部から複素値を構築し、real
と imag
は複素値の実部と虚部を抽出します。
complex(realPart, imaginaryPart floatT) complexT
real(complexT) floatT
imag(complexT) floatT
引数と戻り値の型は対応しています。complex
の場合、二つの引数は同じ 浮動小数点型 でなければならず、戻り値の型は対応する浮動小数点成分を持つ 複素型 です:complex64
は float32
引数用、complex128
は float64
引数用です。引数の一方が型未定義の定数に評価される場合、最初に暗黙的に 変換 され、他方の引数の型になります。両方の引数が型未定義の定数に評価される場合、それらは非複素数であるか、虚部がゼロでなければならず、関数の戻り値は型未定義の複素定数になります。
real
と imag
の場合、引数は複素型でなければならず、戻り値の型は対応する浮動小数点型です:float32
は complex64
引数用、float64
は complex128
引数用です。引数が型未定義の定数に評価される場合、それは数値でなければならず、関数の戻り値は型未定義の浮動小数点定数になります。
real
と imag
関数は一緒に complex
の逆を形成するため、複素型 Z
の値 z
に対して z == Z(complex(real(z), imag(z)))
となります。
これらの関数のオペランドがすべて定数である場合、戻り値は定数です。
var a = complex(2, -2) // complex128
const b = complex(1.0, -1.4) // untyped complex constant 1 - 1.4i
x := float32(math.Cos(math.Pi/2)) // float32
var c64 = complex(5, -x) // complex64
var s int = complex(1, 0) // untyped complex constant 1 + 0i can be converted to int
_ = complex(1, 2<<s) // illegal: 2 assumes floating-point type, cannot shift
var rl = real(c64) // float32
var im = imag(a) // float64
const c = imag(b) // untyped constant -1.4
_ = imag(3 << s) // illegal: 3 assumes complex type, cannot shift
マップ要素の削除
組み込み関数 delete
は、マップ m
からキー k
を持つ要素を削除します。値 k
は m
のキー型に 代入可能 でなければなりません。
delete(m, k) // remove element m[k] from map m
m
の型が 型パラメータ である場合、その型セット内のすべての型はマップでなければならず、すべて同一のキー型を持たなければなりません。
マップ m
が nil
であるか、要素 m[k]
が存在しない場合、delete
は何もしません。
長さと容量
組み込み関数 len
と cap
は、さまざまな型の引数を取り、型 int
の結果を返します。実装は、結果が常に int
に収まることを保証します。
Call Argument type Result
len(s) string type string length in bytes
[n]T, *[n]T array length (== n)
[]T slice length
map[K]T map length (number of defined keys)
chan T number of elements queued in channel buffer
type parameter see below
cap(s) [n]T, *[n]T array length (== n)
[]T slice capacity
chan T channel buffer capacity
type parameter see below
引数の型が 型パラメータ P
である場合、呼び出し len(e)
(または cap(e)
) は P
の型セット内の各型に対して有効でなければなりません。結果は、P
が インスタンス化 された型引数に対応する引数の長さ(または容量)です。
スライスの容量は、基になる配列に割り当てられた要素の数です。常に次の関係が成り立ちます:
0 <= len(s) <= cap(s)
nil
スライス、マップ、またはチャネルの長さは 0 です。nil
スライスまたはチャネルの容量は 0 です。
表現 len(s)
は、s
が文字列定数である場合 定数 です。len(s)
と cap(s)
の表現は、s
の型が配列または配列へのポインタであり、s
の表現が チャネル受信 または(非定数)関数呼び出し を含まない場合に定数です。この場合、s
は評価されません。そうでない場合、len
と cap
の呼び出しは定数ではなく、s
が評価されます。
const (
c1 = imag(2i) // imag(2i) = 2.0 is a constant
c2 = len([10]float64{2}) // [10]float64{2} contains no function calls
c3 = len([10]float64{c1}) // [10]float64{c1} contains no function calls
c4 = len([10]float64{imag(2i)}) // imag(2i) is a constant and no function call is issued
c5 = len([10]float64{imag(z)}) // invalid: imag(z) is a (non-constant) function call
)
var z complex128
スライス、マップ、チャネルの作成
組み込み関数 make
は、型 T
を取り、オプションで型特有の式のリストが続きます。T
の コア型 はスライス、マップ、またはチャネルでなければなりません。型 T
の値を返します(*T
ではありません)。メモリは、初期値 のセクションで説明されているように初期化されます。
Call Core type Result
make(T, n) slice slice of type T with length n and capacity n
make(T, n, m) slice slice of type T with length n and capacity m
make(T) map map of type T
make(T, n) map map of type T with initial space for approximately n elements
make(T) channel unbuffered channel of type T
make(T, n) channel buffered channel of type T, buffer size n
各サイズ引数 n
と m
は、整数型 でなければならず、整数型のみを含む 型セット を持つか、型未定義の 定数 でなければなりません。定数サイズ引数は非負であり、型 int
の値で 表現可能 でなければなりません。型未定義の定数である場合、型 int
が与えられます。n
と m
の両方が提供され、かつ定数である場合、n
は m
より大きくてはなりません。スライスとチャネルの場合、n
が負であるか、実行時に m
より大きい場合、実行時パニック が発生します。
s := make([]int, 10, 100) // slice with len(s) == 10, cap(s) == 100
s := make([]int, 1e3) // slice with len(s) == cap(s) == 1000
s := make([]int, 1<<63) // illegal: len(s) is not representable by a value of type int
s := make([]int, 10, 0) // illegal: len(s) > cap(s)
c := make(chan int, 10) // channel with a buffer size of 10
m := make(map[string]int, 100) // map with initial space for approximately 100 elements
マップ型とサイズヒント n
で make
を呼び出すと、n
マップ要素を保持するための初期スペースを持つマップが作成されます。正確な動作は実装依存です。
最小値と最大値
組み込み関数 min
と max
は、順序型 の固定数の引数の最小値または最大値を計算します。少なくとも一つの引数が必要です [Go 1.21]。
同じ型のルールが 演算子 に適用されます: 順序型 引数 x
と y
に対して、min(x, y)
は x + y
が有効であれば有効であり、min(x, y)
の型は x + y
の型です(max
に対しても同様です)。すべての引数が定数である場合、結果は定数です。
var x, y int
m := min(x) // m == x
m := min(x, y) // m is the smaller of x and y
m := max(x, y, 10) // m is the larger of x and y but at least 10
c := max(1, 2.0, 10) // c == 10.0 (floating-point kind)
f := max(0, float32(x)) // type of f is float32
var s []string
_ = min(s...) // invalid: slice arguments are not permitted
t := max("", "foo", "bar") // t == "foo" (string kind)
数値引数の場合、すべての NaN が等しいと仮定すると、min
と max
は可換であり、結合的です:
min(x, y) == min(y, x)
min(x, y, z) == min(min(x, y), z) == min(x, min(y, z))
浮動小数点引数の場合、負のゼロ、NaN、および無限大に対して次のルールが適用されます:
x y min(x, y) max(x, y)
-0.0 0.0 -0.0 0.0 // negative zero is smaller than (non-negative) zero
-Inf y -Inf y // negative infinity is smaller than any other number
+Inf y y +Inf // positive infinity is larger than any other number
NaN y NaN NaN // if any argument is a NaN, the result is a NaN
文字列引数の場合、min
の結果は、最小(または max
の場合は最大)値を持つ最初の引数であり、字句的にバイト単位で比較されます:
min(x, y) == if x <= y then x else y
min(x, y, z) == min(min(x, y), z)
メモリの割り当て
組み込み関数 new
は、型 T
を取り、その型の 変数 のストレージを実行時に割り当て、型 *T
の値を返します ポインティング します。変数は、初期値 のセクションで説明されているように初期化されます。
new(T)
例えば
type S struct { a int; b float64 }
new(S)
は、型 S
の変数のためのストレージを割り当て、それを初期化し(a=0
、b=0.0
)、その位置のアドレスを含む型 *S
の値を返します。
パニックの処理
二つの組み込み関数、panic
と recover
は、実行時パニック とプログラム定義のエラー条件の報告と処理を支援します。
func panic(interface{})
func recover() interface{}
関数 F
を実行中に、panic
への明示的な呼び出しまたは 実行時パニック が F
の実行を終了させます。F
によって 遅延 された関数は通常通り実行されます。次に、F
の呼び出し元によって実行される遅延関数が実行され、実行中のゴルーチンの最上位関数によって遅延された関数まで続きます。その時点で、プログラムは終了し、エラー条件が報告され、panic
への引数の値が含まれます。この終了シーケンスは パニック と呼ばれます。
panic(42)
panic("unreachable")
panic(Error("cannot parse"))
recover
関数は、パニック状態のゴルーチンの動作を管理するためのプログラムを可能にします。関数 G
が D
を遅延させ、recover
を呼び出す場合、同じゴルーチンで G
が実行されているときにパニックが発生します。遅延関数の実行が D
に達すると、D
の recover
への呼び出しの戻り値は panic
への呼び出しに渡された値になります。D
が通常に戻る場合、新しい panic
を開始せずに、パニックシーケンスは停止します。その場合、G
と panic
への呼び出しの間に呼び出された関数の状態は破棄され、通常の実行が再開されます。G
によって D
の前に遅延された関数が実行され、その後 G
の実行が呼び出し元に戻ることで終了します。
recover
の戻り値は、ゴルーチンがパニック状態でない場合、または recover
が遅延関数によって直接呼び出されなかった場合 nil
です。逆に、ゴルーチンがパニック状態であり、recover
が遅延関数によって直接呼び出された場合、recover
の戻り値は nil
でないことが保証されます。これを確実にするために、panic
を nil
インターフェース値(または型未定義の nil
)で呼び出すと、実行時パニック が発生します。
下の例の protect
関数は、関数引数 g
を呼び出し、g
によって引き起こされた実行時パニックから呼び出し元を保護します。
func protect(g func()) {
defer func() {
log.Println("done") // Println executes normally even if there is a panic
if x := recover(); x != nil {
log.Printf("run time panic: %v", x)
}
}()
log.Println("start")
g()
}
ブートストラップ
現在の実装は、ブートストラップ中に役立ついくつかの組み込み関数を提供します。これらの関数は完全性のために文書化されていますが、言語に残ることは保証されていません。結果を返しません。
Function Behavior
print prints all arguments; formatting of arguments is implementation-specific
println like print but prints spaces between arguments and a newline at the end
実装制限:print
と println
は任意の引数型を受け入れる必要はありませんが、ブール、数値、および文字列 型 の印刷はサポートされなければなりません。
パッケージ
Go プログラムは パッケージ をリンクすることによって構成されます。パッケージは、定数、型、変数、および関数を宣言する一つ以上のソースファイルから構成され、同じパッケージのすべてのファイルでアクセス可能です。これらの要素は エクスポート され、別のパッケージで使用されることがあります。
ソースファイルの構成
各ソースファイルは、所属するパッケージを定義するパッケージ句で始まり、使用したいパッケージの内容を宣言する可能性のある空のインポート宣言のセットが続き、関数、型、変数、および定数の宣言の可能性のある空のセットが続きます。
= ";" { ";" } { ";" } .
パッケージ句
パッケージ句は各ソースファイルの最初に始まり、そのファイルが属するパッケージを定義します。
= "package" .
= .
パッケージ名は ブランク識別子 であってはなりません。
package math
同じパッケージ名を共有するファイルのセットがパッケージの実装を形成します。実装は、パッケージのすべてのソースファイルが同じディレクトリに存在することを要求する場合があります。
インポート宣言
インポート宣言は、宣言を含むソースファイルが インポートされた パッケージの機能に依存していることを示し、そのパッケージの エクスポートされた 識別子へのアクセスを可能にします。インポートは、アクセスに使用される識別子(パッケージ名)と、インポートされるパッケージを指定するインポートパスを名前付けします。
= "import" ( | "(" { ";" } ")" ) .
= [ "." | ] .
= .
パッケージ名は、インポート元のソースファイル内でそのパッケージのエクスポートされた識別子にアクセスするための 修飾識別子 に使用されます。これは ファイルブロック で宣言されます。パッケージ名が省略された場合、インポートされたパッケージの パッケージ句 で指定された識別子がデフォルトになります。名前の代わりに明示的なピリオド(.
)が表示される場合、そのパッケージの パッケージブロック で宣言されたすべてのエクスポートされた識別子が、インポート元のソースファイルのファイルブロックで宣言され、修飾子なしでアクセスされなければなりません。
インポートパスの解釈は実装依存ですが、通常はコンパイルされたパッケージのフルファイル名の部分文字列であり、インストールされたパッケージのリポジトリに対して相対的である場合があります。
実装制限:コンパイラは、Unicode の L、M、N、P、S 一般カテゴリに属する文字のみを使用して非空の文字列にインポートパスを制限する場合があり、!"#$%&'()*,:;<=>?[\]^`{|}
および Unicode 置換文字 U+FFFD を除外する場合があります。
コンパイルされたパッケージがパッケージ句 package math
を含み、関数 Sin
をエクスポートし、コンパイルされたパッケージが "lib/math"
で識別されるファイルにインストールされていると仮定します。この表は、さまざまなインポート宣言の後にパッケージを Sin
にアクセスする方法を示しています。
Import declaration Local name of Sin
import "lib/math" math.Sin
import m "lib/math" m.Sin
import . "lib/math" Sin
インポート宣言は、インポート元パッケージとインポートされたパッケージの間の依存関係を宣言します。パッケージが自分自身を直接または間接的にインポートすることは違法であり、エクスポートされた識別子のいずれかを参照せずにパッケージを直接インポートすることも違法です。副作用(初期化)のためだけにパッケージをインポートするには、ブランク 識別子を明示的なパッケージ名として使用します:
import _ "lib/math"
例のパッケージ
ここに、同時にプライム篩を実装する完全な Go パッケージがあります。
package main
import "fmt"
// Send the sequence 2, 3, 4, … to channel 'ch'.
func generate(ch chan<- int) {
for i := 2; ; i++ {
ch <- i // Send 'i' to channel 'ch'.
}
}
// Copy the values from channel 'src' to channel 'dst',
// removing those divisible by 'prime'.
func filter(src <-chan int, dst chan<- int, prime int) {
for i := range src { // Loop over values received from 'src'.
if i%prime != 0 {
dst <- i // Send 'i' to channel 'dst'.
}
}
}
// The prime sieve: Daisy-chain filter processes together.
func sieve() {
ch := make(chan int) // Create a new channel.
go generate(ch) // Start generate() as a subprocess.
for {
prime := <-ch
fmt.Print(prime, "\n")
ch1 := make(chan int)
go filter(ch, ch1, prime)
ch = ch1
}
}
func main() {
sieve()
}
プログラムの初期化と実行
ゼロ値
変数のためにストレージが割り当てられるとき、宣言を通じてまたは new
の呼び出しを通じて、または新しい値が作成されるとき、合成リテラルまたは make
の呼び出しを通じて、明示的な初期化が提供されない場合、変数または値にはデフォルト値が与えられます。そのような変数または値の各要素は、その型の ゼロ値 に設定されます:ブール値には false
、数値型には 0
、文字列には ""
、ポインタ、関数、インターフェース、スライス、チャネル、およびマップには nil
です。この初期化は再帰的に行われるため、例えば構造体の配列の各要素は、値が指定されていない場合にフィールドがゼロに設定されます。
これら二つの単純な宣言は等価です:
var i int
var i int = 0
type T struct { i int; f float64; next *T }
t := new(T)
`````` の後、次のことが成り立ちます:
``````bash
t.i == 0
t.f == 0.0
t.next == nil
var t T
`````` の後も同様です。
<a name="Package_initialization"></a>
### パッケージの初期化
パッケージ内では、パッケージレベルの変数の初期化は段階的に進行し、各ステップは初期化されていない変数に依存しない最も早い *宣言順序* の変数を選択します。
より正確には、パッケージレベルの変数は、まだ初期化されておらず、[初期化式](#Variable_declarations) がないか、初期化式が初期化されていない変数に依存しない場合、*初期化の準備ができている* と見なされます。初期化は、初期化の準備ができている最も早いパッケージレベルの変数を繰り返し初期化することによって進行し、初期化の準備ができている変数がなくなるまで続きます。
このプロセスが終了したときにまだ初期化されていない変数がある場合、それらの変数は一つ以上の初期化サイクルの一部であり、プログラムは無効です。
左辺に複数の変数があり、右辺に単一の(多値)式で初期化される場合、すべての変数は一緒に初期化されます:左辺のいずれかの変数が初期化されると、すべての変数が同じステップで初期化されます。
``````bash
var x = a
var a, b = f() // a and b are initialized together, before x is initialized
パッケージの初期化の目的で、ブランク 変数は他の変数と同様に扱われます。
複数のファイルで宣言された変数の宣言順序は、ファイルがコンパイラに提示される順序によって決まります:最初のファイルで宣言された変数は、二番目のファイルで宣言された変数の前に宣言されます。再現可能な初期化動作を確保するために、ビルドシステムは同じパッケージに属する複数のファイルを、レキシカルファイル名の順序でコンパイラに提示することが推奨されます。
依存関係分析は、変数の実際の値ではなく、ソース内のそれらへのレキシカル 参照 のみに依存し、推移的に分析されます。例えば、変数 x
の初期化式が、変数 y
を参照する関数を参照している場合、x
は y
に依存します。具体的には:
- 変数または関数への参照は、その変数または関数を示す識別子です。
- メソッド
m
への参照は、t.m
の形の メソッド値 または メソッド式 であり、t
の (静的) 型がインターフェース型でなく、メソッドm
がt
の メソッドセット に含まれている場合です。結果として得られる関数値t.m
が呼び出されるかどうかは重要ではありません。 変数、関数、またはメソッド
x
は、y
という変数に依存します。x
の初期化式または本体(関数およびメソッドの場合)がy
またはy
に依存する関数またはメソッドを参照している場合です。例えば、次の宣言があるとします。
var (
a = c + b // == 9
b = f() // == 4
c = f() // == 5
d = 3 // == 5 after initialization has finished
)
func f() int {
d++
return d
}
初期化順序は d
、b
、c
、a
です。初期化式内の部分式の順序は無関係です:a = c + b
と a = b + c
は、この例で同じ初期化順序をもたらします。
依存関係分析はパッケージごとに行われ、現在のパッケージで宣言された変数、関数、および(非インターフェース)メソッドへの参照のみが考慮されます。他の隠れたデータ依存関係が変数間に存在する場合、それらの変数間の初期化順序は未指定です。
例えば、次の宣言があるとします。
var x = I(T{}).ab() // x has an undetected, hidden dependency on a and b
var _ = sideEffect() // unrelated to x, a, or b
var a = b
var b = 42
type I interface { ab() []int }
type T struct{}
func (T) ab() []int { return []int{a, b} }
変数 a
は b
の後に初期化されますが、x
が b
の前に初期化されるか、b
と a
の間に初期化されるか、a
の後に初期化されるか、したがって sideEffect()
が呼び出される瞬間(x
が初期化される前か後か)は指定されていません。
変数は、パッケージブロックで宣言された init
という名前の関数を使用して初期化することもできます。引数や結果パラメータはありません。
func init() { … }
このような関数は、単一のソースファイル内でも、パッケージごとに複数定義できます。パッケージブロック内では、init
識別子は init
関数を宣言するためにのみ使用できますが、識別子自体は 宣言されていません。したがって、init
関数はプログラムのどこからも参照できません。
パッケージ全体は、すべてのパッケージレベルの変数に初期値を割り当て、その後、ソース内で現れる順序で init
関数を呼び出すことによって初期化されます。複数のファイルであっても、コンパイラに提示される順序で初期化されます。
プログラムの初期化
完全なプログラムのパッケージは、段階的に、一度に一つのパッケージずつ初期化されます。パッケージにインポートがある場合、インポートされたパッケージは、パッケージ自体を初期化する前に初期化されます。複数のパッケージがパッケージをインポートする場合、インポートされたパッケージは一度だけ初期化されます。パッケージのインポートは、構造上、循環初期化依存関係が存在しないことを保証します。より正確には:
すべてのパッケージのリストがインポートパスでソートされている場合、各ステップで、すべてのインポートされたパッケージ(あれば)がすでに初期化されている最初の未初期化パッケージが 初期化 されます。このステップは、すべてのパッケージが初期化されるまで繰り返されます。
パッケージの初期化—変数の初期化と init
関数の呼び出し—は、単一のゴルーチンで、逐次的に、一度に一つのパッケージで行われます。init
関数は他のゴルーチンを起動することができますが、初期化コードと並行して実行されます。しかし、初期化は常に init
関数を順序付けます:前の関数が戻るまで次の関数は呼び出されません。
プログラムの実行
完全なプログラムは、メインパッケージ と呼ばれる単一のインポートされていないパッケージと、それがインポートするすべてのパッケージを再帰的にリンクすることによって作成されます。メインパッケージはパッケージ名 main
を持ち、引数を取らず、値を返さない関数 main
を宣言しなければなりません。
func main() { … }
プログラムの実行は、プログラムの初期化 を行い、その後、main
をメインパッケージ main
で呼び出すことから始まります。その関数の呼び出しが戻ると、プログラムは終了します。他の(非 main
)ゴルーチンが完了するのを待ちません。
エラー
事前に宣言された型 error
は次のように定義されます。
type error interface {
Error() string
}
これは、エラー条件を表すための従来のインターフェースであり、nil 値はエラーがないことを表します。例えば、ファイルからデータを読み取る関数は次のように定義されるかもしれません:
func Read(f *File, b []byte) (n int, err error)
実行時パニック
配列の範囲外をインデックスしようとするなどの実行エラーは、実装定義のインターフェース型 runtime.Error
の値を持つ組み込み関数 panic
の呼び出しに相当する 実行時パニック を引き起こします。その型は、事前に宣言されたインターフェース型 error
を満たします。異なる実行時エラー条件を表す正確なエラー値は未指定です。
package runtime
type Error interface {
error
// and perhaps other methods
}
システムの考慮事項
パッケージの安全性
組み込みパッケージ unsafe
は、コンパイラに知られており、インポートパス "unsafe"
を通じてアクセス可能で、型システムを侵害する操作を含む低レベルプログラミングのための機能を提供します。unsafe
を使用するパッケージは、型安全性のために手動で審査される必要があり、ポータブルでない可能性があります。このパッケージは次のインターフェースを提供します:
package unsafe
type ArbitraryType int // shorthand for an arbitrary Go type; it is not a real type
type Pointer *ArbitraryType
func Alignof(variable ArbitraryType) uintptr
func Offsetof(selector ArbitraryType) uintptr
func Sizeof(variable ArbitraryType) uintptr
type IntegerType int // shorthand for an integer type; it is not a real type
func Add(ptr Pointer, len IntegerType) Pointer
func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
func SliceData(slice []ArbitraryType) *ArbitraryType
func String(ptr *byte, len IntegerType) string
func StringData(str string) *byte
Pointer
は ポインタ型 ですが、Pointer
値は 逆参照 できない場合があります。任意のポインタまたは コア型 uintptr
の値は、コア型 Pointer
の型に 変換 でき、その逆も可能です。Pointer
と uintptr
の間の変換の効果は、実装に依存します。
var f float64
bits = *(*uint64)(unsafe.Pointer(&f))
type ptr unsafe.Pointer
bits = *(*uint64)(ptr(&f))
func f[P ~*B, B any](p P) uintptr {
return uintptr(unsafe.Pointer(p))
}
var p ptr = nil
関数 Alignof
と Sizeof
は、任意の型の式 x
を受け取り、それぞれ仮想変数 v
のアラインメントまたはサイズを、v
が var v = x
を介して宣言されたかのように返します。
関数 Offsetof
は、(括弧で囲まれた可能性のある) セレクタ s.f
を受け取り、s
または *s
によって示される構造体のフィールド f
を示し、構造体のアドレスに対するフィールドオフセットをバイト単位で返します。f
が 埋め込みフィールド の場合、ポインタの間接参照なしで構造体のフィールドを通じて到達可能でなければなりません。フィールド f
を持つ構造体 s
の場合:
uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f))
コンピュータアーキテクチャは、メモリアドレスが アラインメント されることを要求する場合があります。つまり、変数のアドレスが変数の型の アラインメント の倍数である必要があります。関数 Alignof
は、任意の型の変数を示す式を受け取り、その変数の (型の) アラインメントをバイト単位で返します。変数 x
の場合:
uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0
型 T
の (変数) は、T
が 型パラメータ の場合、または可変サイズの要素またはフィールドを含む配列または構造体型である場合に 可変サイズ を持ちます。そうでなければ、サイズは 定数 です。Alignof
、Offsetof
、および Sizeof
への呼び出しは、引数 (またはセレクタ式 s.f
の構造体 s
) が定数サイズの型である場合、型 uintptr
のコンパイル時 定数式 です。
関数 Add
は len
を ptr
に加算し、更新されたポインタ unsafe.Pointer(uintptr(ptr) + uintptr(len))
を返します [Go 1.17]。len
引数は 整数型 または型指定のない 定数 でなければなりません。型指定のない len
引数は、型 int
の値で 表現可能 でなければなりません; 型指定のない定数の場合、型 int
が与えられます。Pointer
の 有効な使用 のルールは依然として適用されます。
関数 Slice
は、基になる配列が ptr
から始まり、長さと容量が len
であるスライスを返します。Slice(ptr, len)
は次のように等価です:
(*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]
特別なケースとして、ptr
が nil
で、len
がゼロの場合、Slice
は nil
を返します [Go 1.17]。
len
引数は 整数型 または型指定のない 定数 でなければなりません。型指定のない len
引数は非負であり、型 int
の値で 表現可能 でなければなりません; 型指定のない定数の場合、型 int
が与えられます。実行時に、len
が負である場合、または ptr
が nil
で len
がゼロでない場合、実行時パニック が発生します [Go 1.17]。
関数 SliceData
は、slice
引数の基になる配列へのポインタを返します。スライスの容量 cap(slice)
がゼロでない場合、そのポインタは &slice[:1][0]
です。slice
が nil
の場合、結果は nil
です。そうでなければ、それは未指定のメモリアドレスへの非 nil
ポインタです [Go 1.20]。
関数 String
は、string
値を返し、その基になるバイトは ptr
から始まり、長さは len
です。ptr
および len
引数に対する要件は、関数 Slice
と同様です。len
がゼロの場合、結果は空の文字列 ""
です。Go の文字列は不変であるため、String
に渡されたバイトはその後変更されてはなりません。 [Go 1.20]
関数 StringData
は、str
引数の基になるバイトへのポインタを返します。空の文字列の場合、返される値は未指定であり、nil
である可能性があります。Go の文字列は不変であるため、StringData
によって返されたバイトは変更されてはなりません [Go 1.20].
サイズとアラインメントの保証
数値型 に対して、次のサイズが保証されます:
type size in bytes
byte, uint8, int8 1
uint16, int16 2
uint32, int32, float32 4
uint64, int64, float64, complex64 8
complex128 16
次の最小アラインメント特性が保証されます:
- 1. 任意の型の変数
x
に対して:unsafe.Alignof(x)
は少なくとも 1 です。 - 2. 構造体型の変数
x
に対して:unsafe.Alignof(x)
は、x
の各フィールドf
に対するすべての値unsafe.Alignof(x.f)
の中で最大ですが、少なくとも 1 です。 3. 配列型の変数
x
に対して:unsafe.Alignof(x)
は、配列の要素型の変数のアラインメントと同じです。構造体または配列型は、サイズがゼロのフィールド (または要素) を含まない場合、サイズがゼロになります。二つの異なるゼロサイズの変数は、メモリ内で同じアドレスを持つ場合があります。
付録
言語のバージョン
Go 1 互換性保証 は、Go 1 仕様に従って書かれたプログラムが、その仕様の有効期間中に変更されることなく、引き続き正しくコンパイルおよび実行されることを保証します。一般的に、言語に調整が加えられ、機能が追加されるにつれて、互換性保証は、特定の Go 言語バージョンで動作する Go プログラムが、その後の任意のバージョンでも動作し続けることを保証します。
たとえば、バイナリ整数リテラルの接頭辞 0b
を使用する機能は、Go 1.13 で導入され、整数リテラル のセクションで [Go 1.13] によって示されています。0b1011
のような整数リテラルを含むソースコードは、コンパイラが使用する暗黙のまたは必要な言語バージョンが Go 1.13 より古い場合、拒否されます。
次の表は、Go 1 以降に導入された機能に必要な最小言語バージョンを説明します。
Go 1.9
- エイリアス宣言 を使用して、型のエイリアス名を宣言できます。
Go 1.13
- 整数リテラル は、バイナリおよび八進リテラルのためにそれぞれ接頭辞
0b
、0B
、0o
、および0O
を使用できます。 - 16進数の 浮動小数点リテラル は、接頭辞
0x
および0X
を使用して記述できます。 - 虚数サフィックス
i
は、任意の (バイナリ、10進、16進) 整数または浮動小数点リテラルで使用できます。 - 任意の数値リテラルの桁は、アンダースコア
_
を使用して 区切る (グループ化) ことができます。 - シフト演算 のシフトカウントは符号付き整数型である場合があります。
Go 1.14
- 異なる 埋め込みインターフェース を通じてメソッドを複数回埋め込むことはエラーではありません。
Go 1.17
- スライスは、スライスと配列の要素型が一致し、配列がスライスよりも長くない場合、変換 できます。
- 組み込み パッケージ
unsafe
には、新しい関数Add
およびSlice
が含まれています。
Go 1.18
1.18 リリースでは、言語に多相関数と型 (「ジェネリクス」) が追加されます。具体的には:
- 演算子と句読点 のセットには、新しいトークン
~
が含まれます。 - 関数および型の宣言は、型パラメータ を宣言できます。
- インターフェイスタイプは、任意の型を 埋め込む ことができ、型名のインターフェースだけでなく、ユニオンおよび
~T
型要素も含まれます。 - 事前宣言された 型のセットには、新しい型
any
およびcomparable
が含まれます。
Go 1.20
- スライスは、スライスと配列の要素型が一致し、配列がスライスよりも長くない場合、変換 できます。
- 組み込み パッケージ
unsafe
には、新しい関数SliceData
、String
、およびStringData
が含まれています。 - 比較可能な型 (通常のインターフェースなど) は、型引数が厳密に比較可能でなくても
comparable
制約を満たすことができます。
Go 1.21
- 事前宣言された 関数のセットには、新しい関数
min
、max
、およびclear
が含まれています。 - 型推論 は、推論のためにインターフェースメソッドの型を使用します。また、変数に割り当てられた汎用関数や他の (おそらく汎用) 関数に引数として渡された型引数を推論します。
Go 1.22
Go 1.23
- 「range」句 を持つ「for」文は、範囲式としてイテレータ関数を受け入れます。
型の統一ルール
型の統一ルールは、2つの型がどのように統一されるかを説明します。正確な詳細は Go の実装に関連し、エラーメッセージの具体的な内容 (コンパイラが型推論やその他のエラーを報告するかどうかなど) に影響を与え、型推論が異常なコード状況で失敗する理由を説明する場合があります。しかし、全体としてこれらのルールは Go コードを書く際には無視できます: 型推論は主に「期待通りに動作する」ように設計されており、統一ルールはそれに応じて微調整されています。
型の統一は マッチングモード によって制御され、厳密 または 緩やか である可能性があります。統一が複合型構造を再帰的に降下する際、型の要素に使用されるマッチングモード、要素マッチングモード は、2つの型が 代入可能性 のために統一される場合を除いて、マッチングモードと同じままです (≡A
): この場合、マッチングモードは最上位レベルでは 緩やか ですが、要素型に対しては 厳密 に変更され、型が代入可能であるためには同一である必要がないことを反映しています。
バウンド型パラメータでない2つの型は、次の条件のいずれかが真である場合、厳密に統一されます:
- 両方の型が 同一 である。
- 両方の型が同一の構造を持ち、その要素型が厳密に統一される。
正確に1つの型が 未バウンド 型パラメータであり、コア型 を持ち、そのコア型が
≡A
の統一ルールに従って他の型と統一される (最上位レベルでの緩やかな統一と要素型に対する厳密な統一)。両方の型がバウンド型パラメータである場合、次の条件を満たす場合、与えられたマッチングモードに従って統一されます:
両方の型パラメータが同一である。
- 型パラメータのうち、最大1つが既知の型引数を持つ。この場合、型パラメータは結合されます: 両方とも同じ型引数を表します。どちらの型パラメータもまだ既知の型引数を持たない場合、将来の型引数が1つの型パラメータに対して推論されると、同時に両方の型パラメータに対して推論されます。
両方の型パラメータが既知の型引数を持ち、型引数が与えられたマッチングモードに従って統一されます。
単一のバウンド型パラメータ
P
と他の型T
は、与えられたマッチングモードに従って統一されます:P
が既知の型引数を持たない。この場合、T
がP
の型引数として推論されます。P
が既知の型引数A
を持ち、A
とT
が与えられたマッチングモードに従って統一され、次の条件のいずれかが真である:- 両方
A
とT
がインターフェイスタイプである: この場合、両方A
とT
が 定義された 型である場合、同一でなければなりません。そうでなければ、どちらも定義された型でない場合、同じ数のメソッドを持たなければなりません (A
とT
の統一はすでにメソッドが一致することを確立しています)。 A
もT
もインターフェイスタイプでない: この場合、T
が定義された型である場合、T
がA
の型引数として推論されます。
最後に、バウンド型パラメータでない2つの型は、次の条件を満たす場合に緩やかに統一されます (および要素マッチングモードに従って):
- 両方
両方の型が厳密に統一される。
- 一方の型が 定義された型 であり、もう一方の型が型リテラルであるがインターフェースではなく、その基になる型が要素マッチングモードに従って統一される。
- 両方の型がインターフェース (ただし型パラメータではない) であり、同一の 型項 を持ち、両方またはどちらも事前宣言された型 比較可能 を埋め込み、対応するメソッド型が厳密に統一され、1つのインターフェースのメソッドセットが他のインターフェースのメソッドセットの部分集合である。
- 一方の型のみがインターフェース (ただし型パラメータではない) であり、2つの型の対応するメソッドが要素マッチングモードに従って統一され、インターフェースのメソッドセットが他の型のメソッドセットの部分集合である。
- 両方の型が同一の構造を持ち、その要素型が要素マッチングモードに従って統一されます。