Goプログラミング言語仕様

2021年10月15日版

はじめに

これは、ジェネリクスの導入前の2021年10月の言語バージョン1.17のGoプログラミング言語のリファレンスマニュアルです。これは、歴史的な関心のために提供されています。現在のリファレンスマニュアルはこちらにあります。詳細およびその他のドキュメントについては、go.devを参照してください。

Goは、システムプログラミングを念頭に置いて設計された汎用言語です。これは強力な型付けがされ、ガベージコレクションを備え、並行プログラミングの明示的なサポートがあります。プログラムはパッケージから構成されており、そのプロパティにより、依存関係を効率的に管理できます。

文法はコンパクトで解析が簡単であり、統合開発環境などの自動ツールによる簡単な分析が可能です。

表記法

構文は、拡張バッカス・ナウア記法 (EBNF) を使用して指定されています

Production  = production_name "=" [ Expression ] "." .
Expression  = Alternative { "|" Alternative } .
Alternative = Term { Term } .
Term        = 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言語のトークンではありません。

ソースコードの表現

ソースコードは、UTF-8でエンコードされたUnicodeテキストです。テキストは正規化されないため、単一のアクセント付きコードポイントは、アクセントと文字を結合して構築された同じ文字とは区別されます。これらは2つのコードポイントとして扱われます。簡単にするために、このドキュメントでは、文字という修飾のない用語を、ソーステキストのUnicodeコードポイントを指すために使用します。

各コードポイントは区別されます。たとえば、大文字と小文字は異なる文字です。

実装上の制限: 他のツールとの互換性のために、コンパイラーはソーステキストでNUL文字 (U+0000) を許可しない場合があります。

実装上の制限: 他のツールとの互換性のために、コンパイラーは、UTF-8エンコードされたバイトオーダーマーク (U+FEFF) がソーステキストの最初のUnicodeコードポイントである場合、これを無視する場合があります。バイトオーダーマークは、ソース内の他の場所では許可されない場合があります。

文字

次の用語は、特定のUnicode文字クラスを示すために使用されます

newline        = /* the Unicode code point U+000A */ .
unicode_char   = /* an arbitrary Unicode code point except newline */ .
unicode_letter = /* a Unicode code point classified as "Letter" */ .
unicode_digit  = /* a Unicode code point classified as "Number, decimal digit" */ .

Unicode標準8.0のセクション4.5「一般カテゴリ」では、文字カテゴリのセットが定義されています。Goは、LetterカテゴリLu、Ll、Lt、Lm、またはLoのすべての文字をUnicode文字として扱い、NumberカテゴリNdの文字をUnicode数字として扱います。

文字と数字

アンダースコア文字_ (U+005F) は文字と見なされます。

letter        = unicode_letter | "_" .
decimal_digit = "0" … "9" .
binary_digit  = "0" | "1" .
octal_digit   = "0" … "7" .
hex_digit     = "0" … "9" | "A" … "F" | "a" … "f" .

字句要素

コメント

コメントはプログラムドキュメントとして機能します。2つの形式があります

  1. 行コメントは文字シーケンス//で始まり、行末で停止します。
  2. 一般コメントは文字シーケンス/*で始まり、最初の後続の文字シーケンス*/で停止します。

コメントは、ルーンまたは文字列リテラル、またはコメント内では開始できません。改行を含まない一般コメントはスペースのように動作します。その他のコメントは改行のように動作します。

トークン

トークンはGo言語の語彙を形成します。識別子キーワード演算子と句読点、およびリテラルの4つのクラスがあります。スペース (U+0020)、水平タブ (U+0009)、キャリッジリターン (U+000D)、および改行 (U+000A) から形成される空白は、それ以外の場合は単一のトークンに結合されるトークンを分離する場合を除いて無視されます。また、改行またはファイルの終端は、セミコロンの挿入をトリガーする場合があります。入力をトークンに分割する際、次のトークンは有効なトークンを形成する最長の文字シーケンスです。

セミコロン

正式な文法では、セミコロン";"を多数の生成規則の終端記号として使用します。Goプログラムでは、次の2つの規則を使用して、これらのセミコロンのほとんどを省略できます

  1. 入力がトークンに分割されると、トークンが次のいずれかである場合、行の最後のトークンの直後に、セミコロンがトークンストリームに自動的に挿入されます
  2. 複雑なステートメントを1行に記述できるようにするには、閉じの")"または"}"の前にセミコロンを省略できます。

慣用的な使用を反映するために、このドキュメントのコード例では、これらの規則を使用してセミコロンを省略しています。

識別子

識別子は、変数や型などのプログラムエンティティに名前を付けます。識別子は、1つ以上の文字と数字のシーケンスです。識別子の最初の文字は文字である必要があります。

identifier = letter { letter | unicode_digit } .
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

演算子と句読点

次の文字シーケンスは、演算子 ( 代入演算子を含む) と句読点を表します

+    &     +=    &=     &&    ==    !=    (    )
-    |     -=    |=     ||    <     <=    [    ]
*    ^     *=    ^=     <-    >     >=    {    }
/    <<    /=    <<=    ++    =     :=    ,    ;
%    >>    %=    >>=    --    !     ...   .    :
     &^          &^=

整数リテラル

整数リテラルは、整数定数を表す数字のシーケンスです。オプションのプレフィックスは、10進数以外の基数を設定します。2進数の場合は0bまたは0B、8進数の場合は00o、または0O、16進数の場合は0xまたは0Xです。単一の0は10進数のゼロと見なされます。16進数のリテラルでは、aからfおよびAからFまでの文字は10から15までの値を表します。

読みやすくするために、アンダースコア文字_は基数プレフィックスの後または連続する数字の間に表示される場合があります。このようなアンダースコアはリテラルの値を変更しません。

int_lit        = decimal_lit | binary_lit | octal_lit | hex_lit .
decimal_lit    = "0" | ( "1" … "9" ) [ [ "_" ] decimal_digits ] .
binary_lit     = "0" ( "b" | "B" ) [ "_" ] binary_digits .
octal_lit      = "0" [ "o" | "O" ] [ "_" ] octal_digits .
hex_lit        = "0" ( "x" | "X" ) [ "_" ] hex_digits .

decimal_digits = decimal_digit { [ "_" ] decimal_digit } .
binary_digits  = binary_digit { [ "_" ] binary_digit } .
octal_digits   = octal_digit { [ "_" ] octal_digit } .
hex_digits     = hex_digit { [ "_" ] hex_digit } .
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でスケールします。

読みやすくするために、アンダースコア文字_は基数プレフィックスの後または連続する数字の間に表示される場合があります。このようなアンダースコアはリテラル値を変更しません。

float_lit         = decimal_float_lit | hex_float_lit .

decimal_float_lit = decimal_digits "." [ decimal_digits ] [ decimal_exponent ] |
                    decimal_digits decimal_exponent |
                    "." decimal_digits [ decimal_exponent ] .
decimal_exponent  = ( "e" | "E" ) [ "+" | "-" ] decimal_digits .

hex_float_lit     = "0" ( "x" | "X" ) hex_mantissa hex_exponent .
hex_mantissa      = [ "_" ] hex_digits "." [ hex_digits ] |
                    [ "_" ] hex_digits |
                    "." hex_digits .
hex_exponent      = ( "p" | "P" ) [ "+" | "-" ] decimal_digits .
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

虚数リテラル

虚数リテラルは、複素数定数の虚数部分を表します。これは、整数または浮動小数点リテラルに続いて小文字の文字iで構成されます。虚数リテラルの値は、それぞれの整数または浮動小数点リテラルの値に虚数単位iを掛けたものです。

imaginary_lit = (decimal_digits | int_lit | float_lit) "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

ルーンリテラル

ルーンリテラルは、Unicodeコードポイントを識別する整数値であるルーン定数を表します。ルーンリテラルは、'x''\n'のように、一重引用符で囲まれた1つ以上の文字として表現されます。引用符内では、改行とエスケープされていない一重引用符を除く任意の文字が表示される場合があります。一重引用符で囲まれた単一の文字は、文字自体のUnicode値を表しますが、バックスラッシュで始まる複数文字のシーケンスは、さまざまな形式で値をエンコードします。

最も単純な形式は、引用符内の単一の文字を表します。GoソーステキストはUTF-8でエンコードされたUnicode文字であるため、複数のUTF-8エンコードされたバイトが単一の整数値を表す場合があります。たとえば、リテラル'a'は、リテラルaを表す単一のバイト、Unicode U+0061、値0x61を保持しますが、'ä'は、リテラルa-二重音字、U+00E4、値0xe4を表す2バイト (0xc3 0xa4) を保持します。

いくつかのバックスラッシュエスケープを使用すると、任意の値をASCIIテキストとしてエンコードできます。整数値を数値定数として表す方法は4つあります。\xに続けて正確に2つの16進数字。\uに続けて正確に4つの16進数字。\Uに続けて正確に8つの16進数字、およびプレーンなバックスラッシュ\に続けて正確に3つの8進数字です。いずれの場合も、リテラルの値は、対応する基数の数字で表される値です。

これらの表現はすべて整数になりますが、有効な範囲が異なります。8進数エスケープは、0から255までの値(両端を含む)を表す必要があります。16進数エスケープは、構造上この条件を満たします。エスケープ\u\UはUnicodeコードポイントを表すため、一部の値、特に0x10FFFFを超える値やサロゲートペアの半分は不正です。

バックスラッシュの後に、特定の1文字エスケープが特殊な値を表します。

\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_lit         = "'" ( unicode_value | byte_value ) "'" .
unicode_value    = unicode_char | little_u_value | big_u_value | escaped_char .
byte_value       = octal_byte_value | hex_byte_value .
octal_byte_value = `\` octal_digit octal_digit octal_digit .
hex_byte_value   = `\` "x" hex_digit hex_digit .
little_u_value   = `\` "u" hex_digit hex_digit hex_digit hex_digit .
big_u_value      = `\` "U" hex_digit hex_digit hex_digit hex_digit
                           hex_digit hex_digit hex_digit hex_digit .
escaped_char     = `\` ( "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
'\xa'        // illegal: too few hexadecimal digits
'\0'         // illegal: too few octal digits
'\uDFFF'     // illegal: surrogate half
'\U00110000' // illegal: invalid Unicode code point

文字列リテラル

文字列リテラルは、文字のシーケンスを連結して得られる文字列定数を表します。生の文字列リテラルと解釈される文字列リテラルの2つの形式があります。

生の文字列リテラルは、`foo`のようにバッククォートで囲まれた文字シーケンスです。クォート内では、バッククォートを除く任意の文字を使用できます。生の文字列リテラルの値は、クォートで囲まれた解釈されない(暗黙的にUTF-8エンコードされた)文字で構成される文字列です。特に、バックスラッシュは特別な意味を持たず、文字列に改行を含めることができます。生の文字列リテラル内のキャリッジリターン文字('\r')は、生の文字列の値から破棄されます。

解釈される文字列リテラルは、"bar"のように二重引用符で囲まれた文字シーケンスです。引用符内では、改行とエスケープされていない二重引用符を除く任意の文字を使用できます。引用符で囲まれたテキストはリテラルの値を形成し、バックスラッシュエスケープはルーンリテラルの場合と同じように解釈されます(ただし、\'は不正であり、\"は有効です)。3桁の8進数(\nnn)と2桁の16進数(\xnn)エスケープは、結果の文字列の個々のバイトを表します。他のすべてのエスケープは、個々の文字の(場合によってはマルチバイトの)UTF-8エンコードを表します。したがって、文字列リテラル内では、\377\xFFは値0xFF=255の単一バイトを表し、ÿ\u00FF\U000000FF、および\xc3\xbfは、文字U+00FFのUTF-8エンコードの2バイト0xc3 0xbfを表します。

string_lit             = raw_string_lit | interpreted_string_lit .
raw_string_lit         = "`" { unicode_char | newline } "`" .
interpreted_string_lit = `"` { unicode_value | byte_value } `"` .
`abc`                // same as "abc"
`\n
\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
`日本語`                                 // UTF-8 input text as a raw literal
"\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つのコードポイントとして表す場合、ルーンリテラルに配置するとエラーになります(単一のコードポイントではないため)。文字列リテラルに配置すると、2つのコードポイントとして表示されます。

