Go 入門
Table of Contents
1 公式チュートリアル
2 規格まとめ
2.1 特徴
- 文の区切りに
;
を使用しない - 型の宣言はシンボル名の後
- 多値返却
- 型推論に対応(ただし、専用の宣言方法が必要)
- 変数のデフォルトは mutable
- for 文などは、必ずブロックを持つ。
2.2 関数
func add(x int, y int) int { return x + y }
同じ型の引数が複数ある場合、最後以外の型宣言を省略できる。
func add(x, y int) int { return x + y }
多値返却をサポートする。
多値返却は ()
で括る。 これはタプルではない。
func swap(x, y string) (string, string) { return y, x }
戻り値を関数宣言時に指定できる。 次の場合、宣言時に x, y を戻り値に指定し、関数本体では return だけを書いている。
func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return }
2.3 変数
var で宣言する。 初期化していない場合の値は??? 型によって決っている?
var c, python, java bool func main() { var i int fmt.Println(i, c, python, java) }
初期化。
var i, j int = 1, 2 func main() { var c, python, java = true, false, "no!" fmt.Println(i, j, c, python, java) }
:=
を使って型推論。
ただし、これは関数内部でのみ有効。
func main() { var i, j int = 1, 2 k := 3 c, python, java := true, false, "no!" fmt.Println(i, j, k, c, python, java) }
2.4 型
bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr byte // uint8 の別名 rune // int32 の別名 // Unicode のコードポイントを表す float32 float64 complex64 complex128
int/uint のサイズは、処理系によって異なる。 サイズを限定する場合以外は int/uint の使用を推奨。
2.4.1 ゼロ値
初期値を与えない変数の初期値。
数値型(int,floatなど): 0 bool型: false string型: "" (空文字列( empty string ))
2.4.2 型変換
ある値 v を、型 T に変換する場合、 T(v) で変換する。
i := 42 f := float64(i) // <- 42 を float64 に変換 u := uint(f) // <- 42 を uint に変換
2.4.3 Constant
定数は Constant で変数を宣言する。 定数なので、当然初期値を設定する。 この初期値を使って型推論も行なうので、型宣言は不要。 なお、変数の型推論は関数内だけで有効だが、 Constant は関数外でも有効。
const Pi = 3.14 func main() { const World = "世界" fmt.Println("Hello", World) fmt.Println("Happy", Pi, "Day") const Truth = true fmt.Println("Go rules?", Truth) }
- 数値の Constant
数値型の範囲(64bit)では表現できない値も、 Constant であれば表現できる。
const ( // Create a huge number by shifting a 1 bit left 100 places. // In other words, the binary number that is 1 followed by 100 zeroes. Big = 1 << 100 // Shift it right again 99 places, so we end up with 1<<1, or 2. Small = Big >> 99 ) func needInt(x int) int { return x*10 + 1 } func needFloat(x float64) float64 { return x * 0.1 } func main() { fmt.Println(needInt(Small)) fmt.Println(needFloat(Small)) fmt.Println(needFloat(Big)) }
2.5 for
- ほぼ C と同じ。
- スコープは for ループで閉じる。
func main() { sum := 0 for i := 0; i < 10; i++ { sum += i } fmt.Println(sum) }
For の 3 つのループ制御ステートメントはそれぞれ省略可能。 これにより、 while/無限ループを表現する。 For で while と等価な表現ができるため、 go は while をサポートしない。
while と等価の for。
func main() { sum := 1 for sum < 1000 { sum += sum } fmt.Println(sum) }
無限ループの for。
func main() { for { } }
2.6 if
()
が無い- {} が必須
- 条件式の前に文を書ける。
- ここで宣言した変数は if と else のスコープ。
func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v } return lim }
2.7 switch
- switch は if/else のシンタックスシュガー。
- 条件文の前の文も書ける。
- シンタックスシュガーなので、 case の各式は上から順に評価される。
- C のような fall-through はない。
- break はなくても、一致した case/default を実行したら終わる。
func main() { fmt.Print("Go runs on ") switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X.") case "linux": fmt.Println("Linux.") default: // freebsd, openbsd, // plan9, windows... fmt.Printf("%s.", os) } }
2.7.1 switch の値を省略
switch の値を省略すると switch true と同義。
func main() { t := time.Now() switch { case t.Hour() < 12: fmt.Println("Good morning!") case t.Hour() < 17: fmt.Println("Good afternoon.") default: fmt.Println("Good evening.") } }
2.8 defer
- 関数コールを呼び出し元関数終了時に実行するように予約する。
- 関数コールの引数に与えている式は、 defer 評価時に実行される。
次は hello hoge ではなく、hello world が表示される。
func main() { txt := "world" defer fmt.Println( txt ) txt = "hoge" fmt.Println("hello") }
defer の予約は、スタックに Push される。
func main() { fmt.Println("counting") for i := 0; i < 10; i++ { defer fmt.Println(i) } fmt.Println("done") }
2.9 ポインタ
- 値を格納しているポインタを扱える。
- ただし、ポインタの演算はできない。
- C++ の参照と考えれば良い。
- ゼロ値は nil。
- 演算子は C と同じ。 &val でポインタ取得。 *val でポインタが格納する値を取得。
func main() { i, j := 42, 2701 p := &i // point to i fmt.Println(*p) // read i through the pointer -- 42 *p = 21 // set i through the pointer fmt.Println(i) // see the new value of i -- 21 p = &j // point to j *p = *p / 37 // divide j through the pointer fmt.Println(j) // see the new value of j -- 73 }
2.10 構造体
- メンバアクセスは C と同じで
.
を使用する。 - ただし、ポインタ経由のアクセス方法が異なる
- 時に
->
は使用せず、.
を使用する。 - (*p).val のようにも書けるが、 p.val と同義。
- 時に
- Println は、構造体のデータを出力可能
- 構造体のポインタを Println すると、 & を付加した
type Vertex struct { X int Y int } func main() { v := Vertex{1, 2} p := &v p.X = 1e9 fmt.Println(v) }
2.10.1 構造体リテラル
- 構造体の初期化データ。
- メンバの初期化は宣言順に処理される。
- 初期値を与えないメンバは、ゼロ値で初期化される。
- 構造体リテラルのポインタも取れる。
type Vertex struct { X, Y int } var ( v1 = Vertex{1, 2} // has type Vertex v2 = Vertex{X: 1} // Y:0 is implicit v3 = Vertex{} // X:0 and Y:0 p = &Vertex{1, 2} // has type *Vertex )
2.11 配列
- 要素数固定のシーケンス。
- 要素数は、宣言時に指定する。
- 配列は
[N]T
として宣言する。ここで N は要素数、T は型。
func main() { var a [2]string a[0] = "Hello" a[1] = "World" fmt.Println(a[0], a[1]) fmt.Println(a) primes := [6]int{2, 3, 5, 7, 11, 13} fmt.Println(primes) }
2.11.1 スライス
- スライスは、配列の一部を参照する。
- スライスの型は
[]T
として宣言する。要は配列の N がない形になる。
func main() { primes := [6]int{2, 3, 5, 7, 11, 13} var s []int = primes[1:4] fmt.Println(s) }
- 上記の primes[1:4] がスライス
- ここで primes[1:4] は、 {3,5,7} を示す。 つまり 1 から (4-1) 番目まで。
- スライスは参照なので、スライスの要素を変更すると、参照元の値も変更になる。
- 次の場合、スライス
s[1] = 0
しているが、これによって、 primes[ 2 ] が変わる。
func main() { primes := [6]int{2, 3, 5, 7, 11, 13} var s []int = primes[1:4] fmt.Println(s) s[1] = 0; fmt.Println( primes ) // [2 3 0 7 11 13] }
2.12 パッケージ
- 公開シンボルは大文字で始める。
2.13 import
パッケージをインポートする。
import ( "fmt" "math" ) import "fmt" import "math"