Go/文法の概要
文法の概要
[編集]Hello World
[編集]- コード例
package main import "fmt" func main() { fmt.Println("Hello, World") }
文法の概要
[編集]ソースファイルのトップレベルの構造
[編集]Goでは、ソースファイルの冒頭に package
文があります。これに続いて import
文があります。
package
文: ファイルの冒頭に記述します。import
文:package
文の直後に配置します。複数のimport
文がある場合は、括弧()
を使用してまとめることができます。- その他の実装:
import
文の後に、関数やその他のコードが続きます。
- 例
package main import ( "fmt" "os" ) func main() { fmt.Println("Hello, Go!") os.Exit(0) }
エントリーポイント
[編集]プログラムの開始点は「エントリーポイント」と呼ばれます。Goでは、エントリーポイントは「main
パッケージの main
関数」と決まっています。
関数
[編集]関数は、プログラム内で再利用可能なコードのブロックを表します。
関数の宣言は func
キーワードを使用します。
- 関数の例
package main import "fmt" func main() { fmt.Println(subr(3, 2)) } func subr(x, y int) (int, int) { return x + y, x - y }
- 実行結果
5 1
- 解説
func subr(x, y int) (int , int) {
- x と y が(int型の)仮パラメーターで、戻値をそれぞれintで返します。
- subrの呼び出しは前方参照となっていますが、Go ではパッケージ内の識別子の参照とその依存関係は宣言などのプログラミング上の負荷なく解決されます。もし循環参照があればコンパイル時に診断されます。
変数
[編集]Goは静的型付けのプログラミング言語であり、変数を使用する前に必ず宣言する必要があります。Goの変数には、以下のような特徴があります。
- 変数の宣言方法は、
var
を使った方法と、短縮形の:=
を使った方法があります。 - 変数の型は、明示的に指定することも、型推論によって自動的に決定されることもあります。
- 宣言した変数は、初期値を指定しない場合はゼロ値が自動的に代入されます。数値型のゼロ値は0、文字列型のゼロ値は空文字列、ブーリアン型のゼロ値はfalseです。
- 宣言した変数は、宣言したスコープ内でのみ有効です。関数の外で宣言された変数は、パッケージレベルの変数として扱われます。
- 変数名は、アルファベット、数字、アンダースコアの組み合わせで構成されます。ただし、先頭の文字はアルファベットまたはアンダースコアである必要があります。
- 変数に対して、算術演算や比較演算、論理演算などを行うことができます。
- 例
package main import "fmt" var i int var j int = 42 var k = 69 func main() { a := 2.0 fmt.Println(i, j, k, a) }
- 実行結果
0 42 69 2
- 変数宣言
var i int
- のように var キーワードを使い、C言語系とは語順が違います(Pascalに近い語順)。
- 初期化を伴った変数宣言
var j int = 42
- 変数は、宣言と同時に初期化できます(初期化しない変数の値はゼロ値になります)。
- 型推論
var k = 69
- 宣言と同時に初期化した場合、型名を省略できます。その場合の変数の型は初期化した値から型推論[1]されます。
- 短い変数宣言
a := 2.0
- 短い変数宣言は関数の中でだけ許されます、この場合の i の型は初期値 123 から int と型推論されます。
:=
はPascalの代入を彷彿とさせますが、Goでは関数スコープあるいは制御構文スコープの変数宣言です。- C++では
auto i = 123;
- のようにキーワード auto を型名の位置に使い型推論を表現しますが、キーワードを増やさないことが特徴の Go では、単に型名を省略したり専用の初期化付宣言構文で表現します。
- また auto がないので戻り値を型推論することはできません。
定数
[編集]Goにおける定数は、実行時に変更できない値のことを指します。変数と異なり、定数は宣言時に初期化する必要があります。
定数の宣言には const
キーワードを使用します。定数の命名規則は変数と同様で、アルファベットまたはアンダースコアで始まり、その後に数字や文字列を含むことができます。
- 例
package main import "fmt" // const i int ← 定数は初期化が必須なのでこれはエラー(ゼロ値とはならない) const j int = 42 const k = 69 const ( zero = iota one two three _ five ) func main() { // const a := 2.0 短い変数宣言で定数は宣言できない fmt.Println(j, k) fmt.Println(zero, one, two, three, five) }
- 実行結果
42 69 0 1 2 3 5
- 解説
const j int = 42
: 定数j
を宣言し、初期値を42
に設定しています。const k = 69
: 定数k
を宣言し、初期値を69
に設定しています。型が指定されていないため、自動的に型が推定されます。const (zero = iota one two three _ five)
:iota
を使用して、0から始まる連続した値を定義しています。_
はブランク識別子で、使用しない定数を無視するために使用されます。fmt.Println(j, k)
: 定数j
とk
を出力しています。fmt.Println(zero, one, two, three, five)
: 定数zero
、one
、two
、three
、およびfive
の値を出力しています。iota
により、zero
は0、one
は1、two
は2、three
は3、_
に対応する値は無視され、five
は5となります。
データ型
[編集]Goでは、変数や関数の戻り値、関数のパラメータなどに対して型を指定する必要があります。
以下に、Goで利用できる主要なデータ型を紹介します。
// 基本データ型: // // 整数型 (int): 符号付き整数。例: int, int8, int16, int32, int64. var age int age = 25 // 符号なし整数型 (uint): 符号なし整数。例: uint, uint8, uint16, uint32, uint64. var count uint count = 10 // 浮動小数点型 (float): 浮動小数点数。例: float32, float64. var price float64 price = 3.14 // 論理型 (bool): 真偽値。true または false のいずれか。 var isOpen bool isOpen = true // 文字列型 (string): 文字列。 var message string message = "Hello, Go!" // 複合データ型: // // 配列 (Array): 固定長の同じ型の要素を保持するデータ構造。 var numbers [3]int numbers = [3]int{1, 2, 3} // スライス (Slice): 動的なサイズの配列。配列よりも柔軟。 var fruits []string fruits = []string{"apple", "banana", "orange"} // マップ (Map): キーと値のペアを保持するデータ構造。 var ages map[string]int ages = map[string]int{"Alice": 25, "Bob": 30} // 構造体 (Struct): 異なる型のフィールドを組み合わせて定義されたデータ構造。 type Person struct { Name string Age int } var p Person p.Name = "Alice" p.Age = 25 // その他: // // ポインタ (Pointer): メモリ上のアドレスを保持する変数。 var x int var ptr *int ptr = &x // 関数型 (Function): 関数を変数に代入したり、関数を返すことができる。 var add func(int, int) int add = func(a, b int) int { return a + b }
型推論
[編集]Goでは、型推論がサポートされており、変数の型をコンパイラが自動的に推測することができます。型推論を使用すると、冗長な型宣言を省略し、コードを簡潔にすることができます。 ただし、パッケージのトップレベルの変数では型推論出来ません。
以下は型推論の例です:
// 基本データ型: // // 整数型 (int): 符号付き整数。例: int, int8, int16, int32, int64. age := 25 // 符号なし整数型 (uint): 符号なし整数。例: uint, uint8, uint16, uint32, uint64. count := uint(10) // 浮動小数点型 (float): 浮動小数点数。例: float32, float64. price := 3.14 // 論理型 (bool): 真偽値。true または false のいずれか。 isOpen := true // 文字列型 (string): 文字列。 message := "Hello, Go!" // 複合データ型: // // 配列 (Array): 固定長の同じ型の要素を保持するデータ構造。 numbers := [3]int{1, 2, 3} // スライス (Slice): 動的なサイズの配列。配列よりも柔軟。 fruits := []string{"apple", "banana", "orange"} // マップ (Map): キーと値のペアを保持するデータ構造。 ages := map[string]int{"Alice": 25, "Bob": 30} // 構造体 (Struct): 異なる型のフィールドを組み合わせて定義されたデータ構造。 type Person struct { Name string Age int } p := Person{Name: "Alice", Age: 25} // その他: // // ポインタ (Pointer): メモリ上のアドレスを保持する変数。 x := 0 ptr := &x // 関数型 (Function): 関数を変数に代入したり、関数を返すことができる。 add := func(a, b int) int { return a + b }
上記のコードでは、変数の型を明示的に宣言せずに、初期値から型が推論されています。型推論を利用することで、冗長な型宣言を省略し、コードの記述量を減らすことができます。
グループ化
[編集]import
, var
, const
の宣言は (
)
でグループ化できます。
- 例
package main import ( "fmt" "math" ) var ( f float64 i int ) const ( PI_2 = math.Pi / 2 PI_4 = math.Pi / 4 ) func main() { fmt.Println(f, i, PI_2, PI_4) }
- 実行結果
0 0 1.5707963267948966 0.7853981633974483
演算子
[編集]Go言語には、以下のような演算子があります。
- 算術演算子:
+
,-
,*
,/
,%
- 比較演算子:
==
,!=
,<
,<=
,>
,>=
- 論理演算子:
&&
,||
,!
- ビット演算子:
&
,|
,^
,<<
,>>
,&^
- 代入演算子:
=
,+=
,-=
,*=
,/=
,%=
,<<=
,>>=
,&=
,|=
,^=
,&^=
算術演算子は、数値型の値の加算、減算、乗算、除算、剰余を行います。 比較演算子は、二つの値の比較を行い、真偽値を返します。 論理演算子は、論理値のAND、OR、NOT演算を行います。 ビット演算子は、整数型の値のビット毎のAND、OR、XOR、左シフト、右シフト、ビットクリア演算を行います。 代入演算子は、左辺の変数に右辺の値を代入し、その後演算を行います。
また、Goには以下のような演算子もあります。
- アドレス演算子:
&
- ポインタ演算子:
*
- 参照演算子:
.
アドレス演算子は、変数のアドレスを取得します。 ポインタ演算子は、ポインタの指す先の値を参照します。 参照演算子は、構造体やインターフェイスのメンバーにアクセスするために使用します。
これらの演算子を組み合わせることで、複雑な演算が可能になります。
- 演算子の例
package main import "fmt" func main() { a, b, c := 42, 12, 3 t, f := true, false /* 単項演算子 */ fmt.Println(+c) // 単項プラス fmt.Println(-c) // 単項マイナス fmt.Println(^c) // ビット反転(C言語系の ~ ではなく ^) fmt.Println(!t) // 論理否定 /* 二項演算子 */ fmt.Println(a * b) // 乗算 fmt.Println(a / b) // 除算 fmt.Println(a % b) // 剰余 fmt.Println(a << c) // 左シフト fmt.Println(a >> c) // 右シフト fmt.Println(a & c) // ビットごとの論理積 fmt.Println(a &^ c) // ビットクリア( &^ でトークン) fmt.Println(a & ^c) // ビットクリア(これとおなじ) fmt.Println(a + c) // 加算 fmt.Println(a - c) // 減算 fmt.Println(a | c) // ビットごとの論理和 fmt.Println(a ^ c) // ビットごとの排他的論理和 fmt.Println(a == b) // 一致 fmt.Println(a != b) // 不一致 fmt.Println(a < b) // より小 fmt.Println(a <= b) // より小または一致 fmt.Println(a > b) // より大 fmt.Println(a >= b) // より大または一致 fmt.Println(t && f) // 論理積(短絡評価あり) fmt.Println(t || f) // 論理和(短絡評価あり) }
- 実行結果
3 -3 -4 false 504 3 6 336 5 2 40 40 45 39 43 41 false true false false true true false true
- 代入は、演算子ではなく文です。
- インクリメントおよびデクリメントは、演算子ではなく文です。
- Goには三項演算子(条件演算子; 式 ? 値1 : 値2 )はありません。
- 冪乗演算子もないので、Goでは結合方向(同じ優先度の二項演算子が続いた場合の評価順序)は左からです。
代入
[編集]Goの構文要素には文・式・演算子があり、代入は文に分類されます。C言語系の言語では代入は式に分類されますが、Goでは異なります。
代入が文であることにより、a = b = 42;
の様な代入はできず、if文などの構造構文の条件式で代入はできません。
このことで、右結合であるか左結合であるかへの配慮を必要とする状況を劇的に少なくなりました。
- 代入の例
package main import "fmt" func main() { x, y := 42, 123 // 2つの変数を宣言し型なしの定数で初期化 fmt.Println("x =", x) fmt.Println("y =", y) // x = y = 10 ・・・ Go では(代入は文なので)は構文エラー x, y = y, x // Go では多重代入が可能 fmt.Println("x =", x) fmt.Println("y =", y) }
- 実行結果
x = 42 y = 123 x = 123 y = 42
- 解説
- このコードでは、2つの変数
x
とy
を宣言して、それぞれを42
と123
で初期化します。:=
演算子を使用して宣言された変数は型が自動的に決定され、Goの仕様に基づいて、初期値から型が推論されます。fmt.Println
関数を使用して、x
とy
の値を出力します。 - 次に、変数
x
とy
の値を交換するために、x, y = y, x
を実行します。この多重代入文では、右側の値の評価が左側の変数に対して代入されます。つまり、y
の値がx
に代入され、x
の値がy
に代入されます。このような多重代入は、一時変数を使用せずに値を交換するために便利です。 - 最後に、交換後の
x
とy
の値を再度出力します。
インクリメント・デクリメント
[編集]C言語系のプログラムには、n++ という構文があります。これは、変数nに1を足すことを表します。C言語系の言語では、この構文は式として扱われますが、Go言語では文として扱われます。 Go言語のインクリメント文は、後置インクリメントのみが存在します。これは、変数に1を足すことを意味します。式ではないため、インクリメントと値の参照の順序について心配する必要はありません。 Go言語でインクリメントを行う方法は、C言語系のプログラムと似ていますが、細かい点では異なる点があります。これらの違いを理解して、Go言語を使用する際には注意してコードを書く必要があります。
- インクリメント・デクリメントの例
package main import "fmt" func main() { x, y := 42, 123 // 2つの変数を宣言し型なしの定数で初期化 fmt.Println("x =", x) fmt.Println("y =", y) // x = y++ ・・・ Go ではインクリメントは文なので構文エラー x++ // ++y インクリメントは後置のみ y-- fmt.Println("x =", x) fmt.Println("y =", y) }
- 実行結果
x = 42 y = 123 x = 43 y = 122
構造構文
[編集]選択文
[編集]選択文には、if文とswitch文とselect文があります。
if文
[編集]これだけだと「C言語と同じアレか」と思われるでしょうが、Goでは、
- if文
if x > max { max = x }
のように条件式を囲むカッコが要らず { } が必須です(擬似コードではなく、動くプログラムの一部です)。また、
- if文スコープの変数
if x := f(); x < y { return -1 } else if x > y { return +1 } else { return 0 }
のように、条件式の前に「単純な文」を置くことができ、とりわけ上の例のように「短い変数宣言」で宣言された変数はif文スコープになります。
if (a) if (b) x(); else // ← 懸垂else y();
- は、実際には
if (a) { if (b) { x(); } else { y(); } }
とelseは最寄りのifと結合します。
Goでは、{ … } を必須とし懸垂else問題を回避し、if文スコープの変数と単文の組合わせの座りの悪さ[2]を回避するとともに、"if" と "{" に条件式(とオプショナルな単純な文)があると決め打ちできるので構文解析の簡素化に役立っています。switch文
[編集]- switch文
switch oct { default: error() case 0, 2, 4, 6: even() case 1, 3, 5, 7: odd() } switch x := f(); { // 条件式は省略されると true とみなす。この場合 ; は必須。 case x < 0: return -x default: return x } switch { case x < y: lt() case x > y: gt() case x == y: eq() }
- C言語と異なり、case節の式は定数式でなくても構いません。
- if文と同じ様に条件式のカッコは不要で、条件式の前に「単純な文」を書けます(必須ではありません)。
- 条件式は省略可能で、省略すると true が仮定されます。
- また break するのが標準動作で、次のcase節に対応する文に処理を継続する場合は、fallthrough文 を使います。
反復文
[編集]Goの反復文はfor文だけです。これもC言語とは異なる文法で
- for文
for a < b { // C言語の while文 に相当しますが、やはり条件式にカッコは不要です a *= 2 } for i := 0; i < 10; i++ { // ここでも :=を使った短い変数宣言 f(i) } for { // C言語の for (;;) あるいは while(1) ⇒ 無限ループ f2(i) } var a [10]string for i, s := range a { // range句は Go独特 // i の型は int // s の型は string // s == a[i] g(i, s) } for _, s := range a { // range句は Go独特 // インデックスが不要なら、 _ に置きかえる // s の型は string // s == a[i] h(s) }
- rangeは、stringの他、配列・スライス・マップ・チャンネルとも組合わせることができます。
小まとめ
[編集]このように、Goの構文や意味論はC言語やC++、あるいはJavaとは大きく異なるため、ユーザーには事前にC言語などの知識が必要ありません。逆に、C言語ファミリーのプログラマーは、同じキーワードが別の意味を持つことが多く、常にその違いを意識する必要があるため、転換教育には頭の切り替えが必要です。
一方、JavaScriptなどのスクリプト言語の経験者は、自動的にセミコロンが挿入されるなど、馴染みの深い文法機能に親近感を持つかもしれません(JSからC/C++への転換教育では、このような機能が1つの大きなハードルになることがあります)。
構文は異なるものの、制約のある文法という点では、PythonとGoは近いものがあります。
- else節を伴ったif文
if x < 0 { fmt.Println("マイナス") } else { fmt.Println("プラス") }
は
- elseの前では改行できない
if x < 0 { fmt.Println("マイナス") } else { fmt.Println("プラス") }
- とelseの前で改行すると
./prog.go:11:3: syntax error: unexpected else, expecting }
- の様に文法的に違法となります(改行すると、; が自動挿入されます)。
- また if の行末の { の前も改行不能です(改行すると、やはり ; が自動挿入されます)。
また、Goには三項演算子 a ? b : c
もありません。
このように、同じロジックを書くと大きな差異を生じないよう慎重に言語設計がなされています。
クラスはないがメソッドはある
[編集]Go言語には、オブジェクト指向言語におけるクラス概念がありませんが、型に対してメソッドを定義することができます。具体的には、構造体を定義してその構造体に関数を紐付けることで、メソッドを定義することができます。
つぎの例では、 Abs メソッドは cmplx という名前の Complex 型のレシーバを持つことを意味しています。
- メソッドの例
// main パッケージは Go メソッドをデモンストレーションするためのシンプルな例を提供します。 package main import ( "fmt" "math" ) // Complex は実部と虚部を持つ複素数を表す構造体です。 type Complex struct { Real, Imag float64 } // Abs は複素数の絶対値(大きさ)を返します。 func (c Complex) Abs() float64 { return math.Hypot(c.Real, c.Imag) } func main() { // Complex 構造体を使った例 c := Complex{3, 4} fmt.Println(c.Abs()) // 絶対値を表示します。 }
また、Goはインターフェース型を持ちます。インターフェース型はインターフェース (interface) と呼ばれるメソッド集合を指定する機能で、クラス階層における継承の機能を受け持ちます(アプローチは全く異なります)。
また、入れ子の構造体の入れ子側の構造体(埋め込み構造体)のフィールドは、埋め込み親のフィールドの構文で参照できるので、継承的な使い勝手を提供します。
インターフェースの例として、以下のような Shape
インターフェースを定義し、Rectangle
構造体と Circle
構造体に Shape
インターフェースを実装する例を示します。
package main import ( "fmt" "math" ) // Shape インターフェースは、面積と周囲長を計算するメソッドを持つ図形を表します。 type Shape interface { Area() float64 // 面積を計算するメソッド Perimeter() float64 // 周囲長を計算するメソッド } // Rectangle 構造体は、幅と高さを持つ長方形を表します。 type Rectangle struct { Width, Height float64 // 幅と高さ } // Area メソッドは、長方形の面積を計算します。 func (r Rectangle) Area() float64 { return r.Width * r.Height } // Perimeter メソッドは、長方形の周囲長を計算します。 func (r Rectangle) Perimeter() float64 { return 2*r.Width + 2*r.Height } // Circle 構造体は、半径を持つ円を表します。 type Circle struct { Radius float64 // 半径 } // Area メソッドは、円の面積を計算します。 func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius } // Perimeter メソッドは、円の周囲長を計算します。 func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius } func main() { r := Rectangle{Width: 3, Height: 4} c := Circle{Radius: 5} shapes := []Shape{r, c} for _, shape := range shapes { fmt.Printf("Area: %f, Perimeter: %f\n", shape.Area(), shape.Perimeter()) } }
また、埋め込み構造体の例として、以下のような Person
構造体と Employee
構造体を定義し、Employee
構造体に Person
構造体を埋め込む例を示します。
package main import "fmt" // Person は人を表す構造体です。 type Person struct { Name string // 名前 Age int // 年齢 } // Introduce は自己紹介するメソッドです。 func (p Person) Introduce() { fmt.Printf("My name is %s, and I'm %d years old.\n", p.Name, p.Age) } // Employee は従業員を表す構造体です。 type Employee struct { Person // 埋め込みにより、Person型のフィールドが継承されます。 Department string // 部署 } func main() { // Employee型の変数を初期化します。 e := Employee{Person{Name: "Alice", Age: 25}, "Sales"} // 自己紹介をします。 e.Introduce() // 部署名を表示します。 fmt.Printf("I work in the %s department.\n", e.Department) }
Employee
構造体に Person
構造体を埋め込むことで、Employee
構造体は Person
構造体のフィールドにアクセスできるようになります。Introduce
メソッドは Person
構造体のメソッドであるため、Employee
構造体でも使用できます。
型パラメータ
[編集]型パラメータ(Type Parameter)は、プログラムで使われる型を抽象化し、柔軟性をもたせるための概念です。型パラメータを使用することで、特定の型に依存しない、汎用的なコードを記述することができます。これにより、同じロジックを異なる型に対して再利用できるようになります。
具体的なプログラミング言語やコンセプトによっては、ジェネリクス(Generics)や型引数(Type Arguments)とも呼ばれることがあります。Go言語では、ジェネリクスのサポートが追加され、その際に型パラメータの概念が導入されました。
型パラメータを使用して、任意の数型を複素数にできるように修正した例を以下に示します。
// main パッケージは Go メソッドをデモンストレーションするためのシンプルな例を提供します。 package main import ( "fmt" "math" ) // Complex は実部と虚部を持つ複素数を表す構造体です。 type Complex[T Number] struct { Real, Imag T } // Number は数値型のためのインターフェースです。 type Number interface { ~int | ~int32 | ~int64 | ~float32 | ~float64 } // Abs は複素数の絶対値(大きさ)を返します。 func (c Complex[T]) Abs() float64 { // float64 への型変換を行います。 return math.Hypot(float64(c.Real), float64(c.Imag)) } func main() { // Complex 構造体を使った例 c := Complex[int]{3, 4} fmt.Println(c.Abs()) // 絶対値を表示します。 // 別の数値型を使用した例 d := Complex[float64]{1.5, 2.5} fmt.Println(d.Abs()) // 絶対値を表示します。 }
型パラメータを使用して、Complex
構造体が任意の数値型を受け入れるようにしました。Number
インターフェースには int
および float
の具体的な型が指定されており、これにより特定の数値型に制約を与えています。Complex
構造体の型パラメータ T
は Number
インターフェースを満たす必要があり、この仕組みにより異なる数値型が Complex
構造体で利用できます。
コメント
[編集]Goでは、 //
から行末までがコメントになります。
また、/*
と*/
で複数行に渡るコメントを書くこともできます。
Go Doc コメント
[編集]Go Doc Comment は、パッケージ、変数、関数、メソッドなどの説明を記述するコメントです。これらのコメントは godoc
ツールによって抽出され、Goのドキュメントを生成するために使用されます。
Go Doc Comment は、//
または /* */
のいずれかで記述できます。//
を使用する場合は、コメントを上に書き、/* */
を使用する場合は、コメントを左側に書きます。
以下は、パッケージと関数の Go Doc Comment の例です。
// Package math は、基本的な数学関数を提供します。 package math // Add は、aとbを加算して結果を返します。 func Add(a, b int) int { return a + b }
Go Doc Comment には、以下のようなルールがあります。
- パッケージの Go Doc Comment は、
// Package
で始まります。 - 変数、定数、関数、メソッドの Go Doc Comment は、
//
または/* */
で始まります。 - 各行は、80文字以下になるようにします。
- コメントの最初の文は、短く、パッケージ、関数、またはメソッドの概要を説明します。
- 2番目の文以降は、詳細な説明、引数、戻り値、エラー、例などを提供します。
- コメント中の単語は、大文字で始め、句読点を含みません。
- コメント内の引用符は、"ダブルクォート" を使用します。
Go Doc Comment は、パッケージのドキュメントを生成するために非常に重要な役割を果たします。適切な Go Doc Comment を書くことで、他の開発者があなたのコードを理解しやすくなり、また、ドキュメントを参照することで、コードの使い方を学ぶことができます。
脚註
[編集]- ^ The Go Programming Language Specificationでは、型推論(type inference)という用語の使用は慎重に避けていて、型なし(untyped)という用語が型推論の文脈で多く使われ、例えば 123 のようなリテラルを型なし定数(untyped constant)と呼んでいます。
- ^ C++のAT&T2.0ではfor文で宣言された変数のスコープはfor文の外でしたがANSIC++ではfor文の中になりました。それはそれで問題ないのですが、for文の本体は複文だけでなく短文も許すので一見するとスコープがわかりにくいと不評です。for文で変数を宣言できる仕様はC言語にもそのままバックポートされたので、現在ではC言語のfor文もスコープ(とシャドーイング)に注意が必要です。Goのfor文はif文同様 { … } が必須なのでfor文×短文のややこしさはありません。