定数

ブール定数ルーン定数整数定数浮動小数点定数複素数定数、および文字列定数があります。ルーン、整数、浮動小数点、および複素数定数は、まとめて数値定数と呼ばれます。

定数値は、ルーン整数浮動小数点虚数、または文字列リテラル、定数を表す識別子、定数式、定数である結果を持つ変換、またはunsafe.Sizeof(任意の値を適用)、capまたはlenいくつかの式に適用)、複素数定数に適用したrealimag、および数値定数に適用したcomplexなど、一部の組み込み関数の結果の値によって表されます。ブール真理値は、事前宣言された定数truefalseで表されます。事前宣言された識別子iotaは整数定数を表します。

一般に、複素数定数は定数式の一種であり、そのセクションで説明します。

数値定数は、任意の精度の正確な値を表し、オーバーフローしません。したがって、IEEE 754の負のゼロ、無限大、および非数値(NaN)値を表す定数はありません。

定数は型付きまたは型なしである場合があります。リテラル定数、truefalseiota、および型なしの定数オペランドのみを含む特定の定数式は型なしです。

定数には、定数宣言または変換によって明示的に型を与えるか、変数宣言代入、またはのオペランドとして使用されたときに暗黙的に型を与えることができます。定数値がそれぞれの型の値として表現できない場合はエラーになります。

型なし定数にはデフォルト型があり、これは、型付きの値が必要なコンテキストで、たとえば、明示的な型がないi := 0のような短い変数宣言で、定数が暗黙的に変換される型です。型なし定数のデフォルト型は、ブール定数、ルーン定数、整数定数、浮動小数点定数、複素数定数、または文字列定数であるかどうかに応じて、それぞれboolruneintfloat64complex128またはstringです。

実装上の制約:数値定数は言語内では任意の精度を持っていますが、コンパイラは限られた精度を持つ内部表現を使用して実装する場合があります。そうは言っても、すべての実装は次のことを行う必要があります。

これらの要件は、リテラル定数と定数式の評価結果の両方に適用されます。

変数

変数は、を保持するためのストレージロケーションです。許可される値のセットは、変数のによって決定されます。

変数宣言、または関数パラメータと結果の場合、関数宣言または関数リテラルのシグネチャは、名前付き変数のストレージを予約します。組み込み関数newの呼び出し、または複合リテラルのアドレスを取得すると、実行時に変数のストレージが割り当てられます。このような匿名変数は、(場合によっては暗黙的な)ポインタ間接参照を介して参照されます。

配列スライス、および構造体型の構造化変数には、個別にアドレス指定できる要素とフィールドがあります。このような各要素は変数のように動作します。

変数の静的型(または単に)は、宣言で与えられた型、new呼び出しまたは複合リテラルで提供された型、または構造化変数の要素の型です。インターフェース型の変数にも、明確な動的型があります。これは、実行時に変数に割り当てられた値の具体的な型です(値が事前宣言された識別子nilである場合を除きます。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

変数の値は、で変数を参照することで取得されます。これは、変数に割り当てられた最新の値です。変数がまだ値に割り当てられていない場合、その値は型のゼロ値です。

型は、それらの値に固有の操作とメソッドと共に、値のセットを決定します。型は、型名がある場合は型名で表すか、既存の型から型を構成する型リテラルを使用して指定できます。

Type      = TypeName | TypeLit | "(" Type ")" .
TypeName  = identifier | QualifiedIdent .
TypeLit   = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
	    SliceType | MapType | ChannelType .

言語は、特定の型名を事前宣言します。その他は、型宣言で導入されます。複合型—配列、構造体、ポインタ、関数、インターフェース、スライス、マップ、およびチャネル型—は、型リテラルを使用して構築できます。

各型Tには、基本型があります。Tが事前宣言されたブール型、数値型、または文字列型、あるいは型リテラルのいずれかである場合、対応する基本型はT自体です。それ以外の場合、Tの基本型は、T型宣言で参照する型の基本型です。

type (
	A1 = string
	A2 = A1
)

type (
	B1 string
	B2 B1
	B3 []B1
	B4 B3
)

stringA1A2B1、およびB2の基本型はstringです。[]B1B3、およびB4の基本型は[]B1です。

メソッドセット

型には、関連付けられた(場合によっては空の)メソッドセットがあります。インターフェース型のメソッドセットは、そのインターフェースです。その他の型Tのメソッドセットは、レシーバー型Tで宣言されたすべてのメソッドで構成されます。対応するポインタ型*Tのメソッドセットは、レシーバー*TまたはTで宣言されたすべてのメソッドのセットです(つまり、Tのメソッドセットも含まれます)。構造体型のセクションで説明されているように、埋め込みフィールドを含む構造体にさらに規則が適用されます。他の型には空のメソッドセットがあります。メソッドセットでは、各メソッドは一意のブランクメソッド名を持っている必要があります。

型のメソッドセットは、型が実装するインターフェースと、その型のレシーバーを使用して呼び出すことができるメソッドを決定します。

ブール型

ブール型は、事前宣言された定数truefalseで表されるブール真理値のセットを表します。事前宣言されたブール型は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ビット幅で、2の補数演算を使用して表現されます。

実装固有のサイズを持つ事前宣言された数値型のセットもあります。

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

移植性の問題を避けるため、すべての数値型は定義された型であり、したがって、byteuint8エイリアス)とruneint32のエイリアス)を除き、区別されます。式や代入で異なる数値型を混在させる場合は、明示的な変換が必要です。たとえば、int32intは、特定のアーキテクチャで同じサイズを持つ可能性がある場合でも、同じ型ではありません。

文字列型

文字列型は、文字列値の集合を表します。文字列値は、バイトの(空である可能性のある)シーケンスです。バイト数は文字列の長さと呼ばれ、負になることはありません。文字列は不変です。一度作成すると、文字列の内容を変更することはできません。事前宣言された文字列型はstringです。これは定義された型です。

文字列sの長さは、組み込み関数lenを使用して検出できます。文字列が定数の場合、長さはコンパイル時の定数です。文字列のバイトには、0からlen(s)-1までの整数のインデックスでアクセスできます。このような要素のアドレスを取得することは許可されていません。s[i]が文字列のi番目のバイトである場合、&s[i]は無効です。

配列型

配列は、要素型と呼ばれる単一の型の要素の番号付きシーケンスです。要素の数は配列の長さと呼ばれ、負になることはありません。

ArrayType   = "[" ArrayLength "]" ElementType .
ArrayLength = Expression .
ElementType = Type .

長さは配列の型の一部です。長さは、int型の値で表現可能な非負の定数として評価される必要があります。配列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))

スライス型

スライスは、基になる配列の連続したセグメントの記述子であり、その配列からの要素の番号付きシーケンスへのアクセスを提供します。スライス型は、要素型の配列のすべてのスライスの集合を表します。要素の数はスライスの長さと呼ばれ、負になることはありません。初期化されていないスライスの値はnilです。

SliceType = "[" "]" ElementType .

スライス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次元ですが、複合して高次元のオブジェクトを構築できます。配列の配列の場合、内側の配列は、構成上、常に同じ長さになります。ただし、スライスのスライス(またはスライスの配列)の場合、内側の長さは動的に変化する可能性があります。さらに、内側のスライスは個別に初期化する必要があります。

構造体型

構造体は、フィールドと呼ばれる名前付き要素のシーケンスであり、各要素には名前と型があります。フィールド名は明示的に(IdentifierList)または暗黙的に(EmbeddedField)指定できます。構造体内で、非ブランクのフィールド名は一意である必要があります。

StructType    = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl     = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag           = string_lit .
// An empty struct.
struct {}

// A struct with 6 fields.
struct {
	x, y int
	u float32
	_ float32  // padding
	A *[]int
	F func()
}

型は宣言されているが、明示的なフィールド名がないフィールドは、埋め込みフィールドと呼ばれます。埋め込みフィールドは、型名Tまたは非インターフェース型名*Tへのポインタとして指定する必要があり、T自体はポインタ型であってはなりません。修飾されていない型名はフィールド名として機能します。

// 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
}

次の宣言は、フィールド名が構造体型で一意でなければならないため、不正です。

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
}

構造体x内の埋め込みフィールドのフィールドまたはメソッドfは、x.fがそのフィールドまたはメソッドfを示す有効なセレクタである場合、昇格されます。

昇格されたフィールドは、構造体の複合リテラルでフィールド名として使用できないことを除いて、構造体の通常のフィールドのように動作します。

構造体型S定義された型Tが与えられた場合、昇格されたメソッドは、次のように構造体のメソッドセットに含まれます。

フィールド宣言の後には、オプションの文字列リテラルタグを続けることができ、これは対応するフィールド宣言内のすべてのフィールドの属性になります。空のタグ文字列は、タグがないのと同等です。タグはリフレクションインターフェースを通じて可視化され、構造体の型アイデンティティに関与しますが、それ以外の場合は無視されます。

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"`
}

ポインタ型

ポインタ型は、ポインタのベース型と呼ばれる、特定の型の変数へのすべてのポインタの集合を表します。初期化されていないポインタの値はnilです。

PointerType = "*" BaseType .
BaseType    = Type .
*Point
*[4]int

関数型

関数型は、同じパラメータ型と結果型を持つすべての関数の集合を表します。関数型の初期化されていない変数の値はnilです。

FunctionType   = "func" Signature .
Signature      = Parameters [ Result ] .
Result         = Parameters | Type .
Parameters     = "(" [ ParameterList [ "," ] ] ")" .
ParameterList  = ParameterDecl { "," ParameterDecl } .
ParameterDecl  = [ IdentifierList ] [ "..." ] Type .

