A Tour of goが長くてどこまでやったかわからなくなるので自分用まとめ

  • パッケージ名はインポートパスの最後の要素と同じの名前
  • goのメソッド名は最初の文字が大文字で始まる場合にpublic扱いで、それ以外はprivate(Exported names)
  • 関数の引数は、変数名の後ろに型名を書く(Functions)
func add(x int, y int) int {
    return x + y
}
  • 関数の2つ以上の引数が同じ型である場合は、最後の型を残して省略出来る(Functions)
func add(x, y int) int {
    return x + y
}
  • 関数は複数の戻り値を返す事が出来る(Functions)
func swap(x, y string) (string, string) {
    return y, x
}

func main() {
    a, b := swap("hello", "world")
}
  • 返り値となる変数に名前をつけることができる。型を書くとI/Oが1行にまとまって見やすそう(Named return values)
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}
  • var宣言で型は省略出来る(Variables)
var c, python, java = true, false, "no!"
  • importと同様に、まとめて宣言可能
var (
    ToBe   bool       = false
    MaxInt uint64     = 1<<64 - 1
    z      complex128 = cmplx.Sqrt(-5 + 12i)
)
  • var宣言のかわりに、:=を使う事もできる(Variables)
c, python, java := true, false, "no!"

Go言語の基本型

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 の別名

rune // int32 の別名
     // Unicode のコードポイントを表す

float32 float64

complex64 complex128

Goの型変換(Type conversions)

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

fmt.Printf("%T %T %T",i, f, u) // int float64 uint

定数(Constants)

const World = "世界"
fmt.Println("Hello", World) // Hello 世界

for

// 基本
sum := 0
for i := 0; i < 10; i++ {
    sum += i
}

// 条件式以外は省略可(条件式を省略すれば無限ループになる)
sum := 1
for ; sum < 1000; {
    sum += sum
}

// Goでのwhileはforで書ける
sum := 1
for ; sum < 1000; {
    sum += sum
}

if

func pow(x, n, lim float64) float64 {
    // ifの条件式の前には簡単なステートメントを書ける
    if v := math.Pow(x, n); v < lim {
        return v
    }
    return lim
    // return v        // ただし、if-elseのスコープ外では無効(これはundefined: v になる)
}

func main() {
    fmt.Println(
        pow(3, 2, 10),
        pow(3, 3, 20),
    )
}

switch

breakは書かなくても自動でされる。代わりにbreakしたくない場合は、fallthroughを書く

条件文のないswitchは、if-then-else構造をシンプルに表現出来る

switch {
case t.Hour() < 12:
    fmt.Println("Good morning!")
case t.Hour() < 17:
    fmt.Println("Good afternoon.")
default:
    fmt.Println("Good evening.")
}

defer

defer へ渡した関数の実行を、呼び出し元の関数の終わり(returnする)まで遅延させる

defer へ渡した関数は LIFO(last-in-first-out) の順番で実行される

func main() {
    defer fmt.Println("world")

    var lang = "golang"

    defer fmt.Println(lang)

    lang = "ruby"

    fmt.Println("hello")    // hello golang world と出力される
}

Pointers

func main() {
    i, j := 42, 2701

    p := &i
    fmt.Println(*p) // 42
    *p = 21
    fmt.Println(i)  // 21

    p = &j
    *p = *p / 37
    fmt.Println(j)    // 73
}

Structs(構造体)

Structのフィールドには、ドット( . )でアクセスする

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    v.X = 4
    fmt.Println(v.X)
}

もしくはポインタでアクセス

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    p := &v
    p.X = 1e9
    fmt.Println(v)
}

Struct Literals

読んでて使い所がよくわからなかったけどのちほど調べる

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
)

func main() {
    fmt.Println(v1, p, v2, v3)    // {1 2} &{1 2} {1 0} {0 0}
}

Arrays

func main() {
    var a [2]string
    a[0] = "Hello"
    a[1] = "World"
    fmt.Println(a[0], a[1])        // Hello World
    fmt.Println(a)                // [Hello World]
}

Slices

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("s ==", s)        // s == [2 3 5 7 11 13]

    for i := 0; i < len(s); i++ {
        fmt.Printf("s[%d] == %d\n", i, s[i])
    }
}

Slices of Slices

スライスには任意の型を収めることができ、他のスライスを入れることもできる

func main() {
    // Create a tic-tac-toe board.
    game := [][]string{
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
    }

    // The players take turns.
    game[0][0] = "X"
    game[2][2] = "O"
    game[2][0] = "X"
    game[1][0] = "O"
    game[0][2] = "X"

    printBoard(game)
}

func printBoard(s [][]string) {
    for i := 0; i < len(s); i++ {
        fmt.Printf("%s\n", strings.Join(s[i], " "))
    }
}

/*
    X _ X
    O _ _
    X _ O
*/

Slicing slices

s[lo:hi]    // lo から hi-1 までの要素のスライスを返す
s[lo:lo]    // 空のスライスとなる
s[lo:lo+1]    // 1つの要素を持つスライスとなる

s := []int{2, 3, 5, 7, 11, 13}
fmt.Println("s ==", s)
fmt.Println("s[1:4] ==", s[4:4])            // []

// missing low index implies 0
fmt.Println("s[:3] ==", s[:3])                // [2 3 5]

// missing high index implies len(s)
fmt.Println("s[4:] ==", s[4:])                // [11 13]

Making slices

// 長さ5のスライスを生成
a := make([]int, 5)        // [0 0 0 0 0]

// 3番目の引数に、スライスの容量を指定出来る
b := make([]int, 0, 5)    // []

Nil slices

スライスのゼロ値はnil

var z []int
fmt.Println(z, len(z), cap(z))
if z == nil {
    fmt.Println("nil!")
}

Adding elements to a slice

スライスへ新しい要素を追加するには、appendを使用。

var a []int
fmt.Printf("%s", a);

var a []int
fmt.Printf("%d\n",a)        // []
a = append(a, 0)
fmt.Printf("%d\n",a)        // [0]
a = append(a, 2, 3, 4)
fmt.Printf("%d\n",a)        // [0 2 3 4]

Range

rangeは反復毎に2つの変数を返す。1つ目の変数はインデックスで、2つ目の変数は値。(foreach的な感じ)

変数の部分に_(アンダーバー)を指定する事で、値は捨てる事が出来る

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

for i, v := range pow {
    fmt.Printf("2[%d] = %d\n", i, v)
}

for _, v := range pow {
    fmt.Printf("2[%d] = %d\n", i, v)    // iは捨てているのでエラーになる。(vだけならばエラーにならない)
}

Maps

map[(keyの型)](valueの型)という感じで書く

mapはmakeで作成する必要がある

type Vertex struct {
    Lat, Long float64
}

var m map[string]Vertex

m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
    40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])

Map literals

type Vertex struct {
    Lat, Long float64
}

var m = map[string]Vertex{
    "Bell Labs": Vertex{
        40.68433, -74.39967,
    },
    "Google": Vertex{
        37.42202, -122.08408,
    },
}

fmt.Println(m)    // map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]

mapに渡すトップレベルの型が単純な型である場合、型は省略できる

var m = map[string]Vertex{
    "Bell Labs": {40.68433, -74.39967},
    "Google":    {37.42202, -122.08408},
}

Mutating Maps

// 要素の挿入・更新
m[key] = elem

// 要素の取得
elem = m[key]

// 要素の削除
delete(m, key)

// キーに対する要素が存在するかどうか、2つ目の値で確認出来る(変数okはboolで存在すればtrue)
// mapにkeyが存在しない場合、elemはmapの要素の型のゼロ値になる
elem, ok = m[key]

// elemとokが未宣言であれば、 := で省略できる
elem, ok := m[key]

Function closures

func adder() func(int) int {
    sum := 0
    fmt.Println("adder")
    return func(x int) int {
        sum += x
        return sum
    }
}

func main() {
    pos := adder()
    for i := 0; i < 10; i++ {
        fmt.Println(pos(i))
    }
}

// adder
// 0
// 1
// 3
// 6
// 10

Methods

Goにはclassのしくみはないが、struct型にMethodを定義出来る((v *Vertex)の部分を「レシーバ」と言う)

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
    v := &Vertex{3, 4}
    fmt.Println(v.Abs())    // 5
}

Interfaces

interface型は、Methodの集まりで定義。

type Abser interface {
    Abs() float64
}

func main() {
    var a Abser
    f := MyFloat(-math.Sqrt2)
    v := Vertex{3, 4}

    a = f  // a MyFloat implements Abser
    a = &v // a *Vertex implements Abser

    // In the following line, v is a Vertex (not *Vertex)
    // and does NOT implement Abser.
    a = v        /* Absは、Vertexではなく*Vertexの定義なので、ここでエラーになる */

    fmt.Println(a.Abs())
}

type MyFloat float64

func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {    // ←レシーバを*VertexからVertexに変更するとエラーがでなくなる
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

Stringers

よく使われているinterfaceの1つに、fmtパッケージに定義されているStringerがある

type Stringer interface {
    String() string
}

Stringer インタフェースは、stringとして表現することができる型です。 fmt パッケージ(と、多くのパッケージ)では、変数を文字列で出力するためにこのインタフェースがあることを確認します。

package main

import "fmt"

// 構造体
type Person struct {
    Name string
    Age  int
}

// 構造体にメソッドを実装
func (p Person) String() string {
    return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}

func main() {
    a := Person{"Arthur Dent", 42}
    z := Person{"Zaphod Beeblebrox", 9001}

    fmt.Println(a, z)        // Arthur Dent (42 years) Zaphod Beeblebrox (9001 years)
}

Errors

Go言語では例外という概念はなく、error型という変数が用意されている

package main

import (
    "fmt"
    "time"
)

type MyError struct {
    When time.Time
    What string
}

func (e *MyError) Error() string {
    return fmt.Sprintf("at %v, %s",
        e.When, e.What)
}

func run() error {
    return &MyError{
        time.Now(),
        "it didn't work",
    }
}

func main() {
    if err := run(); err != nil {
        fmt.Println(err)        // at 2009-11-10 23:00:00 +0000 UTC, it didn't work
    }
}

その他

ここからは、実際に触ってみる途上で試してみた事とかのメモ

  • importはディレクトリしか指定出来ない(ファイル単体をimportしようとするとエラーになる)