Open16

A Tour of Go のまとめ - Basic編 -

chihiro0940chihiro0940

個人的に馴染みがないなと思ったところをまとめていく。

chihiro0940chihiro0940

Named return values

戻り値となる変数に名前を付けることができる。
戻り値の変数に名前を付けると、 return 式に何も書かずに戻すことができる(nakded return)。
読みやすさの観点から、短い関数でのみ利用すべき。

func split(sum int) (x, t int) {
    x = sum * 4 / 9
    y = sum - x
    return
}
chihiro0940chihiro0940

Basic types

Goの基本型

  • bool
  • string
  • int int8 int16 int32 int64
  • uint uint8 uint16 uint32 uint64 uintptr
  • byte (uint8の別名)
  • rune (int32の別名) Unicodeのコードポイントを指す
  • float32 float64
  • complex64 complex128
chihiro0940chihiro0940

Constants

const キーワードを使って定数を宣言できる。
定数は文字、文字列、boolean、数値のみで使える。
定数は := を使って宣言できない。

const Pi = 3.14
chihiro0940chihiro0940

If with a short statement

ifは条件の前に、評価するための簡単なステートメントを書くことができる。
ここで宣言された変数はifのスコープ内のみで有効。

func pow(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
        return v
    }
}
chihiro0940chihiro0940

Switch

GoのSwitchは選択されたcaseのみを実行して、それに続くcaseは実行されない。break文を書く必要もない。
条件のないswitchは switch true と書くことと同義。

func main() {
    os:= runtime.GOOS
    switch {
    case os == "darwin":
        fmt.Println("OS X.")
    case os == "linux":
        fmt.Println("Linux.")
    default:
        fmt.Printf("%s.\n", os)
    }
}
chihiro0940chihiro0940

Defer / Stacking defers

deferは、deferに渡した関数の実行を、呼び出し元の関数の終わりまで遅延させる。
deferへ渡した関数の引数はすぐに評価される。
deferへ渡した関数が複数ある場合は、return時にLIFOの順番で実行される。

func main() {
    for i := 0; i < 10; i++ {
        defer fmt.Println(i)
    }
    fmt.Println("done")
}

// done
// 9
// 8
// 7 ...
chihiro0940chihiro0940

Pointers

T型のポインタは *T型で、ゼロ値はnilになる。
& オペレータはそのオペランドへのポインタを引き出す。
* オペレータはポインタの指す先の変数を示す。

func main() {
    i := 42
    p := &i

    fmt.Println(*p) // 42
    *p = 21
    fmt.Println(*p) // 21
}
chihiro0940chihiro0940

Structs

struct 構造体はフィールドの集まり。

type Vertex struct {
    X int
    Y int
}
chihiro0940chihiro0940

Arrays

[n]T 型は型Tのn個の変数の配列を表す。
長さは型の一部である。よって配列のサイズは固定になる。

var a [10]int
chihiro0940chihiro0940

Slices / Slices are like references to arrays

[]T 型は型Tのスライスを表す。
スライスは配列への参照のようなもの。元の配列の部分列を指し示している。

func main() {
    names := [4]string{"John", "Paul", "George", "Ringo",}
    a := names[0:2]
    fmt.Println(a) // [John Paul]
}
chihiro0940chihiro0940

Slice length and capacity

スライスは長さと容量の両方を持つ。
スライスの長さ=含まれる要素の数。
スライスの容量=スライスの最初の要素から数えて、元となる配列の要素数。

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    a := s[:3]
    fmt.Println(len(a))   // 3
    fmt.Println(cap(a))  // 6
}
chihiro0940chihiro0940

Creating a slice with make

スライスは組み込みの make 関数を利用して作成することもできる。
make関数はゼロ化された配列を割り当て、その配列を指すスライスを返す。
make関数の第3引数にはスライスの容量を指定することができる。

func main() {
    a := make([]int, 5)
    fmt.Println(a) // [0 0 0 0 0]
}
chihiro0940chihiro0940

Range / Range continued

forループに利用する range は反復ごとに2つの変数を返す。
一つ目はインデックスで、2つ目はインデックスの場所の要素のコピー。
それぞれ _ に代入することで捨てることができる。

func main() {
    for i, v := range array {
        fmt.Println(i, v)
    }
}
chihiro0940chihiro0940

Maps

mapはキーと値とを関連付ける。
make関数は指定された型のマップを初期化する。

func main() {
    var m map[string]Vertex
    m = make(map[string]Vertex)
}
chihiro0940chihiro0940

Function closures

Goの関数はクロージャの特性を持つ。外部のスコープの変数を参照し続ける。
以下のadder()関数からreturnされる関数は、スコープ外のsum変数を参照し続ける。

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

func main() {
	pos, neg := adder(), adder()

	fmt.Println(pos(1)) // 1
	fmt.Println(pos(2)) // 3
	fmt.Println(pos(3)) // 6

	fmt.Println(neg(-1)) // -1
	fmt.Println(neg(-2)) // -3
	fmt.Println(neg(-3)) // -6
}