gospec-ja

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

Build Status

本文書は,The Go Programming Language Specification version 2021/02/10 のなんちゃって日本語訳である.

訳注

訳注:記号 | 記号 | 日本語(本文) | 英語(原文) | | :——-: | :————— | :——————- | | _ | アンダースコア | underscore character | | ' | シングルクォート | single quote | | " | ダブルクォート | double quote | | ` | バッククォート | back quote | | \ | バックスラッシュ | backslash | | () | 丸括弧 | parentheses | | {} | 波括弧 | brace brackets | | [] | 角括弧 | square brackets |

目次

イントロダクション

本文書は Go プログラミング言語のリファレンスマニュアルである. 他の情報源としては,golang.org を参照されたい.

Go はシステムプログラミングを念頭において設計された,汎用言語である. 強い型付け,ガベージコレクションを持ち,並行プログラミング (concurrent programming) を明示的にサポートしている. プログラムは, 性質が依存関係の効率的な管理を実現するパッケージ (package) で構成される.

文法はコンパクト,かつ,解析が単純であり, 統合開発環境などの自動ツールによる簡易な解析が可能になる.

表記

構文は,Extended Backus-Naur Form(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 "}" .

Production は, Term と以下の演算子によって構成される式 (expression) である. 以下の演算子は優先順位の昇順に記載している.

|   代替 (alternation)
()  グループ化 (grouping)
[]  オプション (0 回か 1 回)
{}  繰り返し (0 回から n 回)

小文字の Production 名 (production_name) は,字句トークンを識別するために使用する. 非終端はキャメルケース (訳注: CamelCase のように複合語を一綴りとして,要素語の最初を大文字にする) である. 字句トークンはダブルクォーテーション "" またはバッククォート `` で囲む.

形式 a … b は,a から b の文字の集合の代替に使用する. 三点リーダー (horizontal ellipsis) は, 本仕様の他の場所でも,ここで指定していない列挙やコードスニペットを非公式に表すために使用する. 文字 (3文字 ... とは対照的に) は Go言語のトークンではない.

ソースコード表現

ソースコードは UTF-8 でエンコードされた Unicode テキストである. テキストは正規化(canonicalized)されていない. そのため,単一のアクセント付き符号位置は, アクセントと英字を組み合わせて構築される同じ文字と区別される. これらは,2 つの符号位置として扱われる. 単純にするために, 本文書では, 修飾されてない用語の文字 (character) をソーステキスト内の Unicode 符号位置を参照するために使用する.

各符号位置 (code point) は区別され,例えば,大文字と小文字の英字は異なる文字として扱われる.

実装上の制限: 他のツールとの互換性のために, コンパイラはソースコード上で NUL 文字 (U+0000) を許可しない場合がある.

実装上の制限: 他のツールとの互換性のために, コンパイラは,UTF-8でエンコードされたバイトオーダーマーク (BOM) (U+FEFF) がソースコード上の最初の Unicode 符号位置であるときに無視できる. バイトオーダーマークは,ソース内の他の場所では許可されない場合がある.

文字 (characters)

以下の項 (term) は, 特定の Unicode 文字クラス (character class) を示すために使用する.

newline        = /* Unicode 符号位置 (code point) U+000A */ .
unicode_char   = /* 任意の newline を除いた Unicode 符号位置 */ .
unicode_letter = /* "文字 / Letter" に分類される符号位置 */ .
unicode_digit  = /* "数, 10進数 / Number, decimal digit" に分類される符号位置 */ .

The Unicode Standard 8.0 では, 4.5節 “General Category” 節は文字カテゴリの集合を定義する. Go は,英字カテゴリの Lu, Ll, Lt, Lm, Lo に属するすべての文字を Unicode 英字として扱い, 数字カテゴリ Nd に属する文字を Unicode 数字として扱う.

訳注:

value Category Major, minor カテゴリー
Lu Letter, uppercase 文字,大文字 A,B,C,…
Ll Letter, lowercase 文字,小文字 a,b,c,…
Lt Letter, titlecase 文字,タイトル文字
Lm Letter, modifier 文字,修飾
Lo Letter, other 文字,その他
Nd Number, decimal digit 数字,10進数字 0,1,…

英字と数字 (letters and digits)

アンダースコア文字 _ (U+005F) は, 英字 (letter) として考える.

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. 行コメント (line comment): 文字列 // から,行末まで
  2. 一般的なコメント (general comment): /* で始まり,最初の後続の */ まで.(訳注:入れ子不可 /* ABC /* DEF */ GHI */ では GHI はコメントではない)

コメントは,ルーン文字列リテラル内,または,コメント内では開始できない. 改行を含まない「一般的なコメント」はスペースのように機能する. 他のコメントは改行のように機能する.

トークン

トークンは Go言語の語彙を形成する. 識別子 (identifier), キーワード (keyword), 演算子 (operator) と区切り (punctuation), リテラル (literal) の 4 つのクラスがある. 空白 (U+0020), 水平タブ (U+0009), キャリッジ リターン (CR, U+000D), 改行文字 (ラインフィード,LF,U+000A) から形成される ホワイトスペースは, 単一に結合するであろうトークンを分離する場合を除いて無視される. また,改行文字とファイルの末尾はセミコロンを挿入するトリガーになる場合がある. 入力をトークンに分割する間, 次のトークンは有効なトークンを形成する最長の文字シーケンスである.

セミコロン

正式な文法では,セミコロン ; を多くの Production の終端として使用する. Goプログラムでは,次の 2 つの規則を利用して,多くの場合セミコロンを省略できる.

  1. 入力をトークンに分割するとき, 行の最後のトークンが以下の場合,その後ろにセミコロンが自動的に挿入される.
  2. 複雑な文が 1行を専有できるようにするために,セミコロンは閉じカッコ ), } の前では省略できる.

慣用的な使用を反映するために, 本ドキュメントのコード例では,これらの規則によりセミコロンを省略する.

識別子

識別子 (identify) は,変数 (variable) や型 (type) などのプログラムエンティティ (entity) に名付ける. 識別子は,1 つ以上の英字 (letter) と数字 (digit) の列である. 識別子は,英字から始まらなければならない.

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

演算子と区切り

以下の文字列は演算子 (代入演算子 (assignment operators) を含む) と区切り (punctuation) である.

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

整数リテラル

整数リテラル (integer literal) は, 整数定数を表現する数字の列である. オプションの接頭辞は, 非10進数を表現する. 0b0B は2進数, 0o0O は8進数, 0x0X は16進数を表現する. 単独の 0 は10進数のゼロとみなされる. 16進数では,英字 a-fA-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       // 2文字目は大文字 `O` である
0xBadFace
0xBad_Face
0x_67_7a_2f_cc_40_c6
170141183460469231731687303715884105727
170_141183_460469_231731_687303_715884_105727

_42         // 整数リテラルではなく,識別子
42_         // 無効: _ は連続する数字を区切る必要がある
4__2        // 無効: _ は一度にひとつのみ
0_xBadFace  // 無効: _ は連続する数字を区切る必要がある

浮動小数点リテラル

浮動小数点リテラルは,浮動小数点定数の10進数または16進数表現である.

10進浮動小数点リテラルは,整数部 (10進数),小数点,小数部 (10進数), 指数部 (e または E とオプションの符号,10進数)から成る. 整数部と小数部のどちらか一方は省略でき, 小数点と指数部のどちらか一方は省略できる. 指数値 exp は仮数 (整数部と小数部)を 10^{exp} 倍する.

16進数浮動小数点リテラルは,接頭 0x または 0X, 整数部 (16進数), 基数点 (radix point; 訳注 n進数小数点のこと), 小数部 (16進数), 指数部 (p または P とオプションの符号,10進数)から成る. 整数部と小数部のどちらか一方は省略できる. 基数点は省略できるが,指数部は必要である. (この構文は IEEE 754-2008 §5.12.3. で与えられる構文と一致) 指数値 exp は仮数 (整数部と小数部)を 2^{exp} 倍する.

読みやすさのため, アンダースコア _ が接頭辞の後ろ,または,続く数字との間に使用される場合がある. このアンダースコアは,リテラルの値を変更しない.

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        // 無効: 仮数部に数字がない
1p-2         // 無効: p 指数には 16進数仮数部が必要
0x1.5e-2     // 無効: 16進化数部は p 指数が必要
1_.5         // 無効: _ は連続する数字を区切る必要がある
1._5         // 無効: _ は連続する数字を区切る必要がある
1.5_e1       // 無効: _ は連続する数字を区切る必要がある
1.5e_1       // 無効: _ は連続する数字を区切る必要がある
1.5e1_       // 無効: _ は連続する数字を区切る必要がある

虚数リテラル

虚数リテラル (imaginary literal) は複素数定数の虚数部を表す. 虚数リテラルは,整数リテラルまたは浮動小数点リテラルと,その後ろに続く小文字英字 i から成る. 虚数リテラルの値は,それぞれ,整数リテラルまたは浮動小数点リテラルに虚数単位 i を乗じた値である.

imaginary_lit = (decimal_digits | int_lit | float_lit) "i" .

後方互換のため, 虚数リテラルの整数部 (および場合によってはアンダースコア) が 10進数のみで構成される場合は, 0 で始まっていたとしても 10進数と見なされる.

0i
0123i         // == 123i (後方互換のため)
0o123i        // == 0o123 * 1i == 83i
0xabci        // == 0xabc * 1i == 2748i
0.i
2.71828i
1.e+0i
6.67428e-11i
1E6i
.25i
.12345E+5i
0x1p-2i       // == 0x1p-2 * 1i == 0.25i

ルーンリテラル

ルーンリテラル (rune literal) は Unicode 符号位置を特定する整数値である ルーン定数を表現する. ルーンリテラルは,'x''\n' のようにシングルクォートで囲まれた 1つ以上の文字たちで表現される. シングルクォート内では, 改行とエスケープされていないシングルクォートを除く任意の文字を使用できる. シングルクォートで囲まれた1文字は,その文字自身の Unicode 値を表すが, バックスラッシュで始まる複数の文字たちの場合は, 様々な形式で値をエンコードする.

最もシンプルな形式は,シングルクォートで囲まれた単一の文字を表現する. Go のソーステキストは UTF-8 でエンコードされた Unicode 文字たちなので, 複数の UTF-8 エンコードバイトは,単一の整数値を表現する場合がある. 例えば,リテラル 'a' はリテラル a, Unicode U+0061,値 0x61 を保持し, 'ä' は 2バイト (0xc3 0xa4) は リテラル a-ウムラウト, U+00E4, 値 0xe4 を保持する.

いくつかのバックスラッシュエスケープたちにより, 任意の値を ASCII テキストとしてエンコードできる. 数定数として整数は 4 つの方法で表現できる: \x と正確に 2 桁の 16進数; \u と正確に 4 桁の 16進数; \U と正確に 8 桁の 16進数; 素のバックスラッシュ \ と正確に 3 桁の 8 進数. いずれの場合も,リテラルの値は,対応する基数の数字で表される値である.

これらの表現はすべて整数を表すが, 異なる有効範囲をもつ. 8進エスケープは 0 から 255 までの値を表さなければならない. 16進エスケープは,構成からこの条件を満足する. '\u''\U' のエスケープは Unicode 符号位置を表現するので, その中には不当な値, 特に 0x10FFFF より大きな値とサロゲートハーフたちが含まれる.

バックスラッシュの後,特定の一文字のエスケープは特別な値を表す:

\a   U+0007 アラート または ベル
\b   U+0008 バックスペース
\f   U+000C form feed
\n   U+000A ラインフィード (line feed) または ニューライン (newline)
\r   U+000D キャリッジリターン (carriage return)
\t   U+0009 水平タブ
\v   U+000b 垂直タブ
\\   U+005c バックスラッシュ
\'   U+0027 シングルクォート (ルーンリテラル内でのみ有効なエスケープ)
\"   U+0022 ダブルクォート (文字列リテラル内でのみ有効なエスケープ)

バックスラッシュで始まる他のすべての列は,ルーンリテラルの中では不当である.

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'
'\''         // シングルクォート文字を含むルーンリテラル
'aa'         // 不当: 文字が多すぎる
'\xa'        // 不当: 16進数桁数が少ない
'\0'         // 不当: 8進数の桁数が少ない
'\uDFFF'     // 不当: サロゲートハーフ
'\U00110000' // 不当: 無効な Unicode 符号位置

文字列リテラル

文字列リテラル (string literal) は, 文字の列を連結して得られる文字列定数を表現する. 生の文字列リテラル (raw string literal) と 解釈された文字列リテラル (interpreted string literal) の 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`                // "abc" と同じ
`\n
\n`                  // "\\n\n\\n" と同じ
"\n"
"\""                 // `"` と同じ
"Hello, world!\n"
"日本語"
"\u65e5\U00008a9e"
"\xff\u00FF"
"\uD800"             // 不当: サロゲートハーフ
"\U00110000"         // 不当: 無効な Unicode 符号位置

以下の例は,すべて同じ文字列の表現である.

"日本語"                                // UTF-8 入力テキスト
`日本語`                                // 生のリテラルとしての UTF-8 入力テキスト
"\u65e5\u672c\u8a9e"                    // 明示的な Unicode 符号位置
"\U000065e5\U0000672c\U00008a9e"        // 明示的な Unicode 符号位置
"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"  // 明示的な Unicode バイトたち

ソースコードが アクセントと文字を含む結合形式など, 2 つの符号位置として文字を表す場合, ルーンリテラル(単一の符号位置ではない)に配置すると, 結果はエラーとなり, 文字列リテラルに配置すると, 2 つの符号位置として使用される.

定数

ブール定数ルーン定数整数定数浮動小数点整数複素数定数文字列定数がある. ルーン定数,整数定数,浮動小数点定数,複素数定数を総称して,数値定数と呼ばれる.

定数値は,ルーンリテラル整数リテラル浮動小数点リテラル虚数リテラル文字列リテラル, 定数を表す識別子, 定数式, 結果が定数となる変換, 任意の値に適用される unsafe.Sizeofある式に適用される cap, len, 複素数定数に適用される real, imag, 数値定数に適用される complex のようなビルトイン関数の復帰値 によって表現される. ブール真偽値は 事前宣言された定数 truefalse によって表現される. 事前宣言された識別子 iota は整数定数を示す.

一般に,複素数定数は定数式の形式であり,その節で説明する.

数値定数は任意精度の正確な値を表現し, オーバーフローしない. したがって,IEEE-754 の負のゼロ,無限大,非数値 (NaN) を示す定数はない.

定数は,型付きでも,型なしでもいい. リテラル定数,true, false, iota, 型なし定数オペランドを含む定数式は, 型なしである.

定数は, 定数宣言定数変換によって 明示的に型を指定されるか, もしくは, 変数宣言代入で使用するか, のオペランドとして暗黙的に指定される. 定数値がそれぞれの型の値として表現されない場合には, エラーになる.

型なし定数は, デフォルトの型を持つ. デフォルトの型は, 例えば,明示的な型がない i := 0 のような簡潔な変数宣言では, 型付き変数が要求する コンテキストに暗黙的に変換される. 型なし定数のデフォルトの型は, 真偽値定数,ルーン定数,整数定数,浮動小数点定数,複素数定数,文字列定数はそれぞれ bool, rune, int, float64, complex128, string である.

実装上の制限: 数値定数は言語では任意精度を持つが, コンパイラは精度が制限された内部表現を使用して実装する場合がある. ただし,すべての実装は以下を満たす (MUST):

これらの要求は, リテラル定数と定数式の評価結果の両方に適用される.

変数

変数 (variable) は,を保持するための保管場所である. 許容値の集合は,変数のによって決まる.

変数宣言,または, 関数の引数と復帰値のための関数宣言関数リテラルのシグネチャーは, 名前付き変数の保管場所を予約する. ビルトイン関数 new の呼び出しや, 複合リテラル (composite literal) のアドレスの取得は, 実行時に変数の保管場所が割り当てられる. そのような無名変数 (anonymous variable) は, (暗黙の可能性もある) ポインター間接 (pointer indirection) 参照される.

配列 (array),スライス (slice), 構造体型構造化変数 (structured variable) は,個別にアドレス指定できる要素とフィールドがある. そのような各要素は変数のように機能する.

変数の静的な型 (static type) (または単に)は, その宣言で指定された型, new 呼び出しや複合リテラルによって与えられる型, 構造化変数の要素の型である. インターフェース型の変数もまた, 実行時に代入された値の具体的な型 (型を持たない事前宣言された識別子 nil の場合を除く) である 個別の動的な型 (dynamic type) がある. 動的な型は, 実行中に変化する可能性があるが, インターフェース変数に割り当てられた値は 常に変数の静的な型に代入可能 (assignable) である.

