このエントリーをはてなブックマークに追加

Go言語のTips

今日のGoConで学んだこと。 (順次更新していきます)

Sliceの扱い方

// slice作成 第二引数は初期の大きさ
urls := make([]Target, 0)
// 追加するにはappendを使う
urls = append(urls, Target{"http://tdoc.info/blog/", "setAccount"})

// 順々にアクセス
for i, u := range urls{ // iはindex番号。0から始まる
   fmt.Println(i, u)
}

チャンネルのタイムアウト

time.Afterを使う。

for {
    select {
    case receive := <-receiver:
      log.Println(receive)
    case <-time.After(time.Second):
      log.Println("timeout")
      return
    }
}

goroutineの数を制限する

まだ理解不足…

func worker(msg string) <-chan string {
  limit := make(chan int, 5) // limitを指定
  receiver := make(chan string)
  for i := 0; i < 1000; i++ {
    go func(i int) {
      limit <- 1
      msg := fmt.Sprintf("%d %s done", i, msg)
      receiver <- msg
      <-limit
    }(i)
  }
  return receiver
}

testの仕方

type Dummy struct {
    x int
    y int
}
func (d *Dummy) Testing() int { return d.x + d.y }

という感じでmain.goの中で定義しておく。

んで、main_test.goというファイル名で以下のように書く。今回は同じmainパッケージなので、package宣言はmainで。これにより、Dummy型がなにも付けなくても呼べる。

package main

import (
      "testing"
)

func TestTarget(t *testing.T) {
    d := Dummy{1, 2}
    if 3 != d.Testing() {
        t.Fail() // テストする
    }
}

testingパッケージをimportしておいて、あと、関数はTestではじめること。引数に*testing.Tを渡さられるので、そいつでFailとかを起こす。

assertとかはないみたい。

あとはgo testで実行。

% go test
PASS
ok      _/home/example/Works/golang/multihttp    0.007s
# -vをつけると個々のtest名が出てくる
%go test -v
=== RUN TestTarget
--- PASS: TestTarget (0.00 seconds)
PASS
ok      _/home/example/Works/golang/multihttp    0.007s

あとは-p nをつけると並列で、-cpu nとつけると指定したCPU数を使ってくれるみたい。

Example

また、Exampleというテストもかける。これは標準出力の文字列をテストするもの。

func ExampleHello() {
    fmt.Println("hello, and")
    fmt.Println("goodbye")
    // Output:
    // hello, and
    // goodbye
}

という感じで、main_test.goの中に Example で関数名で始まるように書いておくと、go testでテストされる。この場合、Printlnが標準出力に出す"hello,and(改行)goodbye"と、 // Output: というコメントの内容とが比較される。

ベンチマーク

同じようにベンチマークも書ける。BenchMarkで始まる関数を定義して

func BenchmarkHello(b *testing.B) {
    for i := 0; i < b.N; i++ { // b.Nで指定できる
        fmt.Sprintf("hello")
    }
}

-benchをつけてgo testを実行してみる。

% go test -bench Hello
PASS
BenchmarkHello   5000000               373 ns/op
ok      _/home/shirou/Works/golang/multihttp    2.218s

benchの後にパターンを指定して、そのパターンに適合したベンチマークだけが実行される。

benchcmp ってのがついてくるのでそれで比較もできる。

エラー処理

こんな感じでerrを返すように関数を書いておくのが流儀。

if val, err := Get(); err != nil{
   // エラーハンドリング
}

caseの中にも式が書ける

func unhex(c byte) byte {
    switch {
    case '0' <= c && c <= '9':
        return c - '0'
    case 'a' <= c && c <= 'f':
        return c - 'a' + 10
    case 'A' <= c && c <= 'F':
        return c - 'A' + 10
    }
    return 0
}

anonymous fields

フィールド名を匿名にしとくと簡単に書けますよ、というお話。

type Car struct {Color string}
type PricedCar struct { // Carを内包している
    Car  // 変数名なし
    Price string
}

car := PricedCar{Car{Color: "green"}, "100万円"}
fmt.Println(car.Color)  // car.Car.Colorじゃない

goroutineの待ち合わせ

syncパッケージを使うと楽。

func main() {
  var wg sync.WaitGroup
  for i:=0; i<3; i++ {
    wg.Add(1)  // 待ち合わせる数を増やしていく
    go func(i int) {
      log.Println(i)
      wg.Done() // 終わった数
    }(i)
  }
  wg.Wait() // ここで待つ
}