memo

Go Essential

インストール

Mac

brew install go

Linux

yum install gcc
cd /usr/local/src/
curl -O https://dl.google.com/go/go1.12.4.linux-amd64.tar.gz
cd ..
tar zxvf src/go1.12.4.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin

操作

関数呼び出し

変数

型変換

interface{} からの型変換(type assertion)

interface{} はそのまま型付きの変数に代入できない。

var hoge interface{} = "hoge"
var str string = hoge

次のエラーが発生。

cannot use hoge (type interface {}) as type string in assignment: need type assertion

次のように型指定して変化する。

var hoge interface{} = "hoge"
var str string = hoge.(string)
fmt.Println(str)

変換の左辺でステータスを受け取り、型変換可能に成功した場合だけ処理実行する。
このようにすると変数(hoge)が nil でも実行時エラーにならない(ok が false になる)。

var hoge interface{} = "hoge"
str, ok := hoge.(string)
if ok {
    fmt.Println(str)
}

使用

制御

for

swtich

Type Switches

package main

import(
    "fmt"
)

func judge( v interface{} ) {
    switch x := v.(type) {
    case int:
        fmt.Printf( "int: %v, %v\n", x , v )
    case string:
        fmt.Printf( "string %q %v\n", x, v )
    default:
        fmt.Printf( "unknown type: %v %T\n", x, v )
    }
}

func main() {
    judge( 15 )
    judge( "hello" )
    judge( [3]int{ 1, 2, 3 })

    // interface{}型の変数に代入された値が、期待する型かどうかを判定する場合
    var v interface{} = 15
    v, ok := v.( int )
    if ok {
        fmt.Println( "int value is ", v )
    }
}

ポインター

デフォルトでポインターなもの

デフォルトでポインターではないもの

構造体

コレクション

配列

Slice

[] の中に要素数を指定すると Array、指定しないと Slice になる。

Maps

関数

メソッド

インターフェース

エラーハンドリング

エラー型判定

package main

import (
    "os"
    "fmt"
)

func main() {
    file, err := os.Open("hoge.txt")
    if err != nil {
        fmt.Printf( "%T\n", err )       // *os.PathError
        fmt.Printf( "%v\n",   err )     // open hoge.txt: no such file or directory
        switch v := err.(type) {
        case *os.PathError:
            fmt.Println( "Path error:", v )    // Path error: open hoge.txt: no such file or directory
        default:
            fmt.Println( "Unknown error:", v )    // この行には分岐しない
        }
        return
    }

    defer file.Close()
}

Goroutines, channel

package main

import (
    "fmt"
	  "sync"
    "time"
)

// チャネルへの通知で終了判断
func say(s string, id int, ch chan int) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
    ch <- id
}

// チャネルクローズで終了判断
func say2(s string, ch chan int) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
    close(ch)
}

// WaitGroup で終了判断
func say3(s string, wg *sync.WaitGroup) {
    defer wg.Done()

    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    ch := make(chan int)
    go say("world", 1, ch)  // Goroutines で実行
    go say("hello", 2, ch)
    fmt.Println(<-ch)       // ch から受信するまで待機
    fmt.Println(<-ch)

    ch2 := make(chan int)
    go say2("ok", ch2)
    // for v := range ch2 { // channel を for でまわす普通の書き方
    //     fmt.Println( v ) // 今回はクローズを待機するだけなので、「v :=」は不要
    // }
    for range ch2 {}        // ch2 がクローズされるまで待機
    fmt.Println("exit")

    wg := sync.WaitGroup{}
    for i := 0; i<3; i++ {
        wg.Add(1)
        go say3("hoge", &wg)
    }
    wg.Wait()
}

パッケージ

日付・時刻

ログ出力

(例)

import (
    "os"
    "log"
    "runtime/debug"
)

func main() {
    log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

    log.Println("Hello")

    fp, err := os.Open( "hoge.txt" )
    if err != nil {
        debug.PrintStack()
        log.Fatal( err )
    }
    defer fp.Close()
    ...
}

スリープ(待機)