var x interface{}  // x は nil であり,静的な型 interface{} をもつ
var v *T           // v は nil であり,静的な型 *T をもつ
x = 42             // x は 値 42 を持ち,動的な型 int をもつ
x = v              // x 値 (*T)(nil) であり,動的な方 *T をもつ

変数の値は, に含まれる変数を参照することによって取得される; それは,変数に代入された最新の値である. 変数に値が割り当てられていない場合, その値は,その型のゼロ値である.

型 (type) は, オペレーションの値と, これらの値に指定されるメソッドの集合を決定する. 型は, 型名がある場合は型名 (type name) を示すか, 既存の型から構成される型リテラル (type literal) を使って 指定できる.

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

Go言語は,特定の型名を事前宣言 (predeclare)する. その他は,型宣言で導入される. 複合型 (配列型,構造体型,ポインター型,関数型,インターフェース型,スライス型,マップ型,チャンネル型) は型リテラルを使って構築できる.

各型 T基底型 (underlying type) をもつ. T が事前宣言されたブール型,数値型,文字列型の一つであるか, 型リテラルである場合, 対応する基底型は T 自身となる. それ以外の場合, T の基底型は T型宣言で参照する型の基底型である.

type (
	A1 = string
	A2 = A1
)

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

A1, A2, B1, B2 の基底型は文字列型である. []B1, B3, B4 の基底型は []B1 である.

訳注:本家のままだが,[]B1 は必要?

メソッド集合

型は, 型に関連付けられたメソッド集合 (method set)がある場合がある. インターフェース型 (interface type) のメソッド集合は,そのインターフェース自身である. それ以外の型 T のメソッド集合は, レシーバー型 (receiver type) T で宣言されたすべてのメソッドで構成される. ポインター型 *T に対応するメソッド集合は, レシーバー *T もしくは T で宣言されたすべてのメソッド集合である. (つまり,それは T のメソッド集合もまた,含む.) 構造体型の章で説明しているように, 埋め込みフィールドを含む構造体にさらなる規則が適用される. それ以外の型は,空のメソッド集合をもつ. メソッド集合において, それぞれのメソッドは一意で, ブランクでないメソッド名を持たなければならない (MUST).

ある型のメソッド集合は, その型が実装するインターフェースと, その型のレシーバーを用いて呼び出すことができるメソッドによって決定する.

ブール型

ブール型 (boolean type) は, 事前宣言された定数 truefalse で表記される ブール真偽値の集合を表現する. 事前宣言されたブール型は bool である. bool は,定義型 (defined type) である.

数値型

数値型 (numeric type) は整数値の集合または浮動小数点値たちの集合を表現する. 事前宣言されたアーキテクチャに依存しない数値型は以下である.

uint8       符号なし 8 ビット整数の集合 (`0`-`255`)
uint16      符号なし 16 ビット整数の集合 (`0`-`65535`)
uint32      符号なし 32 ビット整数の集合 (`0`-`4294967295`)
uint64      符号なし 64 ビット整数の集合 (`0`-`18446744073709551615`)

int8        符号付き 8 ビット整数の集合 (-128 to 127)
int16       符号付き 16 ビット整数の集合 (-32768 to 32767)
int32       符号付き 32 ビット整数の集合 (-2147483648 to 2147483647)
int64       符号付き 64 ビット整数の集合 (-9223372036854775808 to 9223372036854775807)

float32     IEEE-754 32 ビット浮動小数点数の集合
float64     IEEE-754 64 ビット浮動小数点数の集合

complex64   float32 の実部と虚部をもつ複素数の集合
complex128  float64 の実部と虚部をもつ複素数の集合

byte        uint8 のエイリアス
rune        int32 のエイリアス

n ビット整数の値は n ビット幅であり, 2 の補数を使って表現される.

実装固有のサイズを持つ事前宣言された数値型の集合もある.

uint     32ビットまたは 64ビットのいずれか
int      unit と同じサイズ
uintptr  ポインター値のみ解釈ビットを格納するのに十分大きな符号なし整数

移植性の問題を回避するために, すべての数値型は,定義型であり, したがって, uint8エイリアスである byte と, int32 のエイリアスである rune を除いて区別する. 異なる数値型がひとつの式や代入において混在している場合, 明示的な変換が要求される. 例えば, あるアーキテクチャにおいては同じ型を有する可能性があるが, int32int が異なる型である.

文字列型

文字列型 (string type) は文字列値の集合を表現する. 文字列値は,(空を含めた) バイト列である. バイトの数はその文字列の長さ (length) と呼ばれ,必ず非負である. 文字列は不変 (immutable) である. つまり,一旦生成されると,文字列の内容を変更することは不可能である. 事前宣言された文字列型は string である. string は,定義型 (defined type) である.

文字列 s の長さは, ビルトイン関数 len を使って得られる. 文字列の長さは, その文字列が定数であれば, コンパイル時定数 (compile-time constant) である. 文字列のバイトには整数のインデックス 0-len(s)-1 でアクセスできる. アドレスの取得は不当となる.つまり, s[i]i バイト目であるとき, &s[i] は不当である.

配列型

配列はある要素型 (element type) と呼ばれる単一の型の要素の番号付き列である. 要素の数はその配列の長さと呼ばれ,非負である.

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  // [2]([2]([2]float64)) と同じ

スライス型

スライス (slice) は 基底配列 (underlying array) の連続したセグメントの記述子であり, その配列の要素に番号付の列でアクセスできる. スライス型 (slice type) は,その要素型の配列のすべてのスライスの集合を表す. 要素の数はそのスライスの長さ (length) と呼ばれ,必ず非負である. 初期化されていないスライスの値は nil である.

SliceType = "[" "]" ElementType .

スライス s の長さは ビルトイン関数 len を使って得られる. 配列と異なり,実行中に変化する. スライスの要素は, 整数のインデックス 0 から len(s) - 1 でアクセスできる. ある要素のスライスでのインデックスは, 基底配列における同じ要素のインデックスよりも小さい場合がある.

スライスは一度初期化されると, スライスの要素たちを保持する 基礎配列によって関連付けられる. それゆえ, スライスは,その基底配列とストレージを共有し, 同じ配列から生成される他のスライスもまた,ストレージを共有する. 対照的に, 異なる配列は,いつでも異なるストレージを表現する.

スライスの基底配列は, スライスの終端を超えて拡張されうる. 容量 (capacity) はその拡張量である: 容量は,スライスの長さとそのスライスを超えた配列の長さの和である. 容量を超えた長さのスライスは, 元のスライスから 新しいスライスが元のスライスをスライスする @@@ことによって その容量までの長さのスライスが生成できる. スライス a の容量は, ビルトイン関数 cap(a) を使って得られる. (訳注:本質的ではないが,本家の typo ではないだろうか. a -> s)

ある与えられた要素型 T の初期化されたスライス値は, ビルトイン関数 make を使って得られる. make はスライス型と, 長さ,および,オプションで容量を指定するパラメーターを受け取る. make によって生成されたスライスは 常に復帰されたスライス値を参照する新しい隠し配列が割り当てられる. つまり,

make([]T, length, capacity)

を実行すると, 配列を割り当てて,それをスライスして得られるものと同じスライスを生成する. つまり,以下の 2 つの式は等価である.

make([]int, 50, 100)
new([100]int)[0:50]

配列のように スライスはいつも 1 次元である. しかし,多次元のオブジェクトを構築するために構成できる. 配列の配列では,内部配列は,構造上,常に同じ長さである. しかし,スライスのスライス(または,スライスの配列)では, 内部スライスの長さは動的に変化する. さらに,内部スライスは個別に初期化する必要がある.

構造体型

構造体はフィールド (field) と呼ばれる名前付き要素の列である. 各フィールドには名前と型がある. フィールド名は明示的に指定される (IdentifierList) か, 暗黙的に指定される (EmbeddedField). 構造体内では, ブランクでないフィールド名は一意でなければならない (MUST).

StructType    = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl     = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag           = string_lit .
// 空の構造体
struct {}

// 6 つのフィールドをもつ構造体
struct {
	x, y int
	u float32
	_ float32  // パディング
	A *[]int
	F func()
}

型で宣言されているが,明示的なフィールド名がないフィールドは 埋め込みフィールド (embedded field) と呼ばれる. 埋め込みフィールドは, 型名 T として指定されるか, インターフェースでない型名 *T へのポインターとして指定されなければならず, T 自身はポインタータイプでない場合がある. 非修飾型名はフィールド名として機能する.

// 型 T1, *T2, P.T3, *P.T4 の型の 4 つの埋め込みフィールドをもつ構造体
struct {
	T1        // フィールド名は T1
	*T2       // フィールド名は T2
	P.T3      // フィールド名は T3
	*P.T4     // フィールド名は T4
	x, y int  // フィールド名は x と y
}

次の宣言は, フィールド名が構造体型内で一意でないため, 不当である:

struct {
	T     // 埋め込みフィールド *T, *P.T と衝突
	*T    // 埋め込みフィールド T, *P.T と衝突
	*P.T  // 埋め込みフィールド T, *T と衝突
}

構造体 x の埋め込みフィールドの フィールドやメソッド f は もし,x.f がフィールドやメソッド f を表記される正当なセレクタである場合, x昇格された (promoted) と呼ばれる.@@@

昇格フィールド (promoted field) は 構造体の複合リテラルにおいて フィールド名として使用できないことを除いて, 構造体の通常のフィールドのように機能する.

構造体型 S定義型 T が与えられたとき, 次のように 昇格されたメソッドは 構造体のメソッド集合に含まれる.

フィールド宣言は, オプションである文字列リテラルタグ (tag) に続く場合がある. これは,対応するフィールド宣言内のすべてのフィールドの属性になる. 空のタグ文字列は,タグがない場合と同値である. タグは, リフレクションインターフェース を通して表示され, 構造体の型同一性 @@@ (type identity) に参加する@@@が, そうでなければ,無視される.

struct {
	x, y float64 ""  // 空文字列タグは,タグがない場合と似ている
	name string  "タグとして,任意の文字列が許される"
	_    [4]byte "コレハコウゾウタイフィールドデハアリマセン"
}

// TimeStamp プロトコルバッファ (protocol buffer) に対応する構造体
// タグ文字列は,プロトコルバッファのフィールド番号を定義する;
// タグ文字列は,リフレクトパッケージで概説されている規則に従う
struct {
	microsec  uint64 `protobuf:"1"`
	serverIP6 uint64 `protobuf:"2"`
}

ポインター型

ポインター型 (pointer type) は 与えられた型の変数へのすべてのポインターの集合を表し, ポインターの基本型 (base type) と呼ばれる. 未初期化のポインターの値は nil である.

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

関数型

関数型 (function type) は同じパラメーター (parameter) と復帰型 (result type) をもつすべての関数の集合を表す. 関数型の未初期化の変数の値は nil である.

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

パラメーターや復帰値のリストでは, 名前 (IdentifierList) はすべて存在するか,すべて存在しないかのどちらかである (MUST). 存在する場合,各名前は指定された型の一つのアイテム (パラメーターまたは結果)を表し, シグネチャーにおけるすべての非ブランクな名前は一意でなければならない. 存在しない場合,各型は,その型のひとつのアイテムを表す. 正確に 1 つだけの無名の復帰であり,丸括弧なしの型で書かれる場合を除いて, パラメーターと結果のリストは,いつでも丸括弧で囲まれる.

関数シグネチャーの最後のパラメーターは, ... を接頭辞にもつ型を持つ場合がある. そのようなパラメーターをもつ関数は可変長引数 (variadic) と呼ばれ, そのパラメーターとして,0個以上の引数として呼び出される.

訳注:@@@ 復帰パラメーター

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)

インターフェース型

インターフェース型 (interface type) は インターフェース (interface) と呼ばれるメソッド集合を指定する. インターフェース型の変数は, そのインターフェースの任意のスーパーセットであるメソッド集合の 任意の型の値を格納する. そのような型はインターフェースの実装 (implement the interface) という. インターフェース型の未初期化な変数の値は nil である.

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

インターフェース型は, メソッド仕様を介してメソッドを明示的に指定するか, インターフェース型名を介して, 他のインターフェースのメソッドを埋め込むことができる.

// 単純な File インターフェース
interface {
	Read([]byte) (int, error)
	Write([]byte) (int, error)
	Close() error
}

各明示的に指定されたメソッドの名前は一意であり,非ブランクでなければならない.

interface {
	String() string
	String() string  // 不当: String は一意でない
	_(x int)         // 不当: メソッドは非ブランク名でなければならない
}

複数の型がインターフェースで実装される. 例えば, 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 を表す) S1S2 の他のメソッドをもつ,または,共有するかに関係なく, File インターフェースは S1S2 の両方で実装される.

型は,そのメソッドの部分集合を含むインターフェースを実装するため, いくつかの異なるインターフェースを実装できる. 例えば,すべての型が空インターフェース (empty interface) を実装する.

interface{}

同様に, Locker と呼ばれるインターフェースを定義する型宣言で現れる このインターフェース仕様を考える.

type Locker interface {
	Lock()
	Unlock()
}

もし,S1S2 が次を実装すると

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

S1S2Locker インターフェースと File インターフェースを実装する.

インターフェース T は メソッド仕様の代わりに (修飾された可能性のある) インターフェース型名 E を使用できる. これは,T における埋め込み (embedding) インターフェース E と呼ばれる. 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 のメソッドは Read, Write, Close である
type ReadWriter interface {
	Reader  // `ReadWriter` のメソッド集合は `Reader` のメソッドを含む
	Writer  // `ReadWriter` のメソッド集合は `Writer` のメソッドを含む
}

メソッド集合の和集合には, 各メソッド集合の (エクスポート (export) されたおよびされていない) メソッドが一度だけ含まれ, 同じ名前のメソッドは,同一のシグネチャーを持たなければならない.

type ReadCloser interface {
	Reader  // `ReadWriter` のメソッド集合は `Reader` のメソッドを含む
	Close()  // 不当: `Reader.Close` と `Close` のシグネチャーは異なる
}

インターフェース型 T は それ自身や T が埋め込まれた任意の型を再帰的に埋め込むことはできない.

// 不当: Bad はそれ自身を埋め込めない
type Bad interface {
	Bad
}

// 不当: Bad1 は Bad2 を使ってそれ自身を埋め込むことはできない
type Bad1 interface {
	Bad2
}
type Bad2 interface {
	Bad1
}

訳注: 「union」が 2 回強調

マップ型

マップ (map) は 要素型 (element type) と呼ばれる要素の型の順序付けられていないグループであり, キー型 (key type) と呼ばれる別の型の一意キーの集合によってインデックスがつけられる. 未初期化のマップの値は nil である.

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

比較演算子 ==!= はキー型のオペランドに定義されなければならない. したがって,キー型は 関数,マップ,スライスであってはならない. キー型がインターフェース型である場合, これらの比較演算子は, 動的にキー値に対して定義されなければならない. 失敗すると, ランタイムパニックが発生する.

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

マップの要素の数は長さと呼ばれる. マップ m に対して,長さは ビルトイン関数 lenを使って得られ, これは実行中に変化する. 要素は,実行中に代入によって追加し, インデックス式によって取得できる. ビルトイン関数 delete によって削除できる.

(訳注:m は使っていないのは本家のバグ?)

新しい,空のマップ値は, ビルトイン関数 make を使って生成でき, make はマップ型とオプションで容量ヒントを引数にとる.

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

初期容量は,そのサイズを制限しない. マップは,マップに格納されるアイテムの数に合わせて成長する. nil マップは,要素が追加されないことを除いて,空のマップと等価である.

訳注:急に item という表現に. アイテム=要素

チャンネル型

チャンネル (channel) は 指定された要素型を送信受信する値によって通信する同時に (concurrently) 実行する関数のためのメカニズムを提供する. 未初期化のチャンネルの値は nil である.

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

オプションである <- 演算子は チャンネルの方向,つまり,送信または受信を指定する. もし,方向が指定されなかった場合, チャンネルは双方向 (bidirectional) になる. チャンネルは代入か明示的な変換によって送信のみか受信のみに制限される場合がある.

chan T          // 型 T の値の送受信に使用できる
chan<- float64  // float64 値の送信にのみ使用できる
<-chan int      // int 値の受信にのみ使用できる

<- 演算子は可能な限り左の chan に関連付けられる.

chan<- chan int    // chan<- (chan int) と同じ
chan<- <-chan int  // chan<- (<-chan int) と同じ
<-chan <-chan int  // <-chan (<-chan int) と同じ
chan (<-chan int)