パラメータまたは結果のリスト内で、名前(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です。

InterfaceType      = "interface" "{" { ( MethodSpec | InterfaceTypeName ) ";" } "}" .
MethodSpec         = MethodName Signature .
MethodName         = identifier .
InterfaceTypeName  = TypeName .

インターフェース型は、メソッド仕様を通じてメソッドを明示的に指定したり、インターフェース型名を介して他のインターフェースのメソッドを埋め込んだりすることができます。

// 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つの型S1S2がメソッドセット

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

(ここでTS1またはS2を表します)を持っている場合、Fileインターフェースは、S1S2が他にどのようなメソッドを持つか、または共有するかに関係なく、S1S2の両方によって実装されます。

型は、そのメソッドの任意のサブセットで構成される任意のインターフェースを実装し、したがって、複数の異なるインターフェースを実装できます。たとえば、すべての型は空のインターフェースを実装します。

interface{}

同様に、型宣言内でLockerという名前のインターフェースを定義するために表示される次のインターフェース仕様を考えてください。

type Locker interface {
	Lock()
	Unlock()
}

S1S2も次を実装する場合

func (p T) Lock() { … }
func (p T) Unlock() { … }

Fileインターフェースだけでなく、Lockerインターフェースも実装します。

インターフェースTは、メソッド仕様の代わりに(修飾されている可能性のある)インターフェース型名Eを使用できます。これは、インターフェースET埋め込むと呼ばれます。Tメソッドセットは、Tの明示的に宣言されたメソッドとTの埋め込まれたインターフェースのメソッドセットの和集合です。

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
}

メソッドセットの和集合には、各メソッドセットの(エクスポートされたメソッドとエクスポートされていないメソッド)メソッドが正確に1回含まれ、同じ名前のメソッドは同一のシグネチャを持つ必要があります。

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を再帰的に埋め込むインターフェース型を埋め込むことはできません。

// illegal: Bad cannot embed itself
type Bad interface {
	Bad
}

// illegal: Bad1 cannot embed itself using Bad2
type Bad1 interface {
	Bad2
}
type Bad2 interface {
	Bad1
}

マップ型

マップは、要素型と呼ばれる1つの型の要素の順序付けられていないグループであり、キー型と呼ばれる別の型の一意のキーのセットによってインデックスが付けられます。初期化されていないマップの値はnilです。

MapType     = "map" "[" KeyType "]" ElementType .
KeyType     = Type .

比較演算子==!=は、キー型のオペランドに対して完全に定義されている必要があります。したがって、キー型は関数、マップ、またはスライスであってはなりません。キー型がインターフェース型の場合、これらの比較演算子は動的キー値に対して定義されている必要があります。失敗すると、実行時パニックが発生します。

map[string]int
map[*T]struct{ x, y float64 }
map[string]interface{}

マップ要素の数は、その長さと呼ばれます。マップmの場合、組み込み関数lenを使用して検出でき、実行中に変更される可能性があります。要素は、代入を使用して実行中に追加でき、インデックス式で取得できます。delete組み込み関数で削除できます。

新しい空のマップ値は、マップ型とオプションのキャパシティヒントを引数として取る組み込み関数makeを使用して作成されます。

make(map[string]int)
make(map[string]int, 100)

初期容量はサイズを制限しません。マップは、nilマップを除いて、格納されているアイテムの数を収容するように拡張します。nilマップは、要素を追加できないことを除いて、空のマップと同等です。

チャネル型

チャネルは、並行実行される関数が、指定された要素型の値を送信および受信することによって通信するためのメカニズムを提供します。初期化されていないチャネルの値は nil です。

ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .

オプションの <- 演算子は、チャネルの方向送信または受信を指定します。方向が指定されていない場合、チャネルは双方向です。チャネルは、代入または明示的な変換によって、送信のみまたは受信のみに制約できます。

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

<- 演算子は、可能な限り左端の chan と関連付けられます。

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の呼び出しで、追加の同期なしに任意の数のゴルーチンによって使用できます。チャネルは先入れ先出しのキューとして機能します。たとえば、あるゴルーチンがチャネルに値を送信し、別のゴルーチンがそれらを受信する場合、値は送信された順序で受信されます。

型と値のプロパティ

型の同一性

2つの型は、同一であるか、異なるかのいずれかです。

定義された型は、常に他のどの型とも異なります。それ以外の場合、2つの型は、それらの基になる型リテラルが構造的に同等である場合、つまり、同じリテラル構造を持ち、対応するコンポーネントが同一の型を持つ場合に同一です。詳細:

次の宣言が与えられたとします。

type (
	A0 = []string
	A1 = A0
	A2 = struct{ a, b int }
	A3 = int
	A4 = func(A3, float64) *A0
	A5 = func(x int, _ float64) *[]string
)

type (
	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
)

type	C0 = B0

これらの型は同一です。

A0, A1, and []string
A2 and struct{ a, b int }
A3 and int
A4, func(int, float64) *[]string, and A5

B0 and C0
[]int and []int
struct{ a, b *T5 } and struct{ a, b *T5 }
func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5

B0B1は、異なる型定義によって作成された新しい型であるため異なります。func(int, float64) *B0func(x int, y float64) *[]stringは、B0[]stringと異なるため異なります。

代入可能性

xは、型T変数代入可能です(「xTに代入可能」)次のいずれかの条件が適用される場合:

表現可能性

定数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

ブロック

ブロックは、対応する中括弧内の宣言とステートメントの、場合によっては空のシーケンスです。

Block = "{" StatementList "}" .
StatementList = { Statement ";" } .

ソースコード内の明示的なブロックに加えて、暗黙的なブロックがあります。

  1. ユニバースブロックは、すべてのGoソーステキストを包含します。
  2. パッケージには、そのパッケージのすべてのGoソーステキストを含むパッケージブロックがあります。
  3. 各ファイルには、そのファイルのすべてのGoソーステキストを含むファイルブロックがあります。
  4. "if""for"、および"switch"ステートメントは、独自の暗黙的なブロックにあると見なされます。
  5. "switch"または"select"ステートメントの各句は、暗黙的なブロックとして機能します。

ブロックはネストし、スコープに影響を与えます。

宣言とスコープ

宣言は、非ブランク識別子を定数変数関数ラベル、またはパッケージにバインドします。プログラム内のすべての識別子は宣言されている必要があります。同じブロック内で識別子を2回宣言することはできず、ファイルとパッケージブロックの両方で識別子を宣言することはできません。

ブランク識別子は、宣言で他の識別子と同様に使用できますが、バインディングを導入しないため、宣言されません。パッケージブロックでは、識別子initinit関数宣言にのみ使用でき、ブランク識別子と同様に、新しいバインディングを導入しません。

Declaration   = ConstDecl | TypeDecl | VarDecl .
TopLevelDecl  = Declaration | FunctionDecl | MethodDecl .

宣言された識別子のスコープは、識別子が指定された定数、型、変数、関数、ラベル、またはパッケージを示すソーステキストの範囲です。

Goは、ブロックを使用して字句的にスコープされます。

  1. 事前宣言された識別子のスコープは、ユニバースブロックです。
  2. トップレベル(関数外)で宣言された定数、型、変数、または関数(ただしメソッドではない)を示す識別子のスコープは、パッケージブロックです。
  3. インポートされたパッケージのパッケージ名のスコープは、インポート宣言を含むファイルのファイルブロックです。
  4. メソッドレシーバー、関数パラメータ、または結果変数を表す識別子のスコープは、関数本体です。
  5. 関数内で宣言された定数または変数識別子のスコープは、ConstSpecまたはVarSpec(短い変数宣言の場合はShortVarDecl)の終わりから始まり、最も内側の包含ブロックの終わりで終わります。
  6. 関数内で宣言された型識別子のスコープは、TypeSpec内の識別子から始まり、最も内側の包含ブロックの終わりで終わります。

ブロック内で宣言された識別子は、内側のブロックで再宣言できます。内側の宣言の識別子がスコープ内にある間、その識別子は内側の宣言によって宣言されたエンティティを示します。

パッケージ句は宣言ではありません。パッケージ名はどのスコープにも表示されません。その目的は、同じパッケージに属するファイルを識別し、インポート宣言のデフォルトのパッケージ名を指定することです。

ラベルのスコープ

ラベルはラベル付きステートメントによって宣言され、"break""continue"、および"goto"ステートメントで使用されます。使用されないラベルを定義することは違法です。他の識別子とは対照的に、ラベルはブロックでスコープされず、ラベルではない識別子と競合しません。ラベルのスコープは、それが宣言されている関数の本体であり、ネストされた関数の本体を除きます。

ブランク識別子

ブランク識別子は、アンダースコア文字_で表されます。これは、通常の(非ブランク)識別子の代わりに匿名プレースホルダーとして機能し、宣言オペランドとして、および代入で特別な意味を持ちます。

事前宣言された識別子

次の識別子は、ユニバースブロックで暗黙的に宣言されています。

Types:
	bool byte 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 close complex copy delete imag len
	make new panic print println real recover

エクスポートされた識別子

識別子は、別のパッケージからのアクセスを許可するためにエクスポートされる場合があります。識別子がエクスポートされるのは、次の両方の場合です。

  1. 識別子の名前の最初の文字が、Unicode大文字(Unicodeクラス"Lu")である。
  2. 識別子がパッケージブロックで宣言されているか、フィールド名またはメソッド名である。

他のすべての識別子はエクスポートされません。

識別子の一意性

識別子のセットが与えられた場合、識別子は、セット内の他のすべての識別子と異なる場合に一意と呼ばれます。2つの識別子は、スペルが異なる場合、または異なるパッケージに表示され、エクスポートされない場合は異なります。それ以外の場合、それらは同じです。

定数宣言

定数宣言は、識別子(定数の名前)のリストを、定数式のリストの値に束縛します。識別子の数は式の数と等しくなければならず、左側のn番目の識別子は右側のn番目の式の値に束縛されます。

ConstDecl      = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
ConstSpec      = IdentifierList [ [ Type ] "=" ExpressionList ] .

IdentifierList = identifier { "," identifier } .
ExpressionList = Expression { "," Expression } .

型が指定されている場合、すべての定数は指定された型を取り、式はその型に代入可能でなければなりません。型が省略された場合、定数は対応する式の個別の型を取ります。式の値が型なし定数の場合、宣言された定数は型なしのままになり、定数識別子は定数値を示します。たとえば、式が浮動小数点リテラルの場合、リテラルの小数部分がゼロであっても、定数識別子は浮動小数点定数を示します。

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

定数宣言内では、事前宣言された識別子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)
)

この最後の例では、最後の非空式リストの暗黙的な繰り返しを利用しています。

型宣言

型宣言は、識別子(型名)をに束縛します。型宣言には、エイリアス宣言と型定義の2つの形式があります。

TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec = AliasDecl | TypeDef .

エイリアス宣言

エイリアス宣言は、識別子を指定された型に束縛します。

AliasDecl = identifier "=" Type .

識別子のスコープ内では、型に対するエイリアスとして機能します。

type (
	nodeList = []*Node  // nodeList and []*Node are identical types
	Polar    = polar    // Polar and polar denote identical types
)

型定義

型定義は、指定された型と同じ基になる型と操作を持つ、新しい、異なる型を作成し、識別子をそれに束縛します。

TypeDef = identifier Type .

新しい型は定義型と呼ばれます。これは、作成元の型を含む他のすべての型とは異なります

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 *Comparable
}

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)
}

変数宣言

変数宣言は、1つ以上の変数を作成し、対応する識別子をそれらに束縛し、それぞれに型と初期値を与えます。

VarDecl     = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
VarSpec     = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
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

