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"