新しい,初期化されたチャンネル値は, ビルトイン関数 make を使って生成でき, make はチャンネル型とオプションで容量を引数にとる.

make(chan int, 100)

容量(要素数)はチャンネル内のバッファサイズを設定する. 容量がゼロまたは存在しない場合, チャンネルはバッファリングされておらず, 送信者と受信者の両方が準備できたときにのみ,通信は成功する. それ以外の場合, チャンネルはバッファリングされており, バッファがいっぱいでない (送信時)か, 空でない(受信時)場合には, ブロックせずに通信が成功する. nil チャンネルは通信の準備ができることはない.

チャンネルはビルトイン関数 close を使って閉じられる. 受信演算子の多値代入形式はチャンネルが閉じられる前に受信値が送信されたかどうかを報告する.

単一のチャンネルは送信文受信演算, ビルトイン関数 caplen の呼び出しにおいて, さらなる同期なしで任意の数のゴルーチンによって,使用できる. チャンネルは先入れ先出し (FIFO: first-in-firs-out) キューとして機能する. 例えば, あるゴルーチンがチャンネルで値を送信し, 別のゴルーチンがその値を受信すると, 値は送信した順番で受信される.

型と値の性質

型の一意性

2つの型は同一 (identical) または異なる (different) ものである.

定義型はいつでも他の型と異なる. それ以外の場合, 基底型リテラルが構造的に同一な場合, 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 は異なる型定義によって生成された新しい型なので, B0B1 は異なる; B0[]string と異なるので, func(int, float64) *B0func(x int, y float64) *[]string は異なる.

代入可能性

次の条件のうち一つでも満たす場合, 値 x は型 T変数代入可能 (assignable) である. (xT に代入可能)

表現可能性

次の条件のうち,ひとつの条件を満たすとき, 定数 x は 型 T の値によって表現可能である.

x                   T           x は T の値によって表現可能である, なぜなら

'a'                 byte        97 は byte 値の集合に属する
97                  rune        ルーンは int32 のエイリアスであり, 97 は 32ビット整数の集合に属する
"foo"               string      "foo" は文字列値の集合に属する
1024                int16       1024 は 16ビット整数の集合に属する
42.0                byte        42 は符号なし 8ビット整数の集合に属する
1e10                uint64      10000000000 は符号なし 64ビット整数の集合に属する
2.718281828459045   float32     2.718281828459045 は float32 値の集合に属する 2.7182817 に丸められる
-1e-1000            float64     -1e-1000 は IEEE -0.0 に丸められ,さらに 0.0 に簡略化される
0i                  int         0 は整数値である
(42 + 0i)           float32     42.0 (0 の虚部をもつ) は float32 値の集合に属する
x                   T           x は T の値によって表現不可能である, なぜなら

0                   bool        0 はブール値の集合に属しない
'a'                 string      'a' はルーンであり,文字列値の集合に属しない
1024                byte        1024 は符号なし 8ビット整数の集合に属さない
-1                  uint16      -1 は符号なし 16びと整数の集合に属さない
1.1                 int         1.1 は整数値ではない
42i                 float32     (0 + 42i) は float32 値の集合に属さない
1e1000              float64     1e1000 は丸め後に IEEE +Inf にオーバーフローする

ブロック

ブロック (block) は, 波括弧 (brace brackets) 内の宣言と文の列(空の場合もある)である.

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

ソースコード内の明示的なブロックに加えて, 以下の暗黙的なブロックもある.

  1. ユニバースブロック (universe block) はすべての Go ソースコードを包含する.
  2. パッケージは,そのパッケージのすべての Go ソースコードに含まれるパッケージブロック (package block) をもつ.
  3. 各ファイルは,そのファイル内のすべての Go ソーステキストを含むファイルブロック (file block) をもつ.
  4. if, for, switchは,それ自身の暗黙的なブロックに含まれると見なされる.
  5. switchselectの各句は暗黙的なブロックとして機能する.

ブロックはネストし,スコープに影響する.

宣言とスコープ

宣言 (declaration) は,非ブランクな識別子を定数変数関数ラベルパッケージへバインドする (bind). プログラム内のすべての識別子は,宣言される必要がある. 同じブロック内で識別子を 2 回宣言できず, ファイルとパッケージの両方のブロックで識別子を宣言できない.

ブランク識別子は, 宣言内の他の識別子と同じように使用できるが, バインドされず,したがって,宣言もされない. パッケージブロックにおいて, 識別子 initinit 関数の宣言にのみ使用され, ブランク識別子と同様に,新しいバインドを導入しない.

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

宣言された識別子のスコープ (scope) は, 識別子が指定された定数,型,変数,関数,ラベル,パッケージを示すソーステキストの範囲である.

Go は,ブロックを用いて, 字句的にスコープされる.

  1. 事前宣言のスコープは,ユニバースブロックである.
  2. トップレベルで宣言された定数,型,変数,関数 (メソッドは除く)を示す識別子のスコープは, パッケージブロックである.
  3. インポートされたパッケージのパッケージ名のスコープは, インポート宣言を含むファイルのファイルブロックである.
  4. メソッドレシーバー,関数パラメーター,復帰変数を示す識別子のスコープは, 関数本体である.
  5. 関数内で宣言された定数と変数識別子のスコープは, ConstSpecVarSpec (ShortVarDecl) の終わりから開始し, もっとも内側に含まれるブロックの終端で終了する.
  6. 関数内で宣言された型識別子のスコープは, TypeSpec 内の identifier から開始し, もっとも内側に含まれるブロックの終端で終了する.

ブロック内で宣言された識別子は, 内部ブロック (inner block)で再宣言できる. 内部ブロックの識別子は,スコープに含まれるが, 内部ブロックの識別子は, 内部宣言によって宣言されたエンティティ (entity) を示す.

パッケージ句 (package clause) は,宣言ではない. パッケージ名はスコープに現れることはない. その目的は,同じパッケージに属するファイルを特定し, インポート宣言のデフォルトのパッケージを指定することである.

ラベルスコープ

ラベル (label) は, ラベル文 (labeled statement) によって宣言され, breakcontinuegotoで使用される. 使用されないラベルを定義することは,不当である. 他の識別子と異なり, ラベルはブロックスコープではなく, ラベルでない識別子と衝突しない. ラベルのスコープはラベルが宣言された関数の本体であり, ネストされた関数の本体は除く.

ブランク識別子

ブランク識別子 (blank identifier) はアンダースコア _ によって表現される. ブランク識別子は,通常の (非ブランクな)識別子の代わりに匿名のプレースホルダー (訳注:一時的に保管するだけの変数)として機能し, 宣言オペランド代入で特別な意味を持つ.

事前宣言された識別子

次の識別子は,ユニバースブロック (universe block) で暗黙的に宣言されている.

型:
	bool byte complex64 complex128 error float32 float64
	int int8 int16 int32 int64 rune string
	uint uint8 uint16 uint32 uint64 uintptr

定数:
	true false iota

ゼロ値:
	nil

関数:
	append cap close complex copy delete imag len
	make new panic print println real recover

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

他のパッケージからのアクセスを許可するために, 識別子は,エクスポート (export) できる. 次の 2 つの条件を満足する場合, 識別子はエクスポートされる:

  1. 識別子名の最初の文字は,Unicode 大文字 (Unicode クラス “Lu”) であり,
  2. 識別子は,パッケージブロックで宣言されるか,フィールド名であるか,メソッド名である.

他のすべての識別子はエクスポートされない.

識別子の一意性

識別子の集合が与えられたとき, 集合内における他のすべての識別子と異なるとき, 識別子は,一意 (unique) であると呼ぶ. 2 つの識別子が, 「スペルが異なる」か, 「異なるパッケージに現れ, エクスポートされない」とき, その識別子たちは異なる.

定数宣言

定数宣言 (constant declaration) 識別子のリストに定数式 (constant expression) のリストの値をバインドする. 識別子の数は,定数式の数と一致しなければならず, 左辺の 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         // 型なし浮動小数点定数
const (
	size int64 = 1024
	eof        = -1  // 型なし整数定数
)
const a, b, c = 3, 4, "foo"  // a = 3, b = 4, c = "foo", 型なし整数定数と型なし文字列定数
const u, v float32 = 0, 3    // u = 0.0, v = 3.0

丸括弧で囲まれた (parenthesized) const 宣言リスト内では, 最初の ConstSpec 以外の式リストは省略できる. このような空の式リストは, 最初の先行する空でない式リストとその型のテキスト置換と等価である. それゆえに, 式リストの省略は, 前の式リストの繰り返しを繰り返すことと等価である. 識別子の数は, 前のリストにおける式の数と等価である. このメカニズムは, iota 定数生成器を使うことで, 連続値の容易な宣言を可能とする.

const (
	Sunday = iota
	Monday
	Tuesday
	Wednesday
	Thursday
	Friday
	Partyday
	numberOfDays  // この定数はエクスポートされない
)

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, 使用されない)
	d = 1 << iota  // d == 8  (iota == 3)
)

const (
	u         = iota * 42  // u == 0     (型なし整数定数)
	v float64 = iota * 42  // v == 42.0  (float64 定数)
	w         = iota * 42  // w == 84    (型なし整数定数)
)

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, 使用されない)
	bit3, mask3                           // bit3 == 8, mask3 == 7  (iota == 3)
)

最後の例は,最後の空でない式リストの暗黙的な繰り返しを利用している.

型宣言

型宣言 (type declaration) は, 型名 (type name) である識別子に (type) をバインドする. 型宣言は, エイリアス宣言 (alias declarations) と型定義 (type definitions) の 2 つの形式がある.

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

エイリアス宣言

エイリアス宣言 (alias declaration) は識別子に与えられた型をバインドする.

AliasDecl = identifier "=" Type .

識別子のスコープ内では, その識別子は,与えられた型のエイリアスとして機能する.

type (
	nodeList = []*Node  // nodeList と []*Node は同じ型である
	Polar    = polar    // Polar と polar は同じ型を示す
)

型定義

型定義 (type definition) は,指定された型と同じ基底型と演算をもつ, 新しく,別の型を生成し, それの新しい型を識別子にバインドする.

TypeDef = identifier Type .

新しい型は定義型 (defined type) と呼ばれる. 新しい型は, 生成元となる型を含む, 他のあらゆる型とは, 異なる

type (
	Point struct{ x, y float64 }  // Point と struct{ x, y float64 } は異なる型である
	polar Point                   // polar と Point は異なる型を示す
)

type TreeNode struct {
	left, right *TreeNode
	value *Comparable
}

type Block interface {
	BlockSize() int
	Encrypt(src, dst []byte)
	Decrypt(src, dst []byte)
}

定義型は,それに関連付けられたメソッドをもつことができる. 定義型は,指定された型にバインドされたメソッドは継承 (inherit) しないが, インターフェース型,または, 複合型の要素のメソッド集合は変更されない.

// Mutex は 2 つのメソッド (Lock, Unlock) をもつデータ型である.
type Mutex struct         { /* Mutex フィールド */ }
func (m *Mutex) Lock()    { /* Lock の実装 */ }
func (m *Mutex) Unlock()  { /* Unlock の実装 */ }

// NewMutex は,Mutex と同じ構成であるが,そのメソッド集合は空である.
type NewMutex Mutex

// *Mutex を基底型とする,PtrMutex のメソッド集合は変更されないが,
// PtrMutex のメソッド集合は空である
type PtrMutex *Mutex

// *PrintableMutex のメソッド集合は埋め込みフィールド Mutex にバインドされた
// 2 つのメソッド Lock と Unlock を含む
type PrintableMutex struct {
	Mutex
}

// MyBlock は 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)
}

変数宣言

変数宣言 (variable declaration) は 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]  // マップ検索; "found" にのみ興味がある

式のリスト (ExpressionList) が与えられたら, 変数は以下の代入規則に従った式によって初期化される. そうでなければ,各変数はゼロ値で初期化される.

型が指定されると,変数はその型になる. 型が指定されなければ,各変数は代入における対応する初期値の型が与えられる. その値が型なし定数であれば, 最初に暗黙的にデフォルト型変換される. 型なしブール値であれば,最初に暗黙的に bool 型に変換される. 事前宣言された値 nil は,明示的な型を持たない変数の初期値として使用できない.

var d = math.Sin(0.5)  // d は float64
var i = 42             // i は int
var t, ok = x.(T)      // t は T, ok は bool
var n = nil            // 不当

実装上の制限: コンパイラは, 関数本体内で宣言された変数が, 関数内で使用されない場合, 不当とすることがある.

簡潔な変数宣言

簡潔な変数宣言 (short variable declaration) は次の文法を使用する.

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() は Files の接続ペア(r, w)と error を返す
_, y, _ := coord(p)   // coord() は 3 つの値を返す; しかし, y 軸にしか興味がない

通常の変数宣言とは異なり, 簡潔な変数宣言では, 同じブロック内 (または,そのブロックが関数本体であればパラメーターリスト) で前に宣言された同じ型の変数, そして,少なくとも 1 つの非ブランクな変数が新しい場合, 変数を再宣言 (redeclare) できる. 結果として,再宣言は多値の簡潔な変数宣言においてのみ使用される. 再宣言では新しい変数は導入されず, 新しい値が元の変数に代入される.

field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset)  // オフセットを再宣言する
a, a := 1, 2                              // 不当: a が他の場所で宣言されている場合,a の二重宣言または新規変数なし

簡潔な変数宣言は,関数内でのみ現れる. ifforswitchの初期化のようにローカル一時変数の宣言に使用できる.

訳注:a tour of go 翻訳では,短い変数宣言

関数宣言

関数宣言 (function declaration; FunctionDecl) は 関数名 (function name) である識別子に, 関数をバインドする.

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

関数のシグネチャーが復帰パラメーターたちを宣言する場合, 関数本体 (FunctionBody) の文のリストは, 終端文 (terminating statement) で終了しなければならない.

func IndexRune(s string, r rune) int {
	for i, c := range s {
		if c == r {
			return i
		}
	}
	// 無効: return 文がない
}

関数は,その本体なしで宣言される場合がある. そのような宣言は, アセンブリルーチン (assembly routine) のように Go の外で実装された関数のシグネチャーを提供する.

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

func flushICache(begin, end uintptr)  // 外部で実装される

メソッド宣言

メソッド (method) はレシーバー (receiver) をもつ関数である. メソッド宣言 (method declaration) はメソッド名 (method name) である識別子に, メソッドをバインド (bind) し, レシーバーの基本型 (base type) にメソッドを関連付ける.

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

レシーバーは,メソッド名の前にある追加のパラメーター節で指定される. そのパラメーター節は,ひとつの不可変数引数で,そのレシーバーを宣言する. その型は,定義T,または,定義型 T へのポインターでなければならない. T はレシーバー基本型 (base type)と呼ばれる. レシーバー基本型は,ポインター型またはインターフェース型にはできず, メソッドとして,同じパッケージ内で定義されなければならない. そのメソッドはレシーバー基本型にバインド (bind) されると言い, メソッド名は,型 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 の) メソッド LengthScale を基本型 Point にバインドする.

メソッドの型は, 最初の引数をそのレシーバーとする関数の型である. 例えば,メソッド Scale は次の型をもつ.

func(p *Point, factor float64)

しかしながら,この方法で宣言された関数はメソッドではない.

式 (expression) は. 演算子と関数をオペランドへの適用によって値の計算を指定する.

オペランド

オペランド (operand) は式における基本値を示す. オペランドは, リテラル, または, 定数変数関数を示す (場合によっては修飾された) 非ブランクな識別子,または, 丸括弧で囲まれた式である.

ブランク代入の左辺においてのみオペランドとして現れる.

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

修飾識別子

修飾識別子 (qualified identifier) はパッケージ名を前頭において修飾された識別子である. パッケージ名と識別子はどちらもブランクにできない.

QualifiedIdent = PackageName "." identifier .

修飾識別子は, インポートされなければならない, 別のパッケージの識別子にアクセスする. 識別子は,エクスポートされており, そのパッケージのパッケージブロックで宣言されていなければならない.

math.Sin	// パッケージ math の Sin 関数を示す

複合リテラル

複合リテラル (composite literal, CompositeLit) は, 構造体,配列,スライス,マップの値を構築し, 複合リテラルが評価されるたびに新しい値を生成する. 複合リテラルは, リテラルの型 LiteralType と, 波括弧で囲まれた要素のリスト LiteralValue から成る. 各要素は,オプションとして対応するキー Key を要素の前に置くことがある.

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{}                            // Point3D のゼロ値
line := Line{origin, Point3D{y: -4, z: 12.3}}  // line.q.x にゼロ値

配列リテラルとスライスリテラルの場合,以下の規則が適用される:

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