実装上の制限:コンパイラは、変数が使用されない場合、関数本体内で変数を宣言することを禁止する場合があります。

短縮変数宣言

短縮変数宣言は、次の構文を使用します。

ShortVarDecl = IdentifierList ":=" ExpressionList .

これは、初期化式はあるが型のない通常の変数宣言の略です。

"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

通常の変数宣言とは異なり、短縮変数宣言は、同じブロック(またはブロックが関数本体である場合はパラメーターリスト)で以前に同じ型で宣言されており、少なくとも1つの非ブランク変数が新しい場合に、変数を再宣言できます。その結果、再宣言は複数変数の短縮宣言でのみ発生する可能性があります。再宣言は新しい変数を導入しません。元の変数に新しい値を代入するだけです。

field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset)  // redeclares offset
a, a := 1, 2                              // illegal: double declaration of a or no new variable if a was declared elsewhere

短縮変数宣言は、関数内でのみ使用できます。"if""for"、または"switch"ステートメントの初期化子など、一部のコンテキストでは、ローカルの一時変数を宣言するために使用できます。

関数宣言

関数宣言は、識別子(関数名)を関数に束縛します。

FunctionDecl = "func" FunctionName Signature [ FunctionBody ] .
FunctionName = identifier .
FunctionBody = Block .

関数のシグネチャが結果パラメーターを宣言する場合、関数本体のステートメントリストは終了ステートメントで終わる必要があります。

func IndexRune(s string, r rune) int {
	for i, c := range s {
		if c == r {
			return i
		}
	}
	// invalid: missing return statement
}

関数宣言は本体を省略できます。このような宣言は、アセンブリルーチンなど、Goの外部で実装された関数のシグネチャを提供します。

func min(x int, y int) int {
	if x < y {
		return x
	}
	return y
}

func flushICache(begin, end uintptr)  // implemented externally

メソッド宣言

メソッドはレシーバーを持つ関数です。メソッド宣言は、識別子(メソッド名)をメソッドにバインドし、メソッドをレシーバーの基本型に関連付けます。

MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] .
Receiver   = Parameters .

レシーバーは、メソッド名の前にある追加のパラメーターセクションを介して指定されます。そのパラメーターセクションは、レシーバーである単一の可変長ではないパラメーターを宣言する必要があります。その型は、定義済みの型T、または定義済みの型Tへのポインターである必要があります。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
}

は、基本型Pointに、レシーバー型*Pointを持つメソッドLengthScaleをバインドします。

メソッドの型は、最初の引数としてレシーバーを持つ関数の型です。たとえば、メソッドScaleの型は

func(p *Point, factor float64)

ただし、この方法で宣言された関数はメソッドではありません。

式は、オペランドに演算子と関数を適用することによって値を計算することを指定します。

オペランド

オペランドは、式内の基本的な値を表します。オペランドは、リテラル、(場合によっては修飾された)非ブランクの識別子であり、定数変数、または関数を表すか、括弧で囲まれた式である可能性があります。

ブランク識別子は、代入の左辺でのみオペランドとして表示できます。

Operand     = Literal | OperandName | "(" Expression ")" .
Literal     = BasicLit | CompositeLit | FunctionLit .
BasicLit    = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .
OperandName = identifier | QualifiedIdent .

修飾された識別子

修飾された識別子は、パッケージ名のプレフィックスで修飾された識別子です。パッケージ名と識別子の両方がブランクであってはなりません。

QualifiedIdent = PackageName "." identifier .

修飾された識別子は、インポートする必要がある別のパッケージ内の識別子にアクセスします。識別子はエクスポートされ、そのパッケージのパッケージブロックで宣言されている必要があります。

math.Sin	// denotes the Sin function in package math

複合リテラル

複合リテラルは、構造体、配列、スライス、およびマップの値を構築し、評価されるたびに新しい値を作成します。これらは、リテラルの型と、それに続く波括弧で囲まれた要素のリストで構成されます。各要素の前には、対応するキーを任意で付けることができます。

CompositeLit  = LiteralType LiteralValue .
LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
                SliceType | MapType | TypeName .
LiteralValue  = "{" [ ElementList [ "," ] ] "}" .
ElementList   = KeyedElement { "," KeyedElement } .
KeyedElement  = [ Key ":" ] Element .
Key           = FieldName | Expression | LiteralValue .
FieldName     = identifier .
Element       = Expression | LiteralValue .

LiteralTypeの基になる型は、構造体、配列、スライス、またはマップ型である必要があります(文法では、型がTypeNameとして指定されている場合を除き、この制約が適用されます)。要素とキーの型は、リテラル型のそれぞれのフィールド、要素、およびキー型に代入可能である必要があります。追加の変換はありません。キーは、構造体リテラルの場合はフィールド名、配列およびスライスリテラルの場合はインデックス、マップリテラルの場合はキーとして解釈されます。マップリテラルの場合、すべての要素にキーが必要です。同じフィールド名または定数キー値を持つ複数の要素を指定するとエラーになります。非定数マップキーについては、評価順序に関するセクションを参照してください。

構造体リテラルには、次の規則が適用されます

次の宣言が与えられたとします。

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

配列およびスライスリテラルには、次の規則が適用されます

複合リテラルのアドレスを取得すると、リテラルの値で初期化された一意の変数へのポインターが生成されます。

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{})}

リテラル型のTypeName形式を使用した複合リテラルが、"if"、"for"、または"switch"ステートメントのブロックのキーワードと開始中括弧の間のオペランドとして現れ、その複合リテラルが丸括弧、角括弧、中括弧で囲まれていない場合、構文解析の曖昧さが生じます。このまれなケースでは、リテラルの開始中括弧が、ステートメントのブロックを導入するものとして誤って解析されます。この曖昧さを解消するには、複合リテラルを丸括弧で囲む必要があります。

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,
}

関数リテラル

関数リテラルは、無名の関数を表します。

FunctionLit = "func" Signature FunctionBody .
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)

関数リテラルはクロージャです。つまり、囲まれた関数で定義された変数を参照できます。これらの変数は、囲まれた関数と関数リテラルの間で共有され、アクセス可能な限り存続します。

一次式

一次式は、単項および二項演算のオペランドです。

PrimaryExpr =
	Operand |
	Conversion |
	MethodExpr |
	PrimaryExpr Selector |
	PrimaryExpr Index |
	PrimaryExpr Slice |
	PrimaryExpr TypeAssertion |
	PrimaryExpr Arguments .

Selector       = "." identifier .
Index          = "[" Expression "]" .
Slice          = "[" [ Expression ] ":" [ Expression ] "]" |
                 "[" [ Expression ] ":" Expression ":" Expression "]" .
TypeAssertion  = "." "(" Type ")" .
Arguments      = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
x
2
(s + ".txt")
f(3.1415, true)
Point{1, 2}
m["foo"]
s[i : j + 1]
obj.color
f.p[i].x()

セレクタ

一次式 xパッケージ名でない場合、セレクタ式

x.f

は、値 x (または場合によっては *x、下記参照)のフィールドまたはメソッド f を示します。識別子 f は(フィールドまたはメソッド)セレクタと呼ばれ、ブランク識別子であってはなりません。セレクタ式の型は、f の型です。x がパッケージ名の場合は、修飾識別子に関するセクションを参照してください。

セレクタ f は、型 T のフィールドまたはメソッド f を示す場合や、T のネストされた埋め込みフィールドのフィールドまたはメソッド f を参照する場合があります。f に到達するためにトラバースされる埋め込みフィールドの数は、T におけるその深さと呼ばれます。T で宣言されたフィールドまたはメソッド f の深さはゼロです。T の埋め込みフィールド A で宣言されたフィールドまたはメソッド f の深さは、A における f の深さに1を加えたものです。

セレクタには以下の規則が適用されます。

  1. T または *TT はポインタまたはインターフェイス型ではない)の値 x に対して、x.f は、そのような f が存在する T の最も浅い深さにあるフィールドまたはメソッドを示します。最も浅い深さで1つの f が存在しない場合、セレクタ式は不正です。
  2. II はインターフェイス型)の値 x に対して、x.f は、x の動的な値の f という名前の実際のメソッドを示します。Iメソッドセットf という名前のメソッドが存在しない場合、セレクタ式は不正です。
  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 は、メソッドのレシーバーである追加の引数でプレフィックスされた M と同じ引数を持つ通常の関数として呼び出し可能な関数です。

MethodExpr    = ReceiverType "." MethodName .
ReceiverType  = Type .

レシーバーが型 T である Mv と、レシーバーが型 *T である Mp の2つのメソッドを持つ構造体型 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

は、シグネチャが

func(tp *T, f float32) float32

である Mp を表す関数値を生成します。値レシーバーを持つメソッドの場合、明示的なポインタレシーバーを持つ関数を導出できるため、

(*T).Mv

は、シグネチャが

func(tv *T, a int) int

である Mv を表す関数値を生成します。このような関数は、レシーバーを介して間接的に、基になるメソッドにレシーバーとして渡す値を生成します。メソッドは、関数呼び出しでアドレスが渡される値を上書きしません。

最後のケース、ポインタレシーバーメソッドの値レシーバー関数は、ポインタレシーバーメソッドが値型のメソッドセットにないため、不正です。

メソッドから導出された関数値は、関数呼び出し構文で呼び出されます。レシーバーは、呼び出しの最初の引数として提供されます。つまり、f := T.Mv が与えられた場合、ft.f(7) ではなく、f(t, 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 である Mv と、レシーバーが型 *T である Mp の2つのメソッドを持つ構造体型 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つの呼び出しは同等です。

t.Mv(7)
f := t.Mv; f(7)

同様に、式

pt.Mp

は、型

func(float32) float32

セレクタと同様に、ポインタを使用した値レシーバーを持つ非インターフェイスメソッドへの参照は、そのポインタを自動的に逆参照します。pt.Mv(*pt).Mv と同等です。

メソッド呼び出しと同様に、アドレス指定可能な値を使用したポインタレシーバーを持つ非インターフェイスメソッドへの参照は、その値のアドレスを自動的に取得します。t.Mp(&t).Mp と同等です。

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 は、それぞれインデックスまたはマップキーと呼ばれます。以下の規則が適用されます。

a がマップでない場合

配列型 Aa の場合

配列型へのポインタa の場合

スライス型 Sa の場合

文字列型a の場合

マップ型 Ma の場合

上記以外の場合、a[x] は不正です。

特殊な形式の代入または初期化で使用される型 map[K]V のマップ a のインデックス式

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]

は、追加の型なしブール値を生成します。ok の値は、キー x がマップに存在する場合は true、それ以外の場合は false です。

nil マップの要素に代入すると、実行時パニックが発生します。

スライス式

スライス式は、文字列、配列、配列へのポインタ、またはスライスから部分文字列またはスライスを構築します。2つのバリアントがあります。下限と上限を指定する単純な形式と、容量の境界も指定する完全な形式です。

単純なスライス式

文字列、配列、配列へのポインタ、またはスライス a の場合、一次式

a[low : high]

は、部分文字列またはスライスを構築します。インデックス lowhigh は、オペランド 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

完全スライス式

配列、配列へのポインタ、またはスライス a(ただし文字列ではない)の場合、基本式

a[low : high : max]

