go1.7 の気になるところを試した

go1.7のbeta1がでたので、軽く個人的に気になるところを触ったメモ
以下、環境はOSXで、公式で配布されている go1.7beta1.darwin-amd64.tar.gz を使っています

目玉としては、生成されるバイナリの高速化や、GCの改善などがありますが、日常業務でそんなにGoのパフォーマンスに不満をもつ機会もないので、それ以外で気になったものを中心に試しました。

リリース予定は、順調にいけば8月です。

## 関連リンク

ダウンロード
    https://golang.org/dl/#go1.7beta1

リリースノート
    https://tip.golang.org/doc/go1.7

## ビルドスピード

比較に使ったのは、仕事で使っているコードベースのビルド
generateされたコードも含めて、13万行ほどです。


go1.6

```
> /usr/bin/time -p go build cmd/tuner_server/main.go
real        18.80
user        30.14
sys          2.76
```


go1.7 beta-1

```
> /usr/bin/time -lp go build cmd/tuner_server/main.go
real        17.39
user        39.76
sys          4.32
```

ちょっと遅くなった... コードベースが大きいので、ほぼIOのスピードな感じはする。

ちなみに、バイナリサイズは、

| version | time |
| ---- | --- |
| go1.6.1 | 35M |
| go1.7 beta-1  | 27M |

かなりスリムになりました！

## context パッケージ

今まで、 `golang.org/x/net/context` 配下 にあった、 `context` パッケージが、go 本体ライブラリに統合された。
`context` パッケージの役割については、[Goの並行パターン：コンテキスト (Go Concurrency Pattern: Context)](https://ymotongpoo.github.io/goblog-ja/post/context/) などを参照。

それと同時に、 `*http.Request` に `Context() context.Context` メソッドと、 `WithContext(context.Context) *http.Request` メソッドが追加された。

今まで、いろいろなフレームワークが、主にミドルウェアから各ハンドラへの情報の引き渡しのために、独自のコンテキスト構造を持っていたが、1.7からはデフォルトのcontextを使うことで、ミドルウェアの型を、`func(http.Handler) http.Handler` に統一できてすっきりする。
今までは各フレームワーク感で型が統一されてないので、ミドルウェアの再利用性が低かったけど、 nodeの [connect](https://github.com/senchalabs/connect ) みたいなミドルウェアを集めたパッケージがいろいろと出てくるんじゃないかと思われし、各種フレームワークも context パッケージを使うように落ち着くんじゃないかなぁと個人的には思っている。

context の使い方サンプル

```go
package main

import (
	"context"
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
)

var middlewareKey = "m"

func middleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		ctx = context.WithValue(ctx, middlewareKey, "string set in middleware")
		cr := r.WithContext(ctx)
		next.ServeHTTP(w, cr)
	})
}

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()

		// デフォルトで context に紐付いている値たち
		
		// サーバーがlistenしてるアドレス
		_ = ctx.Value(http.LocalAddrContextKey).(net.Addr)
		// サーバー自体のオブジェクト
		_ = ctx.Value(http.ServerContextKey).(*http.Server)

		// ミドルウェアでリクエストに関連付けた値を取得する
		fmt.Println(ctx.Value(middlewareKey))
	})

	ts := httptest.NewServer(middleware(handler))
	defer ts.Close()

	http.Get(ts.URL)
}
```

## テストの subset 機能

テストの、サブセット機能がサポートされた

```go
package main

import "testing"

func TestMain(t *testing.T) {
	t.Parallel()

	t.Run("Sub1", func(t *testing.T) {
		t.Run("SubA", func(t *testing.T) {
		})
		t.Run("SubB", func(t *testing.T) {
		})
	})
	t.Run("Sub2", func(t *testing.T) {
		t.Run("SubA", func(t *testing.T) {
		})
		t.Run("SubB", func(t *testing.T) {
		})
	})
}
```

のようなテストを書き `go test -v` すると

```
=== RUN   TestMain
=== RUN   TestMain/Sub1
=== RUN   TestMain/Sub1/SubA
=== RUN   TestMain/Sub1/SubB
=== RUN   TestMain/Sub2
=== RUN   TestMain/Sub2/SubA
=== RUN   TestMain/Sub2/SubB
--- PASS: TestMain (0.00s)
    --- PASS: TestMain/Sub1 (0.00s)
        --- PASS: TestMain/Sub1/SubA (0.00s)
        --- PASS: TestMain/Sub1/SubB (0.00s)
    --- PASS: TestMain/Sub2 (0.00s)
        --- PASS: TestMain/Sub2/SubA (0.00s)
        --- PASS: TestMain/Sub2/SubB (0.00s)
PASS
ok      /path-to-package  0.008s
```

のようになる

### `-run` オプションの指定

Goのテストは、-run オプションで正規表現にマッチしたもののみ実行できるが、このオプションをsubsetになっているテストにも適用できる。
指定する場合は、階層毎に、`/` で区切り、正規表現で指定する。
上の例だと以下の様な感じ。

2階層目が Sub2 のものだけ実行

```
> go test -v -run .*/Sub2
=== RUN   TestMain
=== RUN   TestMain/Sub2
=== RUN   TestMain/Sub2/SubA
=== RUN   TestMain/Sub2/SubB
--- PASS: TestMain (0.00s)
    --- PASS: TestMain/Sub2 (0.00s)
        --- PASS: TestMain/Sub2/SubA (0.00s)
        --- PASS: TestMain/Sub2/SubB (0.00s)
PASS
ok      /path-to-package   0.008s
```

3階層目が SubB のものだけ実行

```
> go test -v -run .*/.*/SubB
=== RUN   TestMain
=== RUN   TestMain/Sub1
=== RUN   TestMain/Sub1/SubB
=== RUN   TestMain/Sub2
=== RUN   TestMain/Sub2/SubB
--- PASS: TestMain (0.00s)
    --- PASS: TestMain/Sub1 (0.00s)
        --- PASS: TestMain/Sub1/SubB (0.00s)
    --- PASS: TestMain/Sub2 (0.00s)
        --- PASS: TestMain/Sub2/SubB (0.00s)
PASS
ok      /path-to-package   0.007s
```

テストの構造化と、ピンポイントで走らせてサイクルを回すのがやりやすくなりそう。

##