var pointer *Point3D = &Point3D{y: 1000}

スライス型とマップ型のゼロ値は同じ型の空の値に初期化されたものを同じではないことに注意されたい. したがって, 空のスライスの複合リテラルのアドレス,または, 空のマップの複合リテラルのアドレスを取得することは, new によって新しいスライス値やマップ値を割り当てることとは同じ効果ではない.

p1 := &[]int{}    // p1 []int{} 値の空のスライスで長さ 0 のスライスをポイントする
p2 := new([]int)  // p2 は nil 値をもつ未初期化で長さ 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 であるとき, &T を削除できる.

[...]Point{ {1.5, -3.5}, {0, 0}}     // [...]Point{Point{1.5, -3.5}, Point{0, 0}} と同じ
[][]int{ {1, 2, 3}, {4, 5}}          // [][]int{[]int{1, 2, 3}, []int{4, 5}} と同じ
[][]Point{ { {0, 1}, {1, 2}}}        // [][]Point{[]Point{Point{0, 1}, Point{1, 2}}} と同じ
map[string]Point{"orig": {0, 0}}     // map[string]Point{"orig": Point{0, 0}} と同じ
map[Point]string{ {0, 0}: "orig"}    // map[Point]string{Point{0, 0}: "orig"} と同じ

type PPoint *Point
[2]*Point{ {1.5, -3.5}, {}}          // [2]*Point{&Point{1.5, -3.5}, &Point{}} と同じ
[2]PPoint{ {1.5, -3.5}, {}}          // [2]PPoint{PPoint(&Point{1.5, -3.5}), PPoint(&Point{})} と同じ

// 訳注 GitHub Pages でのエラー回避のため,連続する { の間にスペースを追加している

TypeName 形式の LiteralType を用いた複合リテラルが, キーワードと if文, for文, switch文のブロックの開き波括弧 { の間にオペランドとして現れ,かつ, 複合リテラルが,丸括弧 (),角括弧 [],波括弧 {}で囲まれていないとき, 構文解析における曖昧性が発生する. この稀なケースでは, リテラルの開き波括弧 { が文のブロックを導入するものとして, 誤って解析される. この曖昧性を解決するために, 複合リテラルは,丸括弧の中に表示する必要がある.

if x == (T{a,b,c}[i]) {  }
if (x == T{a,b,c}[i]) {  }

有効な配列リテラル,スライスリテラル,マップリテラルの例:

// 素数のリスト
primes := []int{2, 3, 5, 7, 9, 2147483647}

// ch が vowel であれば vowels[ch] は true である
vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true}

// 配列 [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}

// 平均律スケールの周波数 (Hz) (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,
}

関数リテラル

関数リテラル (function literal) は無名関数を表現する.

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)

関数リテラルはクロージャー (closure) である. 関数リテラルは,周囲の関数で定義された変数を参照する場合がある. これらの変数は,周囲の関数と関数リテラルで共有され, アクセス可能である限り,生存する (survive).

一次式

一次式 (primary expression) は,単項式 (unary expression) と二項式 (binary expression) のオペランドである.

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 に対して, セレクタ式 (selector expression)

x.f

は,値 x (または,*x; 下記参照) のフィールド f,またはメソッド f を示す. 識別子 f は (フィールド,またはメソッド)セレクタ (selector) と呼ばれ, ブランク識別子であってはならない. セレクタ式の型は f の型である. x がパッケージ名の場合は,修飾識別子を参照されたい.

セレクタ f は, 型 T のフィールド f またはメソッド f を示す場合と, T のネストされた埋め込みフィールドのフィールド f かメソッド f を参照する場合がある. f に到達するためにたどる埋め込みフィールドの数を T における f深さ (depth) と呼ばれる. T で宣言されたフィールド f またはメソッド f の深さはゼロである. T の埋め込みフィールド A において宣言されたフィールド f またはメソッド f の深さは, A における f の深さに 1 加えたものである.

以下のルールがセレクタに適用される.

  1. T がポインター型やインターフェース型 でないとするとき, 型 T または型 *T の値 x に対して, x.ff が存在するとき, T の深さがもっとも浅いフィールド,またはメソッドを示す. 深さが最も浅い f がちょうど一つだけ存在しない場合, セレクタ表現は不当である.
  2. I がインターフェース型であるとき,I の値 x に対して, x.fx の動的な値の名前 f をもつ実際のメソッドを示す. 名前 f のメソッドが Iメソッド集合に存在しない場合, セレクタ表現は不当である.
  3. 例外として, x の型が定義されたポインター型であり, (*x).f がフィールドを示す (しかし,メソッドではない) 有効なセレクタ式である場合, x.f(*x).f の省略形である.
  4. 他のすべての場合で,x.f は不当である.
  5. x がポインター型であり,値 nil を持ち, x.f が構造体フィールドを表すとき, x.f への代入や,x.f の評価は, ランタイムパニックが発生する.
  6. x がインターフェース型であり,値 nil を持つとき, メソッド x.f の呼び出しや 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     // t.T0 != nil とする
var p *T2    // p != nil であり,(*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 は有効なフィールドセレクタである

p.M0()       // ((*p).T0).M0()      M0 は *T0 レシーバーを想定する
p.M1()       // ((*p).T1).M1()      M1 は T1 レシーバーを想定する
p.M2()       // p.M2()              M2 は *T2 レシーバーを想定する
t.M2()       // (&t).M2()           M2 は *T2 レシーバーを想定する,呼び出し節を参照

しかし,以下は無効である.

q.M0()       // (*q).M0 は有効であるが,フィールドセレクタである

メソッド式

M が型 Tメソッド集合に存在する場合, T.MM の引数の最初に, メソッドのレシーバーを追加したものを引数として, 通常の関数のように呼び出し可能である関数である.

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

構造体型 T が 2 つのメソッド Mv, Mp をもつとする. Mv のレシーバーは型 T である. Mp のレシーバーは型 *T である.

type T struct {
	a int
}
func (tv  T) Mv(a int) int         { return 0 }  // value receiver
func (tp *T) Mp(f float32) float32 { return 1 }  // pointer receiver

var t T

T.Mv

は, Mv と等価であるが, その最初の引数として明示的なレシーバーをもつ関数を生成する (yield). それは次のシグネチャーをもつ.

func(tv T, a int) int

その関数は,明示的なレシーバーで通常呼び出されるため, 以下の 5 つの呼び出し方法は等価である.

t.Mv(7)
T.Mv(t, 7)
(T).Mv(t, 7)
f1 := T.Mv; f1(t, 7)
f2 := (T).Mv; f2(t, 7)

同様に,式

(*T).Mp

は,次のシグネチャーをもつ Mp を表現する関数値を生成する.

func(tp *T, f float32) float32

値レシーバをもつメソッドの場合, 明示的なポインターレシーバーをもつ関数を導出する.

(*T).Mv

は,次のシグネチャーをもつ Mv を表現する関数値を生成する.

func(tv *T, a int) int

そのような関数は,レシーバーを介して間接的に, 基底メソッドにレシーバーとして渡す値を生成する. メソッドは,関数呼び出しで渡されるアドレスの値を上書きしない.

最後のケースである, ポインターレシーバーメソッドのための値レシーバー関数は, ポインターレシーバーメソッドは値型のメソッド集合に属しないので, 不当である.

メソッドから派生した関数値は関数呼び出し構文で呼び出される. レシーバーは,最初の引数として提供される. つまり,f := T.Mv が与えられたとき, ft.f(7) ではなく,f(t, 7) のように呼び出される. レシーバーをバインドする関数の構築には, 関数リテラルメソッド値を使用する.

インターフェース型のメソッドの関数値を派生させることは正当である. 結果となる関数は,インターフェース型の明示的なレシーバをとる.

メソッド値

x が静的な型 T をもち, M が型 Tメソッド集合に属する場合, x.Mメソッド値 (method value) と呼ばれる. メソッド値 x.Mx.M のメソッド呼び出しと同じ引数で呼び出される関数値である. 式 x は評価され,メソッド値が評価される間保存される. 保存されたコピーは, あとで実行される可能性のある任意の呼び出しでレシーバーとして使用される.

T はインターフェース型,または,非インターフェース型である.

上記メソッド式で説明したように, 2 つのメソッド MvMp をもつ構造体型 T を考える. Mv のレシーバーは型 T で, Mp のレシーバーは型 *T である.

type T struct {
	a int
}
func (tv  T) Mv(a int) int         { return 0 }  // value receiver
func (tp *T) Mp(f float32) float32 { return 1 }  // pointer receiver

var t T
var pt *T
func makeT() T

t.Mv

は次の型の関数値を生成する.

func(int) int

次の 2 つの呼び出し方法は等価である:

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

同様に,式

pt.Mp

は次の型の関数値を生成する.

func(float32) float32

セレクタと同様に, ポインターを使って値レシーバーをもつ非インターフェースメソッドへの参照は, 自動的にそのポインターを間接参照 (dereference) する: つまり,pt.Mv(*pt).Mv と等価である.

メソッド呼び出しと同様に, アドレス値を使ってポインターレシーバーをもつ非インターフェースメソッドへの参照は, 自動的にその値をアドレスをとる: つまり,t.Mp(&t).Mp と等価である.

f := t.Mv; f(7)   // t.Mv(7) と同様
f := pt.Mp; f(7)  // pt.Mp(7) と同様
f := pt.Mv; f(7)  // (*pt).Mv(7) と同様
f := t.Mp; f(7)   // (&t).Mp(7) と同様
f := makeT().Mp   // 無効: makeT() の結果はアドレスではない

上の例は非インターフェース型を使用しているが, インターフェース型の値からメソッド値を生成することは正当である.

var i interface { M(int) } = myVal
f := i.M; f(7)  // like i.M(7)

インデックス式

一次式

a[x]

は,配列, 配列へのポインター,スライス,文字列,または,マップ ax でインデックスされた要素を示す. 値 x はそれぞれ,インデックス (index) またはマップキー (map key) と呼ばれる. 以下のルールが適用される.

a がマップでない場合

a配列型 A の場合

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

aスライス型 S の場合

a文字列型の場合

aマップ型 M の場合

上記以外の場合,a[x] は不当である.

代入や初期化で使用される型 map[K]V のマップ a のインデックス式

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

は,追加の型なし真偽値を生成する. キー x がマップに存在するなら, ok の値は true であり, 存在しないなら,false である.

nil 要素の代入はランタイムパニックが発生する.

スライス式

スライス式 (slice expression) は, 文字列,配列,配列へのポインター,または,スライスから部分文字列,または,スライスを構築する. 2 つのバリアント (variant) がある: 下限と上限を指定する単純な形式 (simple form) と, 容量の上限も指定する完全な形式 (full form) である.

単純なスライス式

文字列,配列,配列へのポインター,または,スライスに対する一次式

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 インデックスがない場合は 0high インデックスがない場合は,スライスされたオペランドの長さとなる.

a[2:]  // a[2 : len(a)] と同じ
a[:3]  // a[0 : 3] と同じ
a[:]   // a[0 : len(a)] と同じ

a が配列へのポインターである場合, a[low : high](*a)[low : high] の省略形である.

配列か文字列の場合, インデックスは, 0 <= low <= high <= len(a) であれば,範囲内 (in range) であり, そうでなければ,範囲外 (out of range) である. スライスに対して, インデックスの場合, 長さではなく,スライスの容量 cap(a) である. 定数インデックスは,非負で,型 int表現可能でなければならない. 配列か定数文字列の場合, 定数インデックスは範囲内でなければならない. どちらのインデックスも定数であるなら, low <= high を満足しなければならない. 実行時にインデックスが範囲外であれば, ランタイムパニックが発生する.

型なし文字列を除いて, スライスされたオペランドが,文字列かスライスの場合, スライス演算の復帰は,オペランドとして同じ型の非定数値である. 型なし文字列オペランドの場合, 復帰は,型 string の非定数値である. スライスオペランド (sliced operand) が配列の場合, それはアドレス可能でなければならず, スライス演算の復帰は, 配列として同じ要素型をもつスライスである.

有効なスライス式のスライスオペランドが nil スライスである場合, 復帰は nil スライスである. そうでなければ,復帰がスライスであれば, それは,基底配列とオペランドを共有する.

var a [10]int
s1 := a[3:7]   // s1 の基底配列は配列 a; &s1[2] == &a[5]
s2 := s1[1:4]  // s2 の基底配列は s1 の基底配列である配列 a; &s2[1] == &a[5]
s2[1] = 42     // s2[1] == s1[2] == a[5] == 42; すべて,同じ基底配列の要素を参照する

完全なスライス式

配列,配列へのポインター,スライス a (文字列ではない)に対して, 一次式

a[low : high : max]

は,同じ型で単純なスライス表現 a[low : high] と同じ長さと要素を持つスライスを構築する. さらに, 復帰されるスライスの容量@@@ 最初のインデックスのみ省略でき,その値は 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 であることを主張する (assert). 表記 x.(T)型アサーション (type assertion) と呼ばれる.

より正確には, T がインターフェース型でない場合, x.(T)x の動的な型が型 T同一であることを主張する. このケースでは, Tx の(インターフェース)型を実装しなければならない. そうでなければ, x に型 T の値を格納できないので, 型アサーションは無効となる. T がインターフェース型であれば, x.(T)x の動的な型がインターフェース T を実装することを主張する.

型アサーションが成り立つとき, 式の値は, x に格納した値であり, その型は T である. もし,型アサーションが false であれば, ランタイムパニックが発生する. 言い換えると, x の動的な型を実行時にしかわからないとしても, 正しいプログラムでは, x.(T) の型は T であることがわかっている.

var x interface{} = 7          // x は動的な型 int を持ち,値 7 である
i := x.(int)                   // i は型 int を持ち,値 7

type I interface { m() }

func f(y I) {
	s := y.(string)        // 不当: string は I を実装しない (メソッド m がない)
	r := y.(io.Reader)     // r は型 io.Reader を持ち, y の動的な型は I と io.Reader の両方を実装しなければならない
	
}

代入や初期化で使用される型アサーション

v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
var v, ok interface{} = x.(T) // v と ok の動的な型は T と bool である

は,追加の型なし真偽値を生成する. アサーションが成り立つなら, ok の値は true であり, 存在しないなら,false であり, v の値は型 Tゼロ値になる. このケースでは,ランタイムパニックは発生しない.

呼び出し

関数型 F の式 f が与えられたとき,

f(a1, a2,  an)

は引数 a1, a2, … anf を呼び出す. 特別な場合を除いて, 引数は F のパラメーター型 (parameter type) に代入可能な単一の値をもつ式でなければならず, 関数が呼び出される前に評価される. その式の型は,F の復帰型 (return type) である. メソッド呼び出しは似ているが, メソッドはそれ自身が, メソッドのレシーバー型の値のセレクタとして指定される.

math.Atan2(x, y)  // 関数呼び出し
var pt *Point
pt.Scale(3.5)     // レシーバー pt を用いたメソッド呼び出し

関数呼び出しでは, 関数値と引数は,通常の順序で評価される. それらが評価されたあと, その呼び出しのパラメーターは, 関数の値として渡され, 呼び出された関数は実行を開始する. 関数が復帰するとき, 関数の復帰パラメーターは, 呼び出し元に値が渡される.

nil 関数値の呼び出しは, ランタイムパニックが発生する.

特別な場合として, 関数 g またはメソッド g の復帰値が, 他の関数 f またはメソッド f のパラメーターに @@@ 数が等しく,個別に代入可能なとき, 呼び出し f(g(g のパラメーター))f のパラメーターに g の復帰値を順番にバインドした後に実行される. 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 を含み, 引数リストに m のパラメーターリストが代入可能なら, メソッド呼び出し x.m() は有効である. fアドレス可能であり, &x のメソッド集合が,m を含むとき, x.m()(&x).m() の省略形である.

var p Point
p.Scale(3.5)

別のメソッド型やメソッドリテラルはない.

引数に ... パラメーターを渡す

f が 型 ...T の最後のパラメーター p をもつ可変長引数 (variadic) な場合 f 内では, p の型は,型 []T と等価である. f が,p の実際の引数なしで実行された場合, p に渡される値は,nil である. そうでなければ, その渡された値は, 連続する要素が実際の引数 (すべて T代入可能でなければならない) である新しい基底配列にもつ, 型 []T の新しいスライスである. そのため, スライスの長さと容量は p にバインドされる引数の数であり, 呼び出し位置毎に異なる場合がある.

次の関数と呼び出しを考えると,

func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")

Greeting 内では, 最初の呼び出しでは, whonil であり, 次の呼び出しでは,who[]string{"Joe", "Anna", "Eileen"} である.