は、同じ型で、単純なスライス式 a[low : high] と同じ長さと要素を持つスライスを構築します。さらに、結果のスライスのキャパシティを max - low に設定することで制御します。最初のインデックスのみ省略できます。デフォルトは0です。配列 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)

は、xnil ではなく、x に格納されている値が型 T であることをアサートします。表記 x.(T)型アサーションと呼ばれます。

より正確には、T がインターフェース型でない場合、x.(T)x の動的型が型 T同一であることをアサートします。この場合、Tx の(インターフェース)型を実装する必要があります。そうでない場合、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 の式 f が与えられた場合、

f(a1, a2, … an)

は、引数 a1, a2, … an を指定して f を呼び出します。1つの特別なケースを除き、引数は F のパラメータ型に代入可能な単一値式であり、関数が呼び出される前に評価されます。式の型は、F の結果型です。メソッド呼び出しも同様ですが、メソッド自体は、メソッドのレシーバ型の値に対するセレクタとして指定されます。

math.Atan2(x, y)  // function call
var pt *Point
pt.Scale(3.5)     // method call with receiver pt

関数呼び出しでは、関数値と引数は通常の順序で評価されます。それらが評価された後、呼び出しのパラメータは値渡しで関数に渡され、呼び出された関数の実行が開始されます。関数の戻りパラメータは、関数が戻るときに値渡しで呼び出し元に戻されます。

nil の関数値を呼び出すと、実行時パニックが発生します。

特別なケースとして、関数またはメソッド g の戻り値の数と、別の関数またはメソッド f のパラメータに個別に代入可能な場合、呼び出し f(g(parameters_of_g)) は、g の戻り値を f のパラメータに順序通りにバインドした後、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 が型 ...T の最後のパラメータ p を持つ可変長である場合、f 内では p の型は型 []T と同等です。 fp に対して実際引数なしで呼び出された場合、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 と同じ値を持ちます。

演算子

演算子はオペランドを結合して式にします。

Expression = UnaryExpr | Expression binary_op Expression .
UnaryExpr  = PrimaryExpr | unary_op UnaryExpr .

binary_op  = "||" | "&&" | rel_op | add_op | mul_op .
rel_op     = "==" | "!=" | "<" | "<=" | ">" | ">=" .
add_op     = "+" | "-" | "|" | "^" .
mul_op     = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" .

unary_op   = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .

比較については別の場所で説明します。その他の2項演算子の場合、演算にシフトまたは型なし定数が含まれない限り、オペランド型は同一である必要があります。定数のみを含む演算については、定数式のセクションを参照してください。

シフト演算を除き、一方のオペランドが型なし定数であり、もう一方のオペランドがそうでない場合、定数は暗黙的に他方のオペランドの型に変換されます。

シフト式の右オペランドは、整数型であるか、型 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 v float32 = 1<<s           // illegal: 1 has type float32, 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)++ と同じです。

2項演算子には5つの優先順位レベルがあります。乗算演算子が最も強く結合し、その後に加算演算子、比較演算子、&&(論理AND)、そして最後に ||(論理OR)が続きます。

Precedence    Operator
    5             *  /  %  <<  >>  &  &^
    4             +  -  |  ^
    3             ==  !=  <  <=  >  >=
    2             &&
    1             ||

同じ優先順位の2項演算子は左から右に結合します。たとえば、x / y * z(x / y) * z と同じです。

+x
23 + 3*x[i]
x <= f()
^a >> b
f() || g()
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

整数演算子

2つの整数値 xy に対して、整数の商 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

この規則の唯一の例外は、被除数 xx のint型の最も負の値である場合、2の補数整数オーバーフローのために、商 q = x / -1x に等しくなります(および 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 << 1x*2と同じであり、x >> 1x/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が常に真であると仮定することはできません。

浮動小数点演算子

浮動小数点数および複素数の場合、+xxと同じであり、-xxの否定です。浮動小数点数または複素数のゼロによる除算の結果は、IEEE 754標準を超える範囲では指定されていません。 実行時パニックが発生するかどうかは実装に依存します。

実装は、複数の浮動小数点演算を単一の融合演算に組み合わせることができ、場合によっては文をまたいで、個別に命令を実行および丸めることによって得られる値とは異なる結果を生成する可能性があります。明示的な浮動小数点型変換は、ターゲット型の精度に丸めるため、その丸めを破棄する可能性のある融合を防ぎます。

たとえば、一部のアーキテクチャは、中間結果x*yを丸めることなくx*y + zを計算する「融合乗算加算」(FMA)命令を提供します。これらの例は、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"

文字列の加算は、オペランドを連結することによって新しい文字列を作成します。

比較演算子

比較演算子は、2つのオペランドを比較し、型なしブール値を生成します。

==    equal
!=    not equal
<     less
<=    less or equal
>     greater
>=    greater or equal

任意の比較では、最初のオペランドは2番目のオペランドの型に代入可能であるか、またはその逆である必要があります。

等価演算子==!=は、比較可能なオペランドに適用されます。順序演算子<<=>、および>=は、順序付けられたオペランドに適用されます。これらの用語と比較の結果は、次のように定義されます。

同一の動的型を持つ2つのインターフェース値の比較は、その型の値が比較可能でない場合、実行時パニックを引き起こします。この動作は、直接インターフェース値の比較だけでなく、インターフェース値の配列やインターフェース値のフィールドを持つ構造体を比較する場合にも適用されます。

スライス、マップ、および関数の値は比較できません。ただし、特殊なケースとして、スライス、マップ、または関数の値は、事前宣言された識別子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変数を示します。xnilの場合、*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

代入または特別な形式の初期化で使用される受信式

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
var x, ok T = <-ch

通信が成功したかどうかを報告する追加の型なしブール結果を生成します。受信した値がチャネルへの正常な送信操作によって配信された場合はokの値がtrueであり、チャネルが閉じられて空であるために生成されたゼロ値の場合はfalseです。

変換

変換は、式のを変換で指定された型に変更します。変換はソースにリテラルで表示されるか、式が表示されるコンテキストによって暗示される場合があります。

明示的な変換は、T(x)の形式の式です。ここで、Tは型であり、xは型Tに変換できる式です。

Conversion = Type "(" Expression [ "," ] ")" .

型が演算子*または<-で始まる場合、または型がキーワード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は、xTの値で表現可能な場合、型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

非定数値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. 符号付きまたは符号なしの整数値を文字列型に変換すると、その整数のUTF-8表現を含む文字列が得られます。有効なUnicodeコードポイントの範囲外の値は、"\uFFFD"に変換されます。
    string('a')       // "a"
    string(-1)        // "\ufffd" == "\xef\xbf\xbd"
    string(0xf8)      // "\u00f8" == "ø" == "\xc3\xb8"
    type MyString string
    MyString(0x65e5)  // "\u65e5" == "日" == "\xe6\x97\xa5"
    
  2. バイトのスライスを文字列型に変換すると、連続するバイトがスライスの要素である文字列が得られます。
    string([]byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'})   // "hellø"
    string([]byte{})                                     // ""
    string([]byte(nil))                                  // ""
    
    type MyBytes []byte
    string(MyBytes{'h', 'e', 'l', 'l', '\xc3', '\xb8'})  // "hellø"
    
  3. ルーンのスライスを文字列型に変換すると、個々のルーン値を文字列に変換したものを連結した文字列が得られます。
    string([]rune{0x767d, 0x9d6c, 0x7fd4})   // "\u767d\u9d6c\u7fd4" == "白鵬翔"
    string([]rune{})                         // ""
    string([]rune(nil))                      // ""
    
    type MyRunes []rune
    string(MyRunes{0x767d, 0x9d6c, 0x7fd4})  // "\u767d\u9d6c\u7fd4" == "白鵬翔"
    
  4. 文字列型の値をバイトのスライス型に変換すると、連続する要素が文字列のバイトであるスライスが得られます。
    []byte("hellø")   // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
    []byte("")        // []byte{}
    
    MyBytes("hellø")  // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
    
  5. 文字列型の値をルーンのスライス型に変換すると、文字列の個々のUnicodeコードポイントを含むスライスが得られます。
    []rune(MyString("白鵬翔"))  // []rune{0x767d, 0x9d6c, 0x7fd4}
    []rune("")                 // []rune{}
    
    MyRunes("白鵬翔")           // []rune{0x767d, 0x9d6c, 0x7fd4}
    

スライスから配列ポインタへの変換

スライスを配列ポインタに変換すると、スライスの基になる配列へのポインタが得られます。スライスの長さが配列の長さよりも短い場合、ランタイムパニックが発生します。

s := make([]byte, 2, 4)
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)    // t0 == nil
t1 := (*[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

実装上の制約:コンパイラは、型なしの浮動小数点または複素数の定数式を計算中に丸めを使用する場合があります。定数に関するセクションの実装上の制約を参照してください。この丸めにより、無限精度を使用して計算した場合は整数になる浮動小数点定数式が整数コンテキストで無効になったり、その逆になる可能性があります。

評価順序

パッケージレベルでは、初期化依存関係によって、変数宣言における個々の初期化式の評価順序が決まります。それ以外の場合、式、代入、またはreturn文オペランドを評価するときは、すべての関数呼び出し、メソッド呼び出し、および通信操作が字句的に左から右の順序で評価されます。

例えば、(関数ローカルの)代入では

y[f()], ok = g(h(), i()+x[j()], <-c), k()

関数呼び出しと通信は、f()h()i()j()<-cg()、およびk()の順序で発生します。ただし、これらのイベントの順序と、xの評価とインデックス付け、およびyの評価との比較は指定されていません。

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 + zxを加算する前に行われます。

ステートメント

ステートメントは実行を制御します。

Statement =
	Declaration | LabeledStmt | SimpleStmt |
	GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
	FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
	DeferStmt .

SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .

終了ステートメント

終了ステートメントは、ブロックにおける通常の制御フローを中断します。次のステートメントは終了ステートメントです

  1. "return"または"goto"ステートメント。
  2. 組み込み関数panicの呼び出し。
  3. ステートメントリストが終了ステートメントで終わるブロック
  4. 次の"if"ステートメント
    • "else"分岐が存在し、
    • 両方の分岐が終了ステートメントである。
  5. 次の"for"ステートメント
    • "for"ステートメントを参照する"break"ステートメントがなく、
    • ループ条件がなく、
    • "for"ステートメントがrange句を使用していない。
  6. 次の"switch"ステートメント
    • "switch"ステートメントを参照する"break"ステートメントがなく、
    • デフォルトケースがあり、
    • デフォルトを含む各ケースのステートメントリストが、終了ステートメント、またはラベル付けされている可能性がある"fallthrough"ステートメントで終わる。
  7. 次の"select"ステートメント
    • "select"ステートメントを参照する"break"ステートメントがなく、
    • 存在する場合、デフォルトを含む各ケースのステートメントリストが終了ステートメントで終わる。
  8. 終了ステートメントをラベル付けするラベル付きステートメント

他のすべてのステートメントは終了ステートメントではありません。

ステートメントリストが空でなく、最後の空ではないステートメントが終了ステートメントである場合、終了ステートメントで終わります。

空のステートメント

空のステートメントは何もしません。

EmptyStmt = .

ラベル付きステートメント

ラベル付きステートメントは、gotobreak、またはcontinueステートメントのターゲットになる可能性があります。

LabeledStmt = Label ":" Statement .
Label       = identifier .
Error: log.Panic("error encountered")

式ステートメント

特定の組み込み関数を除き、関数とメソッドの呼び出し受信操作はステートメントコンテキストに記述できます。このようなステートメントは括弧で囲むことができます。

ExpressionStmt = Expression .

次の組み込み関数は、ステートメントコンテキストでは許可されていません

append cap complex imag len make new real
unsafe.Add unsafe.Alignof unsafe.Offsetof unsafe.Sizeof unsafe.Slice
h(x+y)
f.Close()
<-ch
(<-ch)
len("foo")  // illegal if len is the built-in function

送信ステートメント

送信ステートメントは、チャネルに値を送信します。チャネル式はチャネル型である必要があり、チャネルの方向は送信操作を許可する必要があり、送信される値の型はチャネルの要素型に代入可能である必要があります。

SendStmt = Channel "<-" Expression .
Channel  = Expression .

チャネル式と値式の両方が、通信が開始される前に評価されます。送信が続行できるまで、通信はブロックされます。受信機が準備できている場合、バッファリングされていないチャネルでの送信を続行できます。バッファ付きチャネルでの送信は、バッファに空きがある場合に続行できます。閉じられたチャネルへの送信は、ランタイムパニックを引き起こすことで続行されます。nilチャネルへの送信は永久にブロックされます。

ch <- 3  // send value 3 to channel ch

IncDecステートメント

"++"および"--"ステートメントは、型なしの定数1によってオペランドをインクリメントまたはデクリメントします。代入と同様に、オペランドはアドレス指定可能であるか、マップインデックス式である必要があります。

IncDecStmt = Expression ( "++" | "--" ) .

次の代入ステートメントは意味的に同等です

IncDec statement    Assignment
x++                 x += 1
x--                 x -= 1

代入

Assignment = ExpressionList assign_op ExpressionList .

assign_op = [ add_op | mul_op ] "=" .

左辺の各オペランドは、アドレス指定可能、マップインデックス式、または(=代入のみの場合)ブランク識別子である必要があります。オペランドは括弧で囲むことができます。

x = 1
*p = f()
a[i] = 23
(k) = <-ch  // same as: k = <-ch

代入演算x op= yopがバイナリの算術演算子である場合)は、x = x op (y)と同等ですが、xを1回だけ評価します。op=構成は、単一のトークンです。代入演算では、左辺と右辺の式リストの両方に、単一値の式が1つだけ含まれている必要があり、左辺の式はブランク識別子であってはなりません。

a[i] <<= 2
i &^= 1<<n

タプル代入は、多値演算の個々の要素を変数のリストに代入します。これには2つの形式があります。最初の形式では、右辺のオペランドは、関数呼び出し、チャネルマップ操作、または型アサーションなどの単一の多値式です。左辺のオペランドの数は、値の数と一致する必要があります。例えば、fが2つの値を返す関数である場合、

x, y = f()

最初の値をxに、2番目の値をyに代入します。2番目の形式では、左辺のオペランドの数は右辺の式の数と等しくなければならず、それぞれが単一値でなければならず、右辺のn番目の式が左辺のn番目のオペランドに代入されます

one, two, three = '一', '二', '三'

ブランク識別子は、代入で右辺の値を無視する方法を提供します

_ = x       // evaluate x but ignore it
x, _ = f()  // evaluate f() but ignore second result value

代入は2つのフェーズで進行します。まず、左辺のインデックス式ポインタの間接参照セレクタにおける暗黙的なポインタの間接参照を含む)のオペランドと、右辺の式はすべて、通常の順序で評価されます。次に、代入は左から右の順に実行されます。

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 == []int{3, 5, 3}

代入では、それぞれの値は、代入されるオペランドの型に代入可能でなければなりません。ただし、次の特殊なケースがあります。

  1. 任意の型付きの値は、ブランク識別子に代入できます。
  2. 型なしの定数がインターフェース型の変数またはブランク識別子に代入される場合、定数は最初に暗黙的に変換され、そのデフォルト型になります。
  3. 型なしのブール値がインターフェース型の変数またはブランク識別子に代入される場合、最初に暗黙的にbool型に変換されます。

If文

"If"文は、ブール式の値に応じて2つの分岐の条件付き実行を指定します。式がtrueと評価される場合、"if"分岐が実行されます。それ以外の場合、"else"分岐が存在すれば、それが実行されます。

IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
if x > max {
	x = max
}

式の前には、式が評価される前に実行される単純な文を記述できます。

if x := f(); x < y {
	return x
} else if x > z {
	return z
} else {
	return y
}

Switch文

"Switch"文は、多方向の実行を提供します。式または型が"switch"内部の"case"と比較され、どの分岐を実行するかが決定されます。

SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .

式スイッチと型スイッチの2つの形式があります。式スイッチでは、caseにはswitch式の値と比較される式が含まれます。型スイッチでは、caseには、特別なアノテーション付きのswitch式の型と比較される型が含まれます。switch式は、switch文の中で正確に1回評価されます。

式スイッチ

式スイッチでは、switch式が評価され、定数である必要のないcase式が左から右、上から下の順に評価されます。最初にswitch式と等しくなったものが、関連するcaseの文の実行をトリガーします。他のcaseはスキップされます。一致するcaseがなく、"default" caseがある場合は、その文が実行されます。"default" caseは最大で1つ存在でき、"switch"文のどこにでも記述できます。switch式が欠落している場合は、ブール値trueと同等です。

ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
ExprCaseClause = ExprSwitchCase ":" StatementList .
ExprSwitchCase = "case" ExpressionList | "default" .

switch式が型なしの定数と評価される場合、最初に暗黙的に変換され、そのデフォルト型になります。事前宣言された型なしの値nilは、switch式として使用できません。switch式の型は比較可能である必要があります。

case式が型なしの場合、最初に暗黙的に変換され、switch式の型になります。各(場合によっては変換された)case式xとswitch式の値tについて、x == tは有効な比較でなければなりません。

言い換えれば、switch式は、明示的な型なしの一時変数tを宣言して初期化するために使用されたかのように扱われます。各case式xが等価性のためにテストされるのは、tの値です。

caseまたはdefault句では、最後の空でない文は、この句の終わりから次の句の最初の文に制御を移すことを示す(場合によってはラベル付けされた"fallthrough"文である可能性があります。それ以外の場合、制御は"switch"文の終わりに移ります。"fallthrough"文は、式スイッチの最後の句を除くすべて句の最後の文として記述できます。

switch式の前には、式が評価される前に実行される単純な文を記述できます。

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()
}

実装上の制限:コンパイラは、複数のcase式が同じ定数と評価されるのを許可しない場合があります。たとえば、現在のコンパイラは、case式での整数、浮動小数点数、または文字列定数の重複を許可しません。

型スイッチ

型スイッチは、値ではなく型を比較します。それ以外の場合は、式スイッチに似ています。型スイッチは、実際の型ではなくキーワードtypeを使用した型アサーションの形式を持つ特別なswitch式によってマークされます。

switch x.(type) {
// cases
}

ケースは、式xの動的な型に対して実際の型Tを照合します。型アサーションと同様に、xインターフェース型である必要があり、caseにリストされている各非インターフェース型Txの型を実装する必要があります。型スイッチのケースにリストされている型は、すべて異なる必要があります。

TypeSwitchStmt  = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .
TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
TypeCaseClause  = TypeSwitchCase ":" StatementList .
TypeSwitchCase  = "case" TypeList | "default" .
TypeList        = Type { "," Type } .

TypeSwitchGuardには、短縮変数宣言を含めることができます。この形式を使用する場合、変数は各句の暗黙的なブロックのTypeSwitchCaseの最後に宣言されます。正確に1つの型をリストするcaseを持つ句では、変数はその型を持ちます。それ以外の場合、変数はTypeSwitchGuardの式の型を持ちます。

型ではなく、caseは事前宣言された識別子nilを使用できます。このcaseは、TypeSwitchGuardの式がnilインターフェース値の場合に選択されます。nil caseは最大で1つ存在できます。

interface{}の式xが与えられた場合、次の型スイッチ

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")
	}
}

型スイッチガードの前には、ガードが評価される前に実行される単純な文を記述できます。

"fallthrough"文は型スイッチでは許可されていません。

For文

"for"文は、ブロックの繰り返し実行を指定します。3つの形式があります。反復は、単一の条件、"for"句、または"range"句によって制御できます。

ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
Condition = Expression .

単一の条件を持つFor文

最も単純な形式では、"for"文は、ブール条件がtrueと評価される限り、ブロックの繰り返し実行を指定します。条件は各反復の前に評価されます。条件がない場合、ブール値trueと同等です。

for a < b {
	a *= 2
}

for句を持つFor文

ForClauseを持つ"for"文もその条件によって制御されますが、さらに、代入、インクリメントまたはデクリメント文などのinit文とpost文を指定できます。init文は短縮変数宣言にできますが、post文はできません。init文で宣言された変数は、各反復で再利用されます。

ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
InitStmt = SimpleStmt .
PostStmt = SimpleStmt .
for i := 0; i < 10; i++ {
	f(i)
}

空でない場合、init文は最初の反復の条件を評価する前に1回実行されます。post文は、ブロックの各実行後(およびブロックが実行された場合にのみ)に実行されます。ForClauseの要素は空にすることができますが、条件のみの場合を除き、セミコロンが必要です。条件がない場合は、ブール値trueと同等です。

for cond { S() }    is the same as    for ; cond ; { S() }
for      { S() }    is the same as    for true     { S() }

range句を持つFor文

"range"句を持つ"for"文は、配列、スライス、文字列、マップのすべてのエントリ、またはチャネルで受信された値を反復処理します。各エントリについて、反復値が対応する反復変数(存在する場合)に割り当てられ、その後、ブロックが実行されます。

RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .

"range"句の右側の式は、range式と呼ばれ、配列、配列へのポインタ、スライス、文字列、マップ、または受信操作を許可するチャネルにすることができます。代入と同様に、左側のオペランド(存在する場合)はアドレス指定可能またはマップのインデックス式である必要があります。これらは反復変数を表します。range式がチャネルの場合、最大で1つの反復変数が許可されます。それ以外の場合は、最大で2つの反復変数が許可されます。最後の反復変数がブランク識別子である場合、range句は、その識別子なしの同じ句と同等です。

range式xは、ループの開始前に1回評価されます。ただし、最大で1つの反復変数があり、len(x)定数である場合、range式は評価されません。

左側の関数呼び出しは、反復ごとに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
  1. 配列、配列へのポインタ、またはスライス値aの場合、インデックス反復値は、要素インデックス0から始まる昇順で生成されます。最大で1つの反復変数がある場合、範囲ループは0からlen(a)-1までの反復値を生成し、配列またはスライス自体にインデックスを付けません。nilスライスの場合は、反復回数は0です。
  2. 文字列値の場合、"range"句は、バイトインデックス0から始まる文字列内のUnicodeコードポイントを反復処理します。後続の反復では、インデックス値は、文字列内の後続のUTF-8エンコードされたコードポイントの最初のバイトのインデックスになり、2番目の値(rune型)は、対応するコードポイントの値になります。反復が無効なUTF-8シーケンスを検出した場合、2番目の値は0xFFFD(Unicode代替文字)になり、次の反復では文字列内の単一のバイトを進めます。
  3. マップに対する反復順序は指定されておらず、反復ごとに同じであるとは保証されていません。まだ到達していないマップエントリが反復中に削除された場合、対応する反復値は生成されません。マップエントリが反復中に作成された場合、そのエントリは反復中に生成されるか、スキップされる可能性があります。選択は、作成された各エントリと反復ごとに異なる場合があります。マップがnilの場合、反復回数は0です。
  4. チャネルの場合、生成される反復値は、チャネルが閉じられるまでチャネルで送信される連続した値です。チャネルがnilの場合、range式は永久にブロックされます。

反復値は、代入文のように、それぞれの反復変数に割り当てられます。

反復変数は、短縮変数宣言:=)の形式を使用して、"range"句で宣言できます。この場合、それらの型はそれぞれの反復値の型に設定され、それらのスコープは"for"文のブロックです。それらは各反復で再利用されます。反復変数が"for"文の外で宣言されている場合、実行後、それらの値は最後の反復の値になります。

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 {}

Go文

"go"文は、同じアドレス空間内で、独立した並行制御スレッド(またはgoroutine)として関数呼び出しの実行を開始します。

GoStmt = "go" Expression .

式は関数またはメソッドの呼び出しである必要があります。括弧で囲むことはできません。組み込み関数の呼び出しは、式文の場合と同様に制限されます。

関数値とパラメータは、呼び出し元のゴルーチンで通常どおりに評価されますが、通常の呼び出しとは異なり、プログラムの実行は、呼び出された関数が完了するのを待ちません。代わりに、関数は新しいゴルーチンで独立して実行を開始します。関数が終了すると、そのゴルーチンも終了します。関数が戻り値を持つ場合、関数が完了すると破棄されます。

go Server()
go func(ch chan<- bool) { for { sleep(10); ch <- true }} (c)

Select文

"select"文は、一連の可能な送信または受信操作のうち、どれを進めるかを選択します。"switch"文に似ていますが、ケースはすべて通信操作を参照します。

SelectStmt = "select" "{" { CommClause } "}" .
CommClause = CommCase ":" StatementList .
CommCase   = "case" ( SendStmt | RecvStmt ) | "default" .
RecvStmt   = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
RecvExpr   = Expression .

RecvStmtを持つcaseは、RecvExprの結果を1つまたは2つの変数に割り当てることができ、これらの変数は短縮変数宣言を使用して宣言できます。RecvExprは(場合によっては括弧で囲まれた)受信操作である必要があります。最大で1つのdefault caseが存在でき、caseのリストのどこにでも記述できます。

"select"文の実行は、いくつかのステップで進行します

  1. ステートメント内のすべての場合において、"select" ステートメントに入るとき、受信操作のチャネルオペランド、および送信ステートメントのチャネルと右辺の式は、ソース順に正確に1回評価されます。その結果、受信または送信するチャネルのセットと、送信する対応する値が得られます。その評価における副作用は、どの(もしあれば)通信操作が選択されて実行されるかにかかわらず発生します。短い変数宣言または代入を伴う RecvStmt の左辺の式はまだ評価されません。
  2. 1つ以上の通信が実行可能な場合、実行可能なものが均一な擬似ランダム選択によって1つ選択されます。それ以外の場合、default ケースがある場合は、そのケースが選択されます。default ケースがない場合、"select" ステートメントは、少なくとも1つの通信が実行可能になるまでブロックされます。
  3. 選択されたケースが default ケースでない限り、それぞれの通信操作が実行されます。
  4. 選択されたケースが短い変数宣言または代入を伴う RecvStmt である場合、左辺の式が評価され、受信した値(または複数の値)が代入されます。
  5. 選択されたケースのステートメントリストが実行されます。

nil チャネルでの通信は決して実行できないため、nil チャネルのみで default ケースがない 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 ステートメント

関数 F 内の "return" ステートメントは、F の実行を終了し、オプションで1つ以上の結果値を指定します。F によって 遅延 された関数は、F が呼び出し元に返る前に実行されます。

ReturnStmt = "return" [ ExpressionList ] .

結果の型がない関数では、"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 ステートメント

"break" ステートメントは、同じ関数内の最も内側の "for""switch"、または "select" ステートメントの実行を終了します。

BreakStmt = "break" [ Label ] .

ラベルがある場合、それは囲んでいる "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 ステートメント

"continue" ステートメントは、最も内側の "for" ループ の次の反復を、そのpostステートメントで開始します。"for" ループは同じ関数内にある必要があります。

ContinueStmt = "continue" [ Label ] .

ラベルがある場合、それは囲んでいる "for" ステートメントのラベルである必要があり、それが実行を進めるものです。

RowLoop:
	for y, row := range rows {
		for x, data := range row {
			if data == endOfRow {
				continue RowLoop
			}
			row[x] = data + bias(x, y)
		}
	}

goto ステートメント

"goto" ステートメントは、同じ関数内の対応するラベルを持つステートメントに制御を移します。

GotoStmt = "goto" Label .
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 ステートメント

"fallthrough" ステートメントは、式 "switch" ステートメント の次の case 句の最初のステートメントに制御を移します。これは、そのような句の最後の空でないステートメントとしてのみ使用できます。

FallthroughStmt = "fallthrough" .

defer ステートメント

"defer" ステートメントは、囲んでいる関数が return ステートメント を実行したか、その 関数本体 の最後に到達したか、または対応するゴルーチンが パニック を起こしたかのいずれかの理由で、囲んでいる関数が返される瞬間に実行が遅延される関数を呼び出します。

DeferStmt = "defer" Expression .

式は関数またはメソッドの呼び出しである必要があります。括弧で囲むことはできません。組み込み関数の呼び出しは、式文の場合と同様に制限されます。

"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
}

組み込み関数

組み込み関数は 事前宣言 されています。これらは他の関数のように呼び出されますが、一部は最初の引数として式ではなく型を受け入れます。

組み込み関数には標準の Go 型がないため、呼び出し式 にのみ現れる可能性があります。関数値として使用することはできません。

Close

チャネル c の場合、組み込み関数 close(c) は、チャネルでそれ以上値が送信されないことを記録します。c が受信専用チャネルの場合、エラーになります。クローズされたチャネルへの送信またはクローズは、実行時パニック を引き起こします。nil チャネルをクローズした場合も、実行時パニック を引き起こします。close を呼び出した後、および以前に送信された値がすべて受信された後、受信操作はブロックせずにチャネルの型のゼロ値を返します。多値の 受信操作 は、チャネルが閉じられているかどうかを示すとともに、受信した値を返します。

長さと容量

組み込み関数 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

cap(s)    [n]T, *[n]T      array length (== n)
          []T              slice capacity
          chan T           channel buffer capacity

スライスの容量は、基になる配列にスペースが割り当てられている要素の数です。常に次の関係が成り立ちます

0 <= len(s) <= cap(s)

nil スライス、マップ、またはチャネルの長さは 0 です。nil スライスまたはチャネルの容量は 0 です。

s が文字列定数の場合、式 len(s)定数 です。s の型が配列または配列へのポインターであり、式 sチャネル受信 または(定数ではない) 関数呼び出し が含まれていない場合、式 len(s) および cap(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

割り当て

組み込み関数 new は型 T を取り、実行時にその型の 変数 のストレージを割り当て、それへの ポインターである型 *T の値を返します。変数は、初期値に関するセクションで説明されているように初期化されます。

new(T)

たとえば

type S struct { a int; b float64 }
new(S)

は、S 型の変数のストレージを割り当て、初期化し(a=0b=0.0)、場所のアドレスを含む *S 型の値を返します。

スライス、マップ、およびチャネルの作成

組み込み関数 make は、型 T を取り、これはスライス、マップ、またはチャネル型である必要があり、オプションで型固有の式のリストが続きます。T 型(*T ではない)の値を返します。メモリは、初期値に関するセクションで説明されているように初期化されます。

Call             Type T     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

サイズ引数 nm はそれぞれ、整数型または型指定のない 定数 である必要があります。定数サイズ引数は負ではなく、int 型の値で 表現可能 である必要があります。型指定のない定数の場合、int 型が与えられます。nm の両方が指定され、定数である場合、nm より大きくない必要があります。実行時に 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 個のマップ要素を保持するための初期スペースを持つマップが作成されます。正確な動作は実装によって異なります。

スライスの追加とコピー

組み込み関数 append および copy は、一般的なスライス操作を支援します。両方の関数について、結果は引数によって参照されるメモリが重複するかどうかには依存しません。

可変長引数 関数 append は、0個以上の値 x を型 Ss に追加します。これはスライス型である必要があり、結果のスライスも型 S で返します。値 x は、TS要素型であり、それぞれの パラメータ受け渡しルール が適用される型 ...T のパラメータに渡されます。特別なケースとして、append は、文字列型の2番目の引数の後に ... が続く型 []byte に代入可能な最初の引数も受け入れます。この形式は、文字列のバイトを追加します。

append(s S, x ...T) S  // T is the element type of S

s の容量が追加の値に適合するほど大きくない場合、append は既存のスライス要素と追加の両方に適合する新しい、十分に大きい基になる配列を割り当てます。それ以外の場合、append は基になる配列を再利用します。

s0 := []int{0, 0}
s1 := append(s0, 2)                // append a single element     s1 == []int{0, 0, 2}
s2 := append(s1, 3, 5, 7)          // append multiple elements    s2 == []int{0, 0, 2, 3, 5, 7}
s3 := append(s2, s0...)            // append a slice              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
s4 := append(s3[3:6], s3[2:]...)   // append overlapping slice    s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}

var t []interface{}
t = append(t, 42, 3.1415, "foo")   //                             t == []interface{}{42, 3.1415, "foo"}

var b []byte
b = append(b, "bar"...)            // append string contents      b == []byte{'b', 'a', 'r' }

関数 copy は、ソース src から宛先 dst にスライス要素をコピーし、コピーされた要素の数を返します。両方の引数は 同一 の要素型 T を持ち、型 []T のスライスに 代入可能 である必要があります。コピーされる要素の数は、len(src)len(dst) の最小値です。特別なケースとして、copy は、文字列型のソース引数を持つ型 []byte に代入可能な宛先引数も受け入れます。この形式は、文字列からバイトスライスにバイトをコピーします。

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 == []int{0, 1, 2, 3, 4, 5}
n2 := copy(s, s[2:])            // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
n3 := copy(b, "Hello, World!")  // n3 == 5, b == []byte("Hello")

マップ要素の削除

組み込み関数 delete は、マップ m からキー k を持つ要素を削除します。k の型は、m のキー型に代入可能でなければなりません。

delete(m, k)  // remove element m[k] from map m

マップ mnil の場合、または要素 m[k] が存在しない場合、delete は何もしません。

複素数の操作

3つの関数が複素数を組み立てたり分解したりします。組み込み関数 complex は、浮動小数点の実数部と虚数部から複素数を構成し、realimag は複素数の実数部と虚数部を抽出します。

complex(realPart, imaginaryPart floatT) complexT
real(complexT) floatT
imag(complexT) floatT

引数と戻り値の型は対応しています。complex の場合、2つの引数は同じ浮動小数点型でなければならず、戻り値の型は対応する浮動小数点構成要素を持つ複素数型です。つまり、float32 の引数には complex64 が、float64 の引数には complex128 が返されます。引数のいずれかが型なし定数として評価される場合、まず他方の引数の型に暗黙的に変換されます。両方の引数が型なし定数として評価される場合、それらは非複素数であるか、または虚数部がゼロでなければならず、関数の戻り値は型なし複素数定数です。

realimag の場合、引数は複素数型でなければならず、戻り値の型は対応する浮動小数点型です。つまり、complex64 の引数には float32 が、complex128 の引数には float64 が返されます。引数が型なし定数として評価される場合、それは数値でなければならず、関数の戻り値は型なし浮動小数点定数です。

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

パニックの処理

2つの組み込み関数、panicrecover は、ランタイムパニックとプログラム定義のエラー状態の報告と処理を支援します。

func panic(interface{})
func recover() interface{}

関数 F の実行中に、panic の明示的な呼び出しまたはランタイムパニックが発生すると、F の実行は終了します。F によって遅延された関数は、通常どおり実行されます。次に、F の呼び出し元によって実行された遅延関数が実行され、実行中のゴルーチンの一番上のレベルの関数によって遅延された関数まで同様に実行されます。その時点で、プログラムは終了し、panic への引数の値を含むエラー状態が報告されます。この終了シーケンスはパニックと呼ばれます。

panic(42)
panic("unreachable")
panic(Error("cannot parse"))

recover 関数を使用すると、プログラムはパニックが発生したゴルーチンの動作を管理できます。関数 Grecover を呼び出す関数 D を遅延させ、G が実行されている同じゴルーチン上の関数でパニックが発生したとします。遅延関数の実行が D に到達すると、Drecover の呼び出しの戻り値は、panic の呼び出しに渡された値になります。D が新しい panic を開始せずに正常にリターンした場合、パニックシーケンスは停止します。その場合、Gpanic の呼び出しの間で呼び出された関数の状態は破棄され、通常の実行が再開されます。D より前に G によって遅延された関数は実行され、G の実行は呼び出し元にリターンして終了します。

次のいずれかの条件が満たされる場合、recover の戻り値は 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

実装上の制限:printprintln は任意の引数型を受け入れる必要はありませんが、ブール値、数値、および文字列の印刷はサポートされている必要があります。

パッケージ

Goプログラムは、パッケージをリンクすることによって構成されます。パッケージは、パッケージに属する定数、型、変数、および関数を宣言し、同じパッケージのすべてのファイルでアクセスできる1つまたは複数のソースファイルから構成されます。これらの要素はエクスポートされ、別のパッケージで使用できます。

ソースファイル構成

各ソースファイルは、それが属するパッケージを定義するパッケージ句、それに続く使用したいパッケージの内容を宣言する空である可能性のあるインポート宣言のセット、および関数、型、変数、および定数の空である可能性のある宣言のセットで構成されています。

SourceFile       = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .

パッケージ句

パッケージ句は各ソースファイルの先頭にあり、ファイルが属するパッケージを定義します。

PackageClause  = "package" PackageName .
PackageName    = identifier .

PackageName は、ブランク識別子であってはなりません。

package math

同じ PackageName を共有するファイルのセットは、パッケージの実装を形成します。実装では、パッケージのすべてのソースファイルが同じディレクトリに存在することが要求される場合があります。

インポート宣言

インポート宣言は、宣言を含むソースファイルがインポートされたパッケージの機能に依存していることを示し(§プログラムの初期化と実行)、そのパッケージのエクスポートされた識別子へのアクセスを可能にします。インポートは、アクセスに使用する識別子(PackageName)と、インポートするパッケージを指定する ImportPath を名前付けします。

ImportDecl       = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec       = [ "." | PackageName ] ImportPath .
ImportPath       = string_lit .

PackageName は、インポート元のソースファイル内で、パッケージのエクスポートされた識別子にアクセスするために、修飾された識別子で使用されます。これは、ファイルブロックで宣言されます。PackageName が省略された場合、インポートされたパッケージのパッケージ句で指定された識別子がデフォルトで使用されます。名前の代わりに明示的なピリオド (.) が表示された場合、そのパッケージのパッケージブロックで宣言されたパッケージのエクスポートされたすべての識別子は、インポート元のソースファイルのファイルブロックで宣言され、修飾子なしでアクセスする必要があります。

ImportPath の解釈は実装に依存しますが、通常はコンパイルされたパッケージの完全なファイル名のサブストリングであり、インストールされたパッケージのリポジトリに対する相対パスである可能性があります。

実装上の制限:コンパイラは、ImportPaths を、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 です。この初期化は再帰的に行われるため、たとえば構造体の配列の各要素は、値が指定されていない場合、フィールドがゼロになります。

次の2つの単純な宣言は同等です

var i int
var i int = 0

type T struct { i int; f float64; next *T }
t := new(T)

以下が成り立ちます

t.i == 0
t.f == 0.0
t.next == nil

以下の場合も同じです

var t T

パッケージの初期化

パッケージ内では、パッケージレベルの変数の初期化は段階的に進み、各ステップで、初期化されていない変数に依存しない宣言順で最も早い変数が選択されます。

より正確には、パッケージレベルの変数は、まだ初期化されておらず、初期化式がないか、またはその初期化式が初期化されていない変数への依存関係がない場合に、初期化の準備ができていると見なされます。初期化は、宣言順で最も早く、初期化の準備ができている次のパッケージレベルの変数を繰り返し初期化することによって進められ、初期化の準備ができている変数がなくなるまで続きます。

このプロセスが終了したときにまだ初期化されていない変数がある場合、それらの変数は1つ以上の初期化サイクルの一部であり、プログラムは無効になります。

右辺の単一(多値)式によって初期化された変数宣言の左辺にある複数の変数は、一緒に初期化されます。左辺のいずれかの変数が初期化される場合、これらのすべての変数は同じステップで初期化されます。

var x = a
var a, b = f() // a and b are initialized together, before x is initialized

パッケージの初期化の目的では、ブランク変数は、宣言内の他の変数と同じように扱われます。

複数のファイルで宣言された変数の宣言順は、ファイルがコンパイラに提示される順序によって決定されます。最初のファイルで宣言された変数は、2番目のファイルで宣言されたどの変数よりも前に宣言され、以下同様です。

依存関係分析は、変数の実際の値に依存するのではなく、ソース内の変数の字句参照にのみ依存し、推移的に分析されます。たとえば、変数 x の初期化式が、変数 y を参照する本体を持つ関数を参照している場合、xy に依存します。具体的には

例えば、次の宣言が与えられたとします。

var (
	a = c + b  // == 9
	b = f()    // == 4
	c = f()    // == 5
	d = 3      // == 5 after initialization has finished
)

func f() int {
	d++
	return d
}

初期化順序は、dbca です。初期化式における部分式の順序は無関係であることに注意してください。a = c + ba = 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} }

変数 ab の後に初期化されますが、xb の前に初期化されるか、ba の間に初期化されるか、a の後に初期化されるか、したがって sideEffect() が呼び出されるタイミング(x が初期化される前か後か)も指定されていません。

変数は、引数と戻り値のパラメータを持たないパッケージブロックで宣言された init という名前の関数を使用して初期化することもできます。

func init() { … }

パッケージごとに複数のそのような関数を定義でき、単一のソースファイル内でも可能です。パッケージブロック内では、init識別子はinit関数を宣言するためだけに使用できますが、識別子自体は宣言されていません。したがって、init関数はプログラム内のどこからも参照できません。

インポートを持たないパッケージは、すべてのパッケージレベルの変数に初期値を割り当て、その後にソースに現れる順序(複数のファイルにまたがる可能性あり)で、コンパイラに提示されたすべてのinit関数を呼び出すことによって初期化されます。パッケージにインポートがある場合、インポートされたパッケージは、パッケージ自体を初期化する前に初期化されます。複数のパッケージが1つのパッケージをインポートする場合、インポートされたパッケージは1回だけ初期化されます。パッケージのインポートは、構造上、循環的な初期化依存関係が存在しないことを保証します。

パッケージの初期化(変数の初期化とinit関数の呼び出し)は、単一のゴルーチン内で、順番に、一度に1つのパッケージずつ実行されます。init関数は他のゴルーチンを起動する可能性があり、それらは初期化コードと並行して実行できます。ただし、初期化は常にinit関数を順番に実行します。前の関数が戻るまで、次の関数を呼び出すことはありません。

再現可能な初期化動作を保証するために、ビルドシステムは、同じパッケージに属する複数のファイルを、字句的なファイル名順にコンパイラに提示することを推奨します。

プログラムの実行

完全なプログラムは、メインパッケージと呼ばれる、インポートされない単一のパッケージを、それが推移的にインポートするすべてのパッケージとリンクすることによって作成されます。メインパッケージは、パッケージ名がmainであり、引数を取らず、値を返さない関数mainを宣言する必要があります。

func 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は、型システムに違反する操作を含む、低レベルプログラミングのための機能を提供します。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

Pointerポインタ型ですが、Pointerの値は間接参照できません。基になる型uintptrである任意のポインタまたは値は、基になる型がPointerである型に変換でき、その逆も可能です。Pointeruintptr間の変換の効果は、実装定義です。

var f float64
bits = *(*uint64)(unsafe.Pointer(&f))

type ptr unsafe.Pointer
bits = *(*uint64)(ptr(&f))

var p ptr = nil

関数AlignofSizeofは、任意の型の式xを取り、vvar v = xで宣言されたかのように、仮想変数vのアライメントまたはサイズをそれぞれ返します。

関数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

AlignofOffsetof、およびSizeofへの呼び出しは、uintptr型のコンパイル時定数式です。

関数Addは、lenptrに追加し、更新されたポインタunsafe.Pointer(uintptr(ptr) + uintptr(len))を返します。len引数は、整数型または型指定なしの定数である必要があります。定数len引数は、int型の値で表現可能である必要があります。型指定なしの定数の場合は、int型が与えられます。Pointer有効な使用法に関する規則は引き続き適用されます。

関数Sliceは、基になる配列がptrから始まり、長さと容量がlenであるスライスを返します。Slice(ptr, len)は以下と同等です。

(*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]

ただし、特別なケースとして、ptrnillenがゼロの場合、Slicenilを返します。

len引数は、整数型または型指定なしの定数である必要があります。定数len引数は、非負であり、int型の値で表現可能である必要があります。型指定なしの定数の場合は、int型が与えられます。実行時に、lenが負の場合、またはptrnillenがゼロでない場合、実行時パニックが発生します。

サイズとアライメントの保証

数値型については、次のサイズが保証されています。

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)は、配列の要素型の変数のアライメントと同じです。

構造体型または配列型は、サイズがゼロより大きいフィールド(または要素)をそれぞれ含まない場合、サイズがゼロです。2つの異なるゼロサイズの変数は、メモリ内で同じアドレスを持つ可能性があります。