最後の引数は,スライス型 []T に代入可能である場合, 引数の後に ... を続けると, ...T パラメーターの値がそのまま渡される. このケースでは,新しいスライスは生成されない.

次のスライス s と呼び出しを考えると,

s := []string{"James", "Jasmine"}
Greeting("goodbye:", s...)

Greeting 内では, s と同じ基底配列の値をもつ.

演算子

演算子 (operator) は,オペランドを式に結合する.

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   = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .

比較については,別の場所で説明する. 他の二項演算子の場合, 演算子がシフトか型なし定数の場合を除いて, オペランド型は同一でなければならない. 定数のみの演算の場合は,定数式節を参照されたい.

シフト演算を除いて, 一方のオペランドが型なし定数で, 他方のオペランドがそうでない場合, 定数は他方のオペランドの型に暗黙的に変換される.

シフト式における右のオペランドは, 整数型であるか,型 uint の値で表現可能な型なし定数でなければならない. 非定数シフト式の左のオペランドが型なし定数の場合, 最初に暗黙的にシフト式が左のオペランドに置き換えられた場合に想定される型に変換される.

var a [1024]byte
var s uint = 33

// 以下の例の結果は 64bit 整数に対して与えられる
var i = 1<<s                   // 1 は型 int をもつ
var j int32 = 1<<s             // 1 は型 int32 をもつ; j == 0
var k = uint64(1<<s)           // 1 は型 uint64 をもつ; k == 1<<33
var m int = 1.0<<s             // 1.0 は型 int をもつ; m == 1<<33
var n = 1.0<<s == j            // 1.0 は型 int をもつ; n == true
var o = 1<<s == 2<<s           // 1 と 2 は型 int をもつ; o == false
var p = 1<<s == 1<<33          // 1 は型 int をもつ; p == true
var u = 1.0<<s                 // 不当: 1.0 は型 float64, シフトできない
var u1 = 1.0<<s != 0           // 不当: 1.0 は型 float64, シフトできない
var u2 = 1<<s != 1.0           // 不当: 1 は型 float64, シフトできない
var v float32 = 1<<s           // 不当: 1 は型 float32, シフトできない
var w int64 = 1.0<<33          // 1.0<<33 は定数シフト式; w == 1<<33
var x = a[1.0<<s]              // panics: 1.0 は型 int をもつが, 1<<33 は配列境界をオーバーフローする
var b = make([]byte, 1.0<<s)   // 1.0 は型 int をもつ; len(b) == 1<<33

// 以下の例の結果は 32bit 整数に対して与えられる,
// つまり,シフトがオーバーフローすることを意味する.
var mm int = 1.0<<s            // 1.0 は型 int をもつ; mm == 0
var oo = 1<<s == 2<<s          // 1 と 2 は型 int をもつ; oo == true
var pp = 1<<s == 1<<33         // 不当: 1 は型 int をもつが, 1<<33 は int をオーバーフローする
var xx = a[1.0<<s]             // 1.0 は型 int をもつ; xx == a[0]
var bb = make([]byte, 1.0<<s)  // 1.0 は型 int をもつ; len(bb) == 0

演算子の優先順位

単項演算子は最も高い優先順位をもつ. ++ 演算子と -- 演算子は, 式 (expression) ではなく,文 (statement) を形成するため, これらは,演算子の階層の外である. 結果として,文 *p++(*p)++ と同じになる.

二項演算子には 5 つの優先順位がある. 乗算演算子 mul_op が最も強く, 加算演算子 add_op, 比較演算子 rel_op, 論理積 &&, 最後に,論理和 || が続く:

優先順位          演算子
    5             *  /  %  <<  >>  &  &^
    4             +  -  |  ^
    3             ==  !=  <  <=  >  >=
    2             &&
    1             ||

同じ優先順位の二項演算子は, 左から右に関連付けられる.(訳注:左結合性) 例えば, x / y * z(x / y) * z と同じである.

+x
23 + 3*x[i]
x <= f()
^a >> b
f() || g()
x == y+1 && <-chanInt > 0

算術演算子

算術演算子 (arithmetic operator) は, 数値に対して適用し, 最初のオペランドと同じ型の結果を生成する. 4 つの標準算術演算子 (+, -, *, /) は, 整数型,浮動小数点型,複素数型に適用する. + 演算子は文字列にも適用する. ビット単位論理演算子とシフト演算子は整数のみに適用する.

+    和                     整数, 浮動小数点, 複素数値, 文字列
-    差                     整数, 浮動小数点, 複素数値
*    積                     整数, 浮動小数点, 複素数値
/    商                     整数, 浮動小数点, 複素数値
%    剰余                   整数

&    ビット単位 AND         整数
|    ビット単位 OR          整数
^    ビット単位 XOR         整数
&^   ビットクリア (AND NOT) 整数

<<   算術左シフト           整数 << 符号なし整数
>>   算術左シフト           整数 >> 符号なし整数

訳注:ビットクリアは,ビット単位 AND (論理積) のNOT (否定) を計算する.

整数演算子

2 つの整数値 xy に対し, 整数商 (quotient) q = x / y と剰余 (remainder) r = x % y は, 次の関係を満足する.

x = q*y + r  かつ  |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

この規則の 1 つの例外は, 被除数 xxint 型における最も小さな値である (most negative value) とき, 2 の補数の整数オーバーフローのため, 商 q = x / -1 は,x と等しく, 剰余 r = 0 である.

			 x, q
int8                     -128
int16                  -32768
int32             -2147483648
int64    -9223372036854775808

除数が定数の場合,0 であってはならない. 実行時に除数が 0 であると, ランタイムパニックが発生する. 被除数が非負で,除数が定数の 2 の冪乗である場合, 算術右シフトに置き換えられ, 剰余計算は,ビット単位論理積に置き換えられることがある.

 x     x / 4     x % 4     x >> 2     x & 3
 11      2         3         2          3
-11     -2        -3        -3          1

シフト演算 (shift operator) は,右のオペランドで指定されるシフトカウント (shift count) によって,左のオペランドがシフトされる. そのため,左のオペランドは非負でなければならない. 実行時にシフトカウントが負の場合, ランタイムパニックが発生する. シフト演算子は, 左のオペランドが符号付き整数の場合,算術シフト (arithmetic shift) を, 左のオペランドが符号なし整数の場合,論理シフト (logical shift) を実装する. シフトカウントの上限はない. シフトは,左のオペランドがシフトカウント n に対して, n 回 1 シフトされるように動作する. 結果として,x << 1x * 2 と同じであり, x >> 1 は負の無限大に向かって切り捨てられるが, x / 2 と同じである.

整数オペランドに対して, 単項演算 +, -, ^ は以下のように定義される.

+x                          は 0 + x
-x    符号反転              は 0 - x
^x    ビット単位補完        は m ^ x  で, m はすべてのビットに 1 をセットしたもの (符号なし x の場合)
                                           m = -1  (符号付き x の場合)

整数オーバーフロー

符号なし整数に対して, 演算子 +, -, *, << は, 2^n を法として計算される. ここで,n符号なし整数型のビット幅である. 大まかに言うと, これら符号なし整数の演算は, オーバーフロー (overflow) した上位ビットを捨て, プログラムは,「ラップアラウンド」 (wrap arround) に依存することがある.

訳注: ラップアラウンドは,処理可能な範囲の最後に達した後に,最初に戻ること. 例えば,uint8 型の 0xff, 0x01 に対して, 0xff + 0x010x00 になる.

符号付き整数に対して, 演算子 +, -, *, << は, 正当にオーバーフローし, 復帰値は存在し, 復帰値は, 符号付き整数の表現,演算子,そのオペランドによって決定的に定義される. オーバーフローによるランタイムパニックは発生しない. コンパイラは, オーバーフローが発生しないことを仮定したコードの最適化は行わない場合がある. 例えば,x < x + 1 はいつでも true とは限らない.

浮動小数点演算子

浮動小数点数と複素数に対して, +xx と同じであるが, -xx の符号反転 (negation) である. 浮動小数点か複素数をゼロで割った復帰値は IEEE-754 標準で指定されていない. ランタイムパニックが発生するかどうかは,実装依存である.

実装では, 複数の浮動小数点数演算を (場合によっては,文を超えて) 単一の融合演算 (fused operation) に結合し, 命令を個別に実行および丸めて得られる値と異なる結果を生成する場合がある. 明示的な浮動小数点型への変換は, 変換先の型の精度へ丸める. これは,その丸めを破棄する融合を防ぐ.

例えば,一部のアーキテクチャでは, x * y + z の中間結果 x * y を丸めずに計算する 「融合積和演算 (fused multiply and add; FMA)」命令を提供する. 次の例は,Go 実装がその命令を使用できるか示している:

// FMA は r の計算を許す.なぜなら, x*y は明示的な丸めがないから
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 は r の計算を許さない.なぜなら,x*y の丸めを省略するから
r  = float64(x*y) + z
r  = z; r += float64(x*y)
t  = float64(x*y); r = t + z

文字列の連結

文字列 (string) は,+ 演算子か += 代入演算子を使って連結 (concatenate) できる.

s := "hi" + string(c)
s += " and good bye"

文字列の追加は, オペランドの連結によって新しい文字列が生成される.

比較演算子

比較演算子 (comparison operator) は, 2 つのオペランドを比較し, 型なしブール値を生成する.

==    等しい
!=    等しくない
<     小なり
<=    以下
>     大なり
>=    以上

任意の比較において, 最初のオペランドは, 2 つめのオペランドの型に, もしくはその逆に, 代入可能でなければならない.

等価演算子 (equality operator) ==!= は, 比較可能 (comparable) なオペランドに適用する. 順序演算子 (ordering operator) <, <=, >, >= は, 順序付けられる (ordered) オペランドに適用する. これらの項 (term) と比較結果は,以下のように定義される.

同一の動的な型をもつ 2 つのインターフェース値の比較は, もし,その型の値が比較可能でなければ, ランタイムパニックが発生する. この動作は,直接なインターフェース値の比較だけでなく, インターフェース値の配列や, インターフェース値のフィールドをもつ構造体の比較でも適用される.

スライス値,マップ値,関数値は比較可能ではない. しかし,特別な場合として, スライス値,マップ値,関数値が事前宣言された識別子 nil との比較される場合がある. ポインター値,チャンネル値,インターフェース値の nil との比較もまた, 許容され,上記の一般的な規則に従う.

const c = 3 < 4            // c は型なしブール定数 true

type MyBool bool
var x, y int
var (
	// 比較結果は,型なしブール値である.
	// 通常の代入規則が適用される.
	b3        = x == y // b3 は型 bool を持つ
	b4 bool   = x == y // b4 は型 bool を持つ
	b5 MyBool = x == y // b5 は型 MyBool を持つ
)

論理演算子

論理演算子 (logical operator) は, ブール値に適用され, オペランドと同じ型の復帰値を生成する. 右のオペランドは,条件付きで評価される.

&&    conditional AND    p && q  は  "もし p であれば q,そうでなければ false"
||    conditional OR     p || q  は  "もし p であれば true,そうでなければ q"
!     NOT                !p      は  "p ではない"

アドレス演算子

T のオペランド x に対して, アドレス演算 (address operation) &x は, 型 *Tx へのポインターを生成する. オペランドはアドレス可能 (addressable)でなければならない. つまり, 変数,ポインター間接参照,スライス indexing 演算 @@@ であるか, アドレス可能な構造体オペランドのフィールドセレクタであるか, アドレス可能な配列の配列 indexing @@@ 演算であるか でなければならない. アドレス可能性の要件の例外として, x が,(丸括弧で囲まれた)複合リテラルの場合もある. x の評価でランタイムパニックが発生するとき, &x の評価でも同様にランタイムパニックが発生する.

ポインター型 *T のオペランド x に対して, ポインター間接参照 *xx によってさされる型 T変数を示す. xnil の場合, *x の評価への試みは, ランタイムパニックが発生する.

&x
&a[f(2)]
&Point{2, 3}
*p
*pf(x)

var x *int = nil
*x   // ランタイムパニックが発生
&*x  // ランタイムパニックが発生

受信演算子

チャンネル型のオペランド ch に対して, 受信演算 (receive operation) <-ch の値は, チャンネル ch から受信された値である. チャンネルの向きは, 受信演算を許可されていなければならず, 受信演算の型は,チャンネルの要素型である. 値が利用可能になるまで,式はブロックされる. nil チャンネルからの受信は,永遠にブロックされる. 閉じたチャンネルでの受信演算は,いつでも, すぐに続行し, 前に送信された値が受信された後, 要素型のゼロ値が生成される.

v1 := <-ch
v2 = <-ch
f(<-ch)
<-strobe  // クロックパルスまで待機し,受信した値を破棄する

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

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

通信が成功したかを報告する追加の型なしブール値を復帰する. 受信した値が, チャンネルへの成功した送信演算によって配信された場合, ok の値は true である. チャンネルが閉じられたか空であるため,ゼロ値が生成された場合は, ok の値は false である.

変換

変換 (conversion) は, 式のをその変換によって指定された型へ変更する. 変換は,ソースに文字通り現れるか, 式が現れる文脈によって,暗黙的 (implied) である場合がある.

明示的 (explicit) 変換は, T を型, 型 T に変換可能な式を x として, 形式 T(x) である.

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

型が, 演算子 *<- で始まっているか, 型が, キーワード func で始まっており,復帰値を持たない場合, 曖昧性を回避するために,必要に応じて,丸括弧で囲まなければならない:

*Point(p)        // *(Point(p)) と同じ
(*Point)(p)      // p は,*Point に変換される
<-chan int(c)    // <-(chan int(c)) と同じ
(<-chan int)(c)  // c は,<-chan int に変換される
func()(x)        // 関数シグネチャー func() x
(func())(x)      // x は func() に変換される
(func() int)(x)  // x は func() int に変換される
func() int(x)    // x は(曖昧性なしに)func() int に変換される

定数x は, xT の値として表現可能であれば, 型 T に変換される. 特別なケースとして, 整数定数 x は, 非定数 x のように同じルールを使用して明示的に文字列型に変換できる.

定数を変換すると,型付き定数が復帰される.

uint(iota)               // 型 uint の iota 値
float32(2.718281828)     // 型 float32 の 2.718281828
complex128(1)            // 型 complex128 の 1.0 + 0.0i
float32(0.49999999)      // 型 float32 の 0.5
float64(-1e-1000)        // 型 float64 の 0.0
string('x')              // 型 string の "x"
string(0x266c)           // 型 string の "♬"
MyString("foo" + "bar")  // 型 MyString の "foobar"
string([]byte{'a'})      // 定数ではない: []byte{'a'} は定数ではない
(*int)(nil)              // 定数ではない: nil は定数ではない, *int はブール型,数値型,文字列型ではない
int(1.2)                 // 不当: 1.2 は int で表現不可能
string(65.0)             // 不当: 65.0 は整数定数で表現不可能

非定数値 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)  // タグは無視する.基底型は同一である

特別な規則が, 数値型間の(非定数)変換, 文字列型へ,または文字列型からの(非定数)変換に適用される. これらの変換は, x の表現を変更し, 実行時のコストが発生する場合がある. すべての他の変換は,単に型を変更するだけであり, x の表現は変更されない.

ポインターと整数の間で変換する言語メカニズムはない. パッケージ unsafeは制限された状況下で,この機能を実装する.

数値型間の変換

非定数数値の変換では,以下の規則が適用される.

  1. 整数型間で変換するとき, その値が符号付き整数であるなら, 暗黙的に無限大精度に拡張された符号である. それ以外の場合は,拡張されたゼロである. 復帰型のサイズにあうように切り捨てられる. 例えば, v := uint16(0x10F0) であれば, uint32(int8(v)) == 0xFFFFFFF0 となる. 変換はいつでも,有効な値を生成し, オーバーフローの兆候 (indication) はない.
  2. 浮動小数点数から整数への変換では, 小数部は破棄される (ゼロに向かって切り捨て).
  3. 整数か浮動小数点から,浮動小数点への変換または, 複素数値から,他の複素型へ変換するとき, 復帰値は,変換先の型で指定された精度に丸められる. 例えば,float32 型の変数の値は, 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"
  1. バイトのスライスを文字列へ変換すると, 連続したバイトをスライスの要素とする文字列を生成される.
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ø"
  1. ルーンのスライスを文字列型へ変換すると, 個々のルーン値を連結した文字列が生成される.
string([]rune{0x767d, 0x9d6c, 0x7fd4})   // "\u767d\u9d6c\u7fd4" == "白鵬翔"
string([]rune{})                         // ""
string([]rune(nil))                      // ""

type MyRunes []rune
string(MyRunes{0x767d, 0x9d6c, 0x7fd4})  // "\u767d\u9d6c\u7fd4" == "白鵬翔"
  1. 文字列型の値をバイト型のスライスへ変換すると, 連続した要素がその文字列のバイトたちであるスライスが生成される.
    []byte("hellø")   // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
    []byte("")        // []byte{}

    MyBytes("hellø")  // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
  1. 文字列型の値をルーン型のスライスへ変換すると, 文字列の個々の Unicode 符号位置を含むスライスが生成される.
    []rune(MyString("白鵬翔"))  // []rune{0x767d, 0x9d6c, 0x7fd4}
    []rune("")                 // []rune{}

    MyRunes("白鵬翔")           // []rune{0x767d, 0x9d6c, 0x7fd4}

定数式

定数式 (constant expression) は, 定数オペランドのみを含み, コンパイル時に評価される.

型なしブール定数, 型なし数値定数, 型なし文字列定数は, それぞれ, ブール型,数値型,文字列型のオペランドの使用が正当な場合には, オペランドとして使用できる.

定数の比較はいつでも,型なしブール定数を生成する. 定数シフト式の左のオペランドが,型なし定数の場合, 復帰値は整数定数である. そうでなければ,左のオペランドと同じ型の定数であり, それは,整数型でなければならない.

型なし定数における他のオペランドは, 同じ種類の型なし定数を復帰する. つまり, ブール定数,整数定数,浮動小数点定数,複素数定数,文字列定数である. 二項演算(シフト演算を除く)の型なしオペランドの種類が,異なる場合, 復帰値は, 整数,ルーン,浮動小数点,複素数の後半のオペランドの種別になる.@@@ 例えば,型なし整数定数は, 型なし複素数定数で割ると, 型なし複素数定数が生成される.

const a = 2 + 3.0          // a == 5.0   (型なし浮動小数点定数)
const b = 15 / 4           // b == 3     (型なし整数定数)
const c = 15 / 4.0         // c == 3.75  (型なし浮動小数点定数)
const Θ float64 = 3/2      // Θ == 1.0   (型 float64, 3/2 は整数除算)
const Π float64 = 3/2.     // Π == 1.5   (型 float64, 3/2. は浮動小数除算)
const d = 1 << 3.0         // d == 8     (型なし整数定数)
const e = 1.0 << 3         // e == 8     (型なし整数定数)
const f = int32(1) << 33   // 不当       (定数 8589934592 は int32 でオーバーフローする)
const g = float64(2) >> 1  // 不当       (float64(2) は型付き浮動小数点定数)
const h = "foo" > "bar"    // h == true  (型なしブール定数)
const j = true             // j == true  (型なしブール定数)
const k = 'w' + 1          // k == 'x'   (型なしルーン定数)
const l = "hi"             // l == "hi"  (型なし文字列定数)
const m = string(k)        // m == "x"   (型 string)
const Σ = 1 - 0.707i       //            (型なし複素数定数)
const Δ = Σ + 2.0e-4       //            (型なし複素数定数)
const Φ = iota*1i - 1/1i   //            (型なし複素数定数)

ビルトイン関数 complex を, 型なし整数定数, 型なしルーン定数, 型なし浮動小数点定数に適用すると, 型なし浮動小数点定数が生成される.

const ic = complex(0, c)   // ic == 3.75i  (型なし複素数定数)
const iΘ = complex(0, Θ)   // iΘ == 1i     (型 complex128)

定数式はいつも正確に評価される; 中間値と定数自身は, 言語が事前宣言した型によってサポートされる精度より遥かに大きな精度を要求する場合もある. 以下は,正当な宣言である.

const Huge = 1 << 100         // Huge == 1267650600228229401496703205376  (型なし整数定数)
const Four int8 = Huge >> 98  // Four == 4                                (型 int8)

定数除算や剰余演算の除数はゼロであってはならない:

3.14 / 0.0   // 不当:0 による除算

型付き定数の値は, 定数型の値によって正確に表現可能でなければならない. 以下の定数表現は,正当である:

uint(-1)     // -1 は uint で表現できない
int(3.14)    // 3.14 は int で表現できない
int64(Huge)  // 1267650600228229401496703205376 は int64 で表現できない
Four * 300   // オペランド 300 は (Four の型である) int8 で表現できない
Four * 100   // 積 400 は (Four の型である) int8 で表現できない

単項ビット単位補完 (bitwise complement) 演算子 ^ は, 非定数に対する規則に一致する. マスクは, 符号なしの場合はすべて 1 の定数と, 符号付き型なし定数の場合は -1 である.

^1         // 型なし整数定数で, -2 と等しい
uint8(^1)  // 不当: uint8(-2) と同じ,-2 は uint8 で表現できない
^uint8(1)  // 型 uint8 定数, 0xFF ^ uint8(1) = uint8(0xFE) と同じ
int8(^1)   // int8(-2) と同じ
^int8(1)   // -1 ^ int8(1) = -2 と同じ

実装上の制限: コンパイラは, 型なし浮動小数点定数式,または,複素数定数式を計算するときに, 丸めを使用することがある. 定数節における実装上の制限を参照せよ. 無限の精度を使用して計算して整数になったとしても, この丸めは,浮動小数点定数式が, 整数のコンテキストでは無効になる場合がある.

評価順序

パッケージレベルでは, 初期化の依存関係 (initialization dependency) によって, 変数宣言の個々の初期化式の評価順序 (evaluation order) が決まる. それ以外の場合には, 式,代入,returnの評価のとき, すべての関数呼び出し,メソッド呼び出し,通信演算は, 字句的に左から右の順序で評価される.

例えば,(関数ローカルな)代入では,

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

関数呼び出しと,通信は, f(x), h(), i(), j(), <-c, g(), k() の順序で発生する. しかし, これらのイベントの評価と, x のインデックスの作成, y の評価の順序は,指定されていない.

a := 1
f := func() int { a++; return a }
x := []int{a, f()}            // x は [1, 2] か [2, 2] である: a と f() の評価順序は指定されていない
m := map[int]int{a: 1, a: 2}  // m は {2: 1} か {2: 2} である: 2 つのマップの代入間の順序は指定されていない
n := map[int]int{a: f()}      // n は {2: 3} か {3: 3} である: キーと値の評価順序は指定されていない

パッケージレベルでは, 初期化の依存関係は,個々の初期化式に対する左から右へのルールで上書きされるが, どちらの式にも含まれるオペランドに対しては,上書きされない.

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 }

// 関数 u と v はすべての他の変数と関数から独立している

関数呼び出しは, u(), sqr(), v(), f(), v(), g() の順序で発生する.

単一の式に含まれる浮動小数点演算は, 演算子の結合性に従って評価される. 明示的な丸括弧は, デフォルトの結合性を上書きして評価に影響を与える. 式 x + (y + z) は,x の加算の前に加算 y + z が実行される.

文 (statement) は実行を制御する.

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

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

終端文

終端文 (terminating statement) 同一ブロック内で,その後に字句的に現れるすべての文の実行を防ぐ. 次の文は終端である.

  1. return文またはgoto
  2. ビルトイン関数 panicの呼び出し
  3. 文のリストが終端文によって終わる ブロック
  4. ifであり,
    • else 節があり,かつ
    • どちらの節も終端文である.
  5. forで,
    • その for 文を参照する break 文がない,かつ
    • ループ条件が省略されている.
  6. switchであり,
    • その switch 文を参照する break 文がない,かつ,
    • default ケースがある,かつ,
    • default を含むいずれの文のリストも,終端文で終わるか, ラベル付けされたfallthroughである.
  7. selectであり,
    • その select 文を参照する break 文がない,かつ,
    • default を含むいずれの文リストも,終端文で終わる.
  8. 終端文をラベル付けするラベル文

他のすべての文は終端ではない.

リストが空でなく,その最後の非空文が終端である場合, 文リストは,終端文で終了する.

空文

空文 (empty statement) は何もしない.

EmptyStmt = .

ラベル文

ラベル文 (labeled statement)は, goto文,break文,continue文のターゲットになる.

式文 (expression statements)

特定のビルトイン関数を除いて, 関数呼び出しとメソッド呼び出しと受信演算は, 文コンテキストに現れうる. そのような文は,丸括弧で囲まれている場合がある.

ExpressionStmt = Expression .

以下のビルトイン関数は,文コンテキスト内では使用できない.

append cap complex imag len make new real
unsafe.Alignof unsafe.Offsetof unsafe.Sizeof
h(x+y)
f.Close()
<-ch
(<-ch)
len("foo")  // len がビルトイン関数である場合は不当

送信文

送信文 (send statement) はチャンネルで,値を送信する. チャンネル式は,チャンネル型であり, チャンネルの方向は送信演算を許可し, 送信される値の型は,チャンネルの要素型に代入可能でなければならない.

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

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

ch <- 3  // 値 3 をチャンネル ch に送信

インクリメント文,デクリメント文

++ 文と -- 文は, 型なし定数 1 によってそれらのオペランドをインクリメント (increment),または,デクリメント (decrement)する. 代入と同様に, オペランドは,アドレス可能であるか, マップのインデックス式でなければならない.

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  // k = <-ch と同じ

代入演算 (assignment operation) x op= y は, x = x op (y) と等価であるが, x は一度しか評価されない. ここで op は二項算術演算子とする. op= は単一のトークンである. 代入演算において,左側の式リストも右側の式リストもどちらも ちょうどひとつの単一の値をもつ式でなければならず, 左側の式は,ブランク識別子であってはならない.

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

代入の組は, 多値演算の個々の要素を変数のリストに代入する. 2 つの形式がある. 1 つめの形式は,右辺のオペランドが 関数呼び出し,チャンネル演算,マップ演算, 型アサーションのような 単一の多値をもつ式である. 左辺のオペランドの数は,右辺の値の数と一致しなければならない. 例えば,f が 2 値を復帰する関数の場合,

x, y = f()

は,最初の値は x に, 2 番目の値は y に代入される. 2 つめの形式では, 左辺のオペランドの数が, 右辺の式の数が等しく, すべての式は単一の値を復帰しなければならず, 右辺の n 番目の式は, 左辺の n 番目のオペランドに代入される.

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

ブランク識別子は代入における右辺の値を無視する方法を提供する:

_ = x       // x は評価するが,その値は無視する
x, _ = f()  // f() は評価するが,2 番目の復帰値は無視する

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

a, b = b, a  // a と b を交換する

x := []int{1, 2, 3}
i := 0
i, x[i] = 1, 2  // i = 1, x[0] = 2 を設定する

i = 0
x[i], i = 2, 1  // x[0] = 2, i = 1 を設定する

x[0], x[0] = 1, 2  // x[0] = 1 を設定した後,x[0] = 2 を設定する (最終的に x[0] == 2)

x[1], x[3] = 4, 5  // x[1] = 4 を設定した後, x[3] = 5 でパニックが起きる

type Point struct { x, y int }
var p *Point
x[2], p.x = 6, 7  // x[2] = 6 を設定し,p.x = 7 でパニックが起きる

i = 2
x = []int{3, 5, 7}
for i, x[i] = range x {  // i, x[2] = 0, x[0] を設定する
	break
}
// このループの後, i == 0 と x == []int{3, 5, 3} である

代入では,すべての値が 代入されるオペランドの型に代入可能でなければならず, 次の特殊なケースがある:

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

if文

if 文は, ブール式 Expression の値に従って, 2 つの分岐の条件付き実行を指定する. ブール式が true と評価された場合, if 節が実行される. そうでない場合で, もしあれば,else 節が実行される.

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

ブール式が評価されるまでに実行される 単順な式 SimpleStmt をブール式の前に置くことができる.

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

switch文

switch 文は, 多方向の実行を提供する. 式か型指定子は, switch 内の ケース (case) たちと比較され,実行する節が決定する.

SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .

式スイッチ (expression switch, ExprSwitchStmt) と,型スイッチ (type switch, TypeSwitchStmt) の 2 つの形式がある. 式スイッチでは, case は, スイッチ式 (Expression) の値と比較可能な式を含む. 型スイッチでは, case は, 特別に注釈がつけられたスイッチ式の型と比較可能な型を含む. スイッチ式は,スイッチ文内で,一度だけ評価される.

式スイッチ

式スイッチでは, スイッチ式 (Expression) は評価され, ケース式 (定数である必要はない) は,左から右へ,そして,上から下へ評価される. スイッチ式と等価な最初のものが, 関連するケースの文の実行のトリガーとなる. それ以外のケースはスキップされる. どのケースもマッチせず, default ケースが存在する場合には, default ケースの文が実行される. 多くとも一つの default ケースが存在でき, switch 文内のどこに現れても良い. スイッチ式 (Expression) を省略した場合は, ブール値 true を指定された場合と等価である.

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

スイッチ式が型なし定数と評価された場合, その定数は最初に暗黙的にそのデフォルト型変換される. もし,それが型なしブール値なら,最初に型 boolに暗黙的に変換される. 事前宣言された型なし値 nil は スイッチ式として使用できない.

ケース式が型なしなら, 最初にスイッチ式の型に暗黙的に変換される. 各(変換された)ケース式 x とスイッチ式の値 t に対して, x == t は有効な比較でなければならない.

言い換えると, スイッチ式は,明示的な型なしで一時的に変数 t として宣言,初期化されたように扱われ, 各ケース式 xt の値と等しいかどうかテストされる.

ケース句か default 句では, 最後の空でない文が, 制御がこの句の最後から次の句の最初の文へ流れることを示す (ラベル付き) fallthrough の場合がある. そうでなければ,制御は switch 文の最後に行く. fallthrough 文は, 式スイッチの最後の句を除いて,すべての最後の文に表示できる.

スイッチ式が評価されるまでに実行される 単順な式 SimpleStmt をブール式の前に置くことができる.

switch tag {
default: s3()
case 0, 1, 2, 3: s1()
case 4, 5, 6, 7: s2()
}

switch x := f(); {  // スイッチ式を省略すると "true" を意味する
case x < 0: return -x
default: return x
}

switch {
case x < y: f1()
case x < z: f2()
case x == 4: f3()
}

実装上の制限: コンパイラは, 同じ定数に評価される 複数のケース式を許可しない場合がある. 例えば, 現在のコンパイラでは, ケース式で 整数定数,浮動小数点定数,文字列定数の重複を許可していない.

型スイッチ

型スイッチ (type switch) は, 値ではなく,型を比較する. それ以外は式スイッチと同様である. 実際の型ではなく,予約後 type を使って, 型アサーションの形式を持つ 特別なスイッチ式によってマークされる.

switch x.(type) {
// cases
}

次に,ケースは 実際の型 T を 式 x の動的な型と 照合する. 型アサーションと同様に, xインターフェース型でなければならないし, ケースにリストされる 各非インターフェース型 Tx の型を実装しなければならない. 型スイッチのケースたちにリストされる型はすべて異ならなければならない.

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

TypeSwitchGuard は簡潔な変数宣言 SimpleStmt を含めることができる. その形式が使用されると, その変数は 各句の暗黙的なブロックTypeSwitchCase の最後で宣言される. TypeList に一つの型のみを並べるケース句では, 変数はその型をもつ. そうでなければ, 変数は,TypeSwitchGuard における式の型をもつ.

型の代わりに, 事前宣言された識別子 nil が使用されることがある; その場合には,TypeSwitchGuard における式が nil インターフェース値 @@@ である場合に選択される. 多くとも一度だけ nil ケースが許される.

interface{} の式 x が与えられたとき, 以下の型スイッチを考えると,

switch i := x.(type) {
case nil:
	printString("x is nil")                // i の型は x の型である (interface{})
case int:
	printInt(i)                            // i の型は int の型である
case float64:
	printFloat64(i)                        // i の型は float64 の型である
case func(int) float64:
	printFunction(i)                       // i の型は func(int) float64 の型である
case bool, string:
	printString("type is bool or string")  // i の型は x の型 (interface{}) である
default:
	printString("don't know the type")     // i の型は 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")
	}
}

型スイッチガード TypeSwitchGuard は ガードが評価されるまでに実行される 単順な式 SimpleStmt をブール式の前に置くことができる.

fallthrough は型スイッチでは許可されていない.

for文

for 文はブロックの繰り返し実行を指定する. 反復 (iteration) は, 単一の条件で指定, for 句で指定, range 句で指定で制御する 3 つの形式がある.

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

単一条件の for

最も単純な形式では, for 文は, ブール条件 Conditiontrue と評価される限り ブロックの繰り返し実行を指定する. ブール条件は,各反復の前に評価される. ブール条件が省略された場合は, true が指定された場合と等価である.

for a < b {
	a *= 2
}

for 句を用いた for

ForClause を用いた for 文もまた, その条件によって制御されるが, 追加で, 代入のような 初期化文 (init statement; InitStmt) と, インクリメント文やデクリメント文のような 更新文 (post statement; PostStmt @@@反復文・後処理文… a tour of Go 日本語訳では,後処理文) が指定される. 初期化文は,簡潔な変数宣言の場合があるが, 更新文はそうではない. 初期化文における 変数宣言は,各反復で再利用される.

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

空でない場合, 初期化文が最初の反復の条件の評価の前に一度だけ実行される. 更新文は, (ブロックが実行された場合のみ) そのブロックの各反復の後に実行される. ForClause の任意の要素は,空でも良いが, セミコロンは,条件しかない場合を除いて必須である. 条件が省略された場合は, true が指定された場合と等価である.

for cond { S() }    は次と同じである    for ; cond ; { S() }
for      { S() }    は次と同じである    for true     { S() }

range 句を用いた for

range 句を用いた for 文は, 配列,スライス,文字列,マップ,チャンネルが受信した値のすべての エントリーを反復する. 各エントリーでは,もしあれば, 反復値 (iteration value) は, 反復変数 (iteration variable) に代入され, ブロックが実行される.

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

range 句の右側の式は, 範囲式 (range expression) と呼ばれる. これは,配列,配列へのポインター,スライス,文字列,マップ, 受信演算が許可されたチャンネルの場合がある. 代入の場合と同様に,指定された場合には, 反復変数を表す 左側にオペランドは, アドレス可能であるか map index 式でなければならない. 範囲式がチャンネルの場合, 多くともひとつの反復変数が許され, そうでなければ,最大 2 つまでである. 最後の反復変数が,ブランク識別子の場合, range 句は,識別子が指定されなかった場合と等価である.

範囲式 x は,ひとつの例外を除いて, ループの開始前に一度だけ評価される. 多くともひとつの反復変数が指定され, len(x)定数の場合, 範囲式は評価されない.

左側の関数呼び出しは反復毎に一度だけ評価される. 各反復では,反復変数は,対応する反復変数が存在する場合, 以下のように生成される.

範囲式                                    1つ目の値                2つ目の値

array or slice  a  [n]E, *[n]E, or []E    インデックス   i  int    a[i]       E
string          s  string type            インデックス   i  int    以下参照   rune
map             m  map[K]V                キー           k  K      m[k]       V
channel         c  chan E, <-chan E       要素           e  E
  1. 配列,配列へのポインター,またはスライス値の a に対して, インデックス反復値は,0 から始まる要素インデックスが昇順で生成される. 多くともひとつの反復変数が指定された場合, 範囲ループは, 0 から len(a) - 1 までの反復値が生成され, 配列やスライス自身インデックスされない. nil スライスに対しては,反復数は 0 である.
  2. 文字列値に対して, range 句は,0 から始まるバイトインデックスにおける Unicode 符号位置を反復する. 連続する反復では, 「1つ目の値」インデックス値は, 文字列における UTF-8 エンコードされた符号位置の最初のバイトのインデックスであり, 型 rune である「2つ目の値」は対応する符号位置の値になる. 反復が,無効な UTF-8 列を検出すると, 「2つ目の値」は 0xFFFD (Unicode 置換文字) になり, 次の反復は,文字列の 1 バイトに進む.
  3. マップでの反復順序は,指定されないし, 次の反復が前の反復とで反復順序が同じことは保証されない. マップのエントリーが,反復の途中で, そのエントリーに達する前に削除された場合, 対応する反復値は生成されない. 新しいマップのエントリーが反復中に生成されると, そのエントリーは,反復中に生成されるかもしれないし,飛ばされるかもしれない. エントリーが生成されるかの選択は, 各生成されるエントリーに毎に,また,反復毎に異なるかもしれない. マップが nil の場合,反復数は 0 である.
  4. チャンネルに対して, 生成される反復値は チャンネルが閉じられるまでチャンネルに送信される連続値である. チャンネル nil の場合,範囲式は永久にブロックされる.

反復値は,代入文における反復変数に代入される.

反復変数は, 簡潔な変数宣言 (:=) の形式を使って, range 句によって宣言される. この場合, 反復変数の型は, 対応する反復値の型が代入され, 反復変数のスコープは,for 文のブロックであり, 反復変数は,各反復で再利用される. 反復変数は, for 文の外で宣言される場合, 実行後に,反復変数の値は,最後の反復の値になる.

var testdata *struct {
	a *[7]int
}
for i, _ := range testdata.a {
	// testdata.a は評価されない:len(testdata.a) は定数だから
	// i は 0 から 6 の範囲である
	f(i)
}

var a [10]string
for i, s := range a {
	// i の型は int
	// s の型は string
	// s == a[i]
	g(i, s)
}

var key string
var val interface{}  // m の要素型は 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 == 反復での最後の map キー
// val == map[key]

var ch chan Work = producer()
for w := range ch {
	doWork(w)
}

// 空のチャンネル
for range ch {}

go文

go 文は 同じアドレス空間内で, 制御の独立した並行スレッドか,ゴルーチン (goroutine) として関数呼び出しの実行を開始する.

GoStmt = "go" Expression .

Expression は,関数呼び出しかメソッド呼び出しでなければならず, 丸括弧で囲うことはできない. ビルトイン関数の呼び出しは,式文と同様に制限されている.

関数値とパラメーターは,呼び出し側のゴルーチンの内で,通常通り評価されるが, 通常の呼び出しとは異なり, プログラムの実行は実行された関数の完了を待たない. 代わりに,関数は新しいゴルーチン内で独立に実行を開始する. 関数が停止したら,そのゴルーチンもまた停止する. 関数が何かしらの復帰値を持っていたら, それらは関数が完了すると破棄される.

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

select文

select 文は, 可能な送信演算受信演算の どちらを続行するかを選択する. これは,switch文に似ているが, すべての case は通信演算 (communication operation) を参照している.

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

RecvStmt を伴う case は, RecvExpr の復帰を 1 つまたは 2 つの変数に代入する. これらの変数は, 簡潔な変数宣言が使用される場合がある. RecvExpr は,(丸括弧で囲まれた)受信演算でなければならない. 多くともひとつの default case が存在し, case 文のリストのどこに書いても良い.

select 文の実行は以下のステップで進行する.

  1. select 文におけるすべての case は, 受信演算のチャンネルオペランドと, 送信文の右辺の式は, select 文に入ったときに, ソース順で, 一度だけ評価される. 復帰値は, 受信または送信するチャンネルの集合と, 送信する対応した値である. その評価での副作用は, どの通信演算 (存在する場合) を選択して続行するかに関係なく発生する. 簡潔な変数宣言か代入を伴う RecvStmt の左辺の式はまだ評価されない.
  2. 1 つ以上の通信が続行できる場合, 続行可能な単一のものが,一様擬似乱数により選択される. そうでなければ,もし,default があれば,それが選択される. もし,default がなければ,select 文は少なくとも 1 つの通信が続行できるようになるまで, ブロックする.
  3. 選択された casedefault でない場合, 対応する通信演算が実行される.
  4. 選択された case が簡潔な変数宣言か代入を伴う RecvStmt の場合, 左辺の式は評価され,受信値が代入される.
  5. 選択された case の文リストは実行される.

nil チャンネルの通信は継続されないので, nil チャンネルを伴う selectdefault をもたないとき, 永久にブロックされる.

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):  // 次と同じ: i3, ok := <-c3
	if ok {
		print("received ", i3, " from c3\n")
	} else {
		print("c3 is closed\n")
	}
case a[f()] = <-c4:
	// 次と同じ:
	// case t := <-c4
	//	a[f()] = t
default:
	print("no communication\n")
}

for {  // c にビットのランダム列を送信する
	select {
	case c <- 0:  // 注意: 文なし, fallthrough なし, no folding of cases@@@
	case c <- 1:
	}
}

select {}  // 永久にブロックされる

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 文の式リスト (ExpressionList) は,多値を復帰する関数の単一の呼び出しである. その結果, その関数から復帰された値が対応する値の型をもつ一時変数に代入され, その後, (前の方法のように)その一時変数をリストする return 文が続くようになる.
     func complexF2() (re float64, im float64) {
     	return complexF1()
     }
    
  3. 関数の復帰型が復帰パラメーターの名前が指定されているとき, 式リスト (ExpressionList) は空である. 復帰パラメーターは,通常のローカル変数として機能し, 必要に応じて代入される. 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 場所と同じスコープにあるとき, 空の式リストをもつ return 文を許可しない場合がある.

func f(n int) (res int, err error) {
	if _, err := f(n-1); err != nil {
		return  // 無効な return 文: err は隠される
	}
	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 statement) で次の反復を開始する. 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--
}

は,ラベル L1for 文のブロック内にあるが, goto はそうではないため,エラーになる.

fallthrough文

fallthrough 文は switchにおける,次の case 句の最初の文に制御を転送する. それは,そのような句の最後の空でない文としてのみ使用できる.

FallthroughStmt = "fallthrough" .

defer文

defer 文は, returnに達するか, 関数本体の最後に達するか 対応するゴルーチンがパニックで落ちることによって defer 文を囲む親関数 (surrounding function) が 復帰するときまで実行が遅延された (deferred) 関数を呼び出す.

DeferStmt = "defer" Expression .

Expression は(丸括弧で囲まれていない)関数呼び出しかメソッド呼び出しでなければならない. ビルトイン関数の呼び出しは,式文と同様に制限されている.

defer 文が実行されるたびに, その呼び出しでの 関数値とパラメーターは,通常通り評価され, 新たに保存される (saved anew) が, 実際の関数は呼び出されない. 代わりに,遅延された関数は, 親関数が復帰する直前に 関数が遅延される順番と逆順に 呼び出される. つまり,親関数が 明示的な returnで復帰する場合, すべての復帰パラメーターが,その復帰文で設定された後で, 関数が呼び出し元に戻る前に 遅延関数は実行される. 遅延関数の値が nil の場合, defer 文が実行されるときではなく, その遅延関数が呼び出されるときに, 実行はパニックする.

例えば, 遅延関数が関数リテラルであり, 親関数が リテラルのスコープに属する名前付き復帰パラメーターを持つとき, 遅延関数は,それらが復帰する前に関数パラメーターはアクセスされ,変更される. 遅延関数が復帰値をもつとき, 関数が完了すると破棄される. (パニックの対処節を参照)

lock(l)
defer unlock(l)  // 親関数が復帰する前に unlock する

// 親関数が復帰する前に 3 2 1 0 を表示する
for i := 0; i <= 3; i++ {
	defer fmt.Print(i)
}

// f は 42 を復帰する
func f() (result int) {
	defer func() {
		// result は return 文で 6 が設定されたあと,アクセスされる
		result *= 7
	}()
	return 6
}

ビルトイン関数

ビルトイン関数(組み込み関数; built-in function) は事前宣言されている. ビルトイン関数は, 他の関数のように呼び出されるが, 一部は,最初の引数として式の代わりに型を受け入れる.

ビルトイン関数は,標準的な go 型を持たないため, ビルトイン関数は呼び出し式においてのみ現れる. ビルトイン関数は関数値として使用できない.

閉じる

チャンネル c に対して, ビルトイン関数 close(c) は チャンネルに送信する値がないことを記録する. c が受信専用チャンネルの場合,エラーになる. 閉じたチャンネルに対して送信するか,閉じるとランタイムパニックが発生する. nil チャンネルを閉じると同様にランタイムパニックが発生する. close を呼び出したあとで, 前に送った値が受信されたあと, 受信演算は,ブロックすることなしにチャンネルの型のゼロ値を返す. 多値受信演算は, チャンネルが閉じられているかどうかの表示とともに受信値を返す.

長さと容量

ビルトイン関数 lencap は, 多様な型の引数をとり, 型 int の値を復帰する. 実装は,復帰値がいつでも int に収まることを保証する

呼び出し  引数の型         復帰値

len(s)    string 型        バイトでの文字列長
          [n]T, *[n]T      配列長 (== n)
          []T              スライス長
          map[K]T          マップ長 (定義されたキーの数)
          chan T           チャンネルバッファーにキューイングされた要素数

cap(s)    [n]T, *[n]T      配列長 (== n)
          []T              スライスの容量
          chan T           チャンネルバッファの容量

スライスの容量は, 基底配列で割り当てられた空間の要素数である. いつでも以下の関係が成り立つ.

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

nil スライス,nil マップ,nil チャンネルの長さは 0 である. nil スライス,nil チャンネルの容量は 0 である.

s が文字列定数のとき 式 len(s)定数である. s の型が配列,配列へのポインターの型であり, sチャンネル受信機か, (非定数な)関数呼び出しを含まないとき, 式 len(s) と式 cap(s) は定数である. このケースでは, s は評価されない. そうでなければ, lencap の呼び出しは,定数ではなく, s は評価される.

const (
	c1 = imag(2i)                    // imag(2i) = 2.0 は定数
	c2 = len([10]float64{2})         // [10]float64{2} 関数呼び出しを含まない
	c3 = len([10]float64{c1})        // [10]float64{c1} 関数呼び出しを含まない
	c4 = len([10]float64{imag(2i)})  // imag(2i) は定数で,関数呼び出しの問題がない
	c5 = len([10]float64{imag(z)})   // 無効: imag(z) は (非定数) 関数呼び出し
)
var z complex128

割り当て

ビルトイン関数 new は型 T を取り, 実行時にその型の変数の格納域を割り当て (allocate), それをポイントする型 *T の値を復帰する. 変数は,初期値節で説明するように初期化される.

new(T)

例えば,

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

は,型 S の変数の保存域を割り当て, それを初期化 (a=0, b=0.0) し, その場所のアドレスを含む型 *S の値を復帰する.

スライス・マップ・チャンネルの生成

ビルトイン関数 make は スライス型,マップ型,またはチャンネル型 T を受け取り, オプションで,式の型固有のリストが続く. (型 *T ではなく) 型 T の値を復帰する. メモリは, 初期値節で説明するように初期化される.

呼び出し         型 T         復帰値

make(T, n)       スライス     型 T, 長さ n, 容量 n のスライス
make(T, n, m)    スライス     型 T, 長さ n, 容量 m のスライス

make(T)          マップ       型 T のマップ
make(T, n)       マップ       型 T,約 n 要素の初期容量をもつマップ

make(T)          チャンネル   型 T のバッファなしチャンネル
make(T, n)       チャンネル   型 T, バッファサイズ n のバッファ付きチャンネル

サイズ引数 nm は整数型か,型なし定数でなければならない. 定数のサイズ引数は,非負であり, 型 int の値で表現可能でなければならない. それが型なし定数であると,それは型 int が与えられる. nm の両方共与えられ,定数である場合, nm よりも大きくてはならない. 実行時に n が負か m よりも大きい場合, ランタイムパニックが発生する.

s := make([]int, 10, 100)       // スライス len(s) == 10, cap(s) == 100
s := make([]int, 1e3)           // スライス len(s) == cap(s) == 1000
s := make([]int, 1<<63)         // 不当: len(s) が型 int で表現不可能
s := make([]int, 10, 0)         // 不当: len(s) > cap(s)
c := make(chan int, 10)         // バッファサイズ 10 のチャンネル
m := make(map[string]int, 100)  // 約 100 要素の初期スペースをもつマップ

マップ型でサイズヒント n を引数とする make の呼び出しは, n マップ要素を保持する初期スペースをもつマップを生成する. 詳細な挙動は実装依存である.

スライスへの追加とコピー

ビルトイン関数 appendcopy は,一般的なスライス演算を支援する. どちらの関数でも,復帰値は引数に参照されるメモリが重複しているかどうかに依存しない.

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

append(s S, x ...T) S  // T は S の要素型

s の容量が 追加する値に対して十分大きくない場合, append は新しく, 既存のスライスと追加の値を保持するのに 十分大きな基底配列を割り当てる. そうでなければ,append は基底配列を再利用する.

s0 := []int{0, 0}
s1 := append(s0, 2)                // 一つの要素を追加            s1 == []int{0, 0, 2}
s2 := append(s1, 3, 5, 7)          // 複数の要素を追加            s2 == []int{0, 0, 2, 3, 5, 7}
s3 := append(s2, s0...)            // スライスを追加              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
s4 := append(s3[3:6], s3[2:]...)   // 重複したスライスを追加      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"...)            // 文字列を追加                b == []byte{'b', 'a', 'r' }

関数 copy は, コピー元 (source) src から, コピー先 (destination) dst へ スライスの要素をコピーし, コピーされた要素の数を復帰する. どちらの引数も, 同一の要素型 T を持たねばならず, 型 []T のスライスへ代入可能でなければならない. コピーされた要素の数は,len(src)len(dst) の最小値である. 特別な場合として, copy は, 文字列型のコピー元引数(訳注:src)を []byte 型のコピー先引数(訳注: dst)への代入を受け入れる. この形式では,文字列から,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)  // マップ m から 要素 m[k] の削除

マップ mnil であるか要素 m[k] が存在しない場合, delete はなにもしない.

複素数の取扱

3 つの関数が,複素数を組み立て (assemble),分解する (disassemble). ビルトイン関数 complex は, 浮動小数点値の 実部 (real part) と虚部 (imaginary part) から 複素数値を構築する. realimag は,複素数値の 実部と虚部を抽出する.

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

引数の型と復帰値の型は対応する. complex では, 2 つの引数は同じ浮動小数点型でなければならず, 復帰型は,対応する浮動小数点から成る複素数型である: 引数 float32 に対して, complex64, 引数 float64 に対して, complex128 となる. 引数の一方が型なし定数に評価された場合, それは最初に暗黙的に他方の引数の型に変換される. どちらの引数も型なし定数に評価された場合, それらは, 複素数でないか,虚部が 0 でなければならず, 関数の復帰値は,型なし複素数定数である.

realimag では, 引数は,複素数型でなければならず, 復帰型は対応する複素数点型である. 引数 complex64 に対しては float32, 引数 complex128 に対しては float64 となる. 引数が型なし定数に評価された場合, それは,数でなければならず, 関数の復帰値は,型なし浮動小数点定数である.

realimag 関数の 2 つで, complexの逆関数を形成するため, 複素数型 Z の値 z の値に対して, z == Z(complex(real(z), imag(z))) が成り立つ.

これらの関数のオペランドがすべて定数である場合, 復帰値は定数である.

var a = complex(2, -2)             // complex128
const b = complex(1.0, -1.4)       // 型なし複素数定数 1 - 1.4i
x := float32(math.Cos(math.Pi/2))  // float32
var c64 = complex(5, -x)           // complex64
var s int = complex(1, 0)          // 型なし複素数定数 1 + 0i は int に変換できる
_ = complex(1, 2<<s)               // 不当: 2 は浮動小数点型となり,シフトできない
var rl = real(c64)                 // float32
var im = imag(a)                   // float64
const c = imag(b)                  // 型なし定数 -1.4
_ = imag(3 << s)                   // 不当: 3 は複素数型となり,シフトできない

パニックの対処

2 つのビルトイン関数 panicrecoverランタイムパニックと プログラムで定義されたエラー条件の レポートと処理を支援する.

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

関数 F の実行中に, 明示的な panic の呼び出しか, ランタイムパニックは, F の実行を停止する. F によって遅延された任意の関数は,通常通り実行される. 次に,F の呼び出し元によって遅延された関数が実行され, 実行中のゴルーチンのトップレベル関数によって遅延された関数が続く. その時点で, プログラムは終了し, panic の引数の値を含む エラー条件を報告する. この停止列 (termination sequence) は,パニック (panicking) と呼ばれる.

panic(42)
panic("到達しない unreachable")
panic(Error("解析できない cannot parse"))

recover 関数は,プログラムがパニックしたゴルーチンの動作を管理することを可能にする. 関数 Grecover を呼び出す関数 D を遅延し, パニックが G を実行中に同じゴルーチン上の関数で発生すると仮定する. 遅延関数の実行中に D に到達すると, recover を呼び出す D の復帰値は, panic の呼び出しに渡された値である. D が新しい panic を開始することなしに,通常通り復帰する場合, パニック列は停止する. その場合, Gpanic の呼び出しの間に呼び出される関数の状態が破棄され, 通常の実行が再開される. D の前に G によって遅延された 任意の関数が実行され, G の実行がその実行元に戻ることによって終了する.

以下の条件のいずれかを満たすとき, recover の復帰値は nil である.

以下の例の protect 関数は, 関数の引数 g を呼び出し, g によって発生したランタイムパニックから 呼び出し元を保護する (protect).

func protect(g func()) {
	defer func() {
		log.Println("done")  // パニックがあったとしても Println は実行される
		if x := recover(); x != nil {
			log.Printf("run time panic: %v", x)
		}
	}()
	log.Println("start")
	g()
}

ブートストラップ

現在の実装では, ブートラップ (bootstrap) 中に役立ついくつかのビルトイン関数が提供される. これらの関数は,完全に文書化されているが, 言語が動作を保証するものではない. これらの関数は復帰値を持たない.

関数       動作

print      すべての引数を出力する; 引数のフォーマットは実装依存である
println    print ににているが,引数の間にスペースと,最後に改行を出力する

実装上の制限: printprintln は 任意の引数の型を受け取れる必要はないが, ブール,数値型,文字列型の出力はサポートしなければならない.

パッケージ

Go プログラムは,パッケージ (package) をリンクすることによって構築される. パッケージは, パッケージに属する定数,型,変数,関数を宣言し, 同じパッケージのすべてのファイルからアクセス可能な 1 つ以上のソースファイルから構築される. これらの要素は, エクスポートされ, 他のパッケージで使用される.

ソースファイルの編成

各ソースファイル (source file, SourceFile) は, それが属するパッケージを定義するパッケージ句 (package clause; PackageClause) から成り, それが使用するパッケージを宣言する import 宣言 ImportDecl の(空でも良い)集合が続き, 関数,型,変数,定数の宣言 TopLevelDecl の(空でも良い)集合が続く.

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

パッケージ句

パッケージ句 (package clause) は各ソースファイルを開始し, そのファイルが属するパッケージを定義する.

PackageClause  = "package" PackageName .
PackageName    = identifier .

PackageNameブランク識別子にはできない.

package math

同じ PackageName を共有するファイルの集合は, パッケージの実装を形成する. 実装は,パッケージに属する すべてのソースファイルが 同じディレクトリに存在することを要求する場合がある.

インポート宣言

インポート宣言 (import declaration; ImportDecl) は, その宣言を含むソースファイルがインポート (import) するパッケージの機能 (プログラムの初期化と実行節) に依存することを示し, そのパッケージのエクスポートされた識別子にアクセスが可能となる. インポートは, アクセスのために使用される 識別子 (PackageName) を名付け, ImportPath は インポートされるパッケージを指定する.

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

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

ImportPath の解釈は,実装依存であるが, 通常は, コンパイルされたパッケージのフルファイル名の部分文字列であり, インストールされたパッケージのリポジトリに関連している場合がある.

実装上の制限: コンパイラは, Unicode の L, M, N, P, S general categories に属する文字 (スペースを除く Graphic 文字) のみを使用した 空でない文字列に ImportPaths を制限する場合があるし, 文字 !"#$%&'()*,:;<=>?[\]^{|} と Unicode 置換文字 U+FFFD` を除外する場合もある.

関数 Sin をエクスポートする package math をパッケージ句に含むパッケージをコンパイルし, "lib/math" で特定されるファイルにコンパイルされたパッケージはインストールした と仮定する. 以下の表は, インポート宣言のさまざまな形式のあと, そのパッケージをインポートするファイルで どのように Sin がファイル内でアクセスされるかを示す.

インポート宣言              Sin のローカル名

import   "lib/math"         math.Sin
import m "lib/math"         m.Sin
import . "lib/math"         Sin

インポート宣言は, インポートしたパッケージとインポートされたパッケージの間の依存関係を宣言する. 直接的でも,間接的でも, パッケージが自分自身をインポートすることは不当であり, パッケージがエクスポートした識別子を参照しないのに, 直接的にそのパッケージをインポートするのは不当である. 副作用 (初期化) のみを目的としてパッケージをインポートする場合は, 暗黙的なパッケージ名としてブランク識別子を使用する.

import _ "lib/math"

パッケージの例

並行エラトステネスの篩 (prime sieve) を実装する 完全な Go パッケージである.

package main

import "fmt"

// チャンネル 'ch' に列 2, 3, 4, … を送信
func generate(ch chan<- int) {
	for i := 2; ; i++ {
		ch <- i  // Send 'i' to channel 'ch'.
	}
}

// 'prime' で割り切れる数を削除しながら,
// チャンネル 'src' からチャンネル 'dst' へ値をコピーする
func filter(src <-chan int, dst chan<- int, prime int) {
	for i := range src {  // 'src' から受け取った値を繰り返す
		if i%prime != 0 {
			dst <- i  // 'i' をチャンネル 'dst' へ送信
		}
	}
}

// エラトステネスの篩: デイジーチェインフィルターも一緒に処理する
func sieve() {
	ch := make(chan int)  // 新しいチャンネルの生成
	go generate(ch)       // サブプロセスとして generate() を開始
	for {
		prime := <-ch
		fmt.Print(prime, "\n")
		ch1 := make(chan int)
		go filter(ch, ch1, prime)
		ch = ch1
	}
}

func main() {
	sieve()
}

プログラムの初期化と実行

ゼロ値

宣言または, new の呼び出しによって 格納域が変数として割り当てられるとき,または, 複合リテラルか make の呼び出しによって 新しい変数が生成され,かつ, 明示的な初期化が提供されなかったとき, 変数や値はデフォルト値が与えられる. そのような変数や値の要素には, その型に対するゼロ値 (zero value) が設定される. ゼロ値は, ブールには 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

パッケージの初期化

パッケージ内では, パッケージレベルの変数の初期化が段階的に行われる. 初期化されていない変数に依存していない変数で, 各段階では, 宣言した順序 (declaration order) がはやい変数から選択される.

より正確には, パッケージレベルの変数は, それが,初期化されておらず,かつ, 初期化式を持たないか, その初期化式が未初期化の変数に依存 (dependency) していない場合, 初期化する準備ができた (ready for initialization) とよぶ. 初期化は, 次のパッケージレベルの変数を 宣言された順序で最もはやいもので,かつ,初期化される準備ができた変数 から 初期化する準備ができた変数がなくなるまで, 繰り返し初期化する.

すべての変数が未初期化のままである場合, この処理は終了する. これらの変数は,1 つ以上の初期化サイクルの一部であり, プログラムは有効でない.

右辺が 単一で多値の式によって初期化される変数宣言の 左辺の複数の変数は,同時に初期化される: 左辺の変数の一部が初期化されていたら, 他の変数たちも同時に初期化される.

var x = a
var a, b = f() // a と b は x の初期化前に,同時に初期化される

パッケージの初期化を目的として, ブランク変数が, 宣言における他の変数のように扱われる.

複数の変数で宣言された 変数の宣言順序は, コンパイラーに提示されたファイルの順で決定する. 最初のファイルで宣言された変数は, 2 番目のファイルで宣言される変数よりも前に宣言される,など.

依存関係分析 (dependency analysis) は, 変数の実際の値には依存せず, 推移的に分析される ソースコード内のそれらの字句的な参照 (reference) にのみ依存する. 例えば,変数 x の初期化式が, 変数 y を本体で参照する関数を参照している場合, xy に依存する. 具体的には:

例えば,以下の宣言が与えられたとき,

var (
	a = c + b  // == 9
	b = f()    // == 4
	c = f()    // == 5
	d = 3      // == 5 (初期化が完了したあと)
)

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

初期化順序は d, b, c, a である. 初期化式における部分式の順序は無関係である. この例において, a = c + ba = b + c は, 同じ初期化順序になる.

依存関係分析は, パッケージ毎に行われる. 現在のパッケージ内で宣言される 変数,関数,(非インターフェース)メソッドへの参照のみ,考慮される. 他の隠れたデータ依存関係が変数間に存在する場合, これらの変数の初期化順序は指定されない.

例えば,以下の宣言が与えられたとき,

var x = I(T{}).ab()   // x は検出されない,隠れた依存関係を a と b にもつ
var _ = sideEffect()  // x, a, 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() が呼び出されるタイミング (moment) も指定されていない.

変数は, パッケージブロックで宣言される 関数名 init を使って初期化される場合がある. ここで,init は引数と復帰値をもたない.

func init() { … }

単一のファイル内であっても複数のそのような関数がパッケージごとに定義できる. パッケージブロックでは, init 識別子は,init 関数の宣言にのみ使用され, 識別子自身は,宣言されない. したがって,init 関数はプログラムのどこからも参照されない.

インポートがないパッケージは, すべてのパッケージレベルの変数に初期値を代入し, すべての init 関数をソースコード内で現れる順(複数ファイルの場合,コンパイラーに提示される順)に呼び出されることで, 初期化される. あるパッケージがインポートをもつ場合, インポートされるパッケージは,インポートするパッケージよりも前に初期化される. あるパッケージを 複数のパッケージがインポートする場合, インポートされるパッケージは,一度だけ初期化される. パッケージのインポートにより,構造上,初期化の依存関係に循環がないことを保証できる.

パッケージの初期化 (変数初期化と init 関数の呼び出し) 一度にひとつのパッケージを 順に単一のゴルーチンで実行する. init 関数は, 初期化コードと同時に実行でき, 他のゴルーチンを起動することがある. しかし, 初期化はいつも init 関数を順に処理する. つまり, 前の init 関数が復帰するまで 次の init 関数は呼び出されることはない.

初期化動作の再現性を保証するために, ビルドシステム (build system) は, 同一パッケージ内に属する複数のファイルを 字句ファイル名順にコンパイラに提示することを推奨する.

プログラムの実行

完全なプログラムは, メインパッケージ (main package) と呼ばれる, 単一で,インポートされないパッケージを メインパッケージがインポートするパッケージを推移的に (transitively) リンクによって生成される. メインパッケージは,パッケージ名 main を持ち, 引数を取らず,復帰値のない main 関数を宣言しなければならない.

func main() {  }

プログラムの実行 (program execution) は,man パッケージの初期化から開始し, 関数 main を呼び出す. その関数呼び出しが復帰すると,関数は終了する (exist). それは,他の (非 main) ゴルーチンの完了を待たない.

エラー

事前宣言された型 error は以下で定義される.

type error interface {
	Error() string
}

これは,エラー条件を表すために便利なインターフェースである. nil 値はエラーがないことを表す. 例えば,ファイルのデータを読み込む関数は以下のように定義される場合がある.

func Read(f *File, b []byte) (n int, err error)

ランタイムパニック

配列の範囲外のインデックスの指定のような 実行時エラーはランタイムパニック (run-time panic) を引き起こす. これは, 実装で定義されたインターフェース型 runtime.Error の値で, ビルトイン関数 panic の呼び出しと等価である. その型は,事前宣言されたインターフェース型 error を満足する. 個別の実行時エラー条件を表すエラーの正確な値は指定されていない.

package runtime

type Error interface {
	error
	// それから,他のメソッド
}

システムの考慮事項

パッケージ unsafe

コンパイラが認識し, インポートパス unsafe を通してアクセス可能な ビルトイン関数 unsafe は, 型システムに違反する操作を含む低レベルプログラミング機能を提供する. unsafe を使用するパッケージは, 型の安全性のために,手動で入念に検査する必要があり, 移植できない場合もある. パッケージは以下のインターフェースを提供する.

package unsafe

type ArbitraryType int  // 任意の Go 型の省略形; 本当の型ではない.
type Pointer *ArbitraryType

func Alignof(variable ArbitraryType) uintptr
func Offsetof(selector ArbitraryType) uintptr
func Sizeof(variable ArbitraryType) uintptr

Pointer は,ポインター型であるが, Pointer 値は,逆参照できない. 任意の基底型 uintptr のポインターまたは値は, 基底型 Pointer の型へ変換でき,その逆も可能である. Pointuintptr 間の変換の影響は実装定義である.

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.fs または *s によって表記される構造体のフィールド f を表す. 関数 Offsetof は構造体のアドレスを基準とした相対バイトで,フィールドオフセットを復帰する. 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

Alignof, Offsetof, Sizeof の呼び出しは, 型 uintptr のコンパイル時定数式である.

サイズと配置の保証

数値型に対して,以下のサイズ (size) が保証される.

                                    バイト単位のサイズ

byte, uint8, int8                     1
uint16, int16                         2
uint32, int32, float32                4
uint64, int64, float64, complex64     8
complex128                           16

以下の最小限の配置 (alignment) 性質が保証される:

  1. 任意の型の変数 x: unsafe.Alignof(x) は少なくとも 1 である.
  2. 構造体型の変数 x: unsafe.Alignof(x)x の各フィールド f に対する unsafe.Alignof(x.f) の最大値であり,少なくとも 1 である.
  3. 配列型の変数 x: unsafe.Alignof(x) は配列の要素型の変数の配置と同じである.

サイズが 0 よりも大きなフィールドまたは要素を持たない 構造体型または配列型はサイズ 0 である. 2 つの異なる 0 サイズの経数は,メモリ上同じアドレスをもつ場合がある.