2017この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。27日についに対応しました(まだ、ベータですが)。SEのGo1.8への移行方法とGo1.8になると何が嬉しいのか、移行する際に問題となる点についてまとめたいと思います。SDKをアップデートしましょう。updateをかけましょう。SDKを直に使っている方は、ダウンロードページから落としてきましょう。SDKを直に使っているので、落としてきたディレクトリをlsをしてみると以下のようになりました。wrapper_util.pygoroot-1.6とgoroot-1.8というディレクトリがあることが分かります。前のバージョンでは、gorootしかなかったので、Go1.6とGo1.8を使う場合で切り替えられるようになっているようです。goappコマンドを使って、実際に使われているGoのバージョンやGOROOTを見てみましょう。ちなみに、goコマンドやgoappコマンドにはenvというサブコマンドがあって、使用される環境変数を確認することができます。GOROOT/Users/tenntenn/Documents/go_appengine/goroot-1.6なるほど、デフォルトではgoroot-1.6の方を使うようですね。go1.8に変更するようにと書かれています。そこで、app.yamlの設定をたとえば以下のように変更してみます。alwaysそして、再度バージョンとGOROOTを確認してみます。GOROOT/Users/tenntenn/Documents/go_appengine/goroot-1.8おぉ。バージョンがGo1.8に変わりましたね。app.yamlの内容を見て切り替えているようです。context.Contextの移行と問題点context.Contextの移行Go1.7で標準パッケージにcontextパッケージが追加されました。それまで使われていた準標準パッケージのgolang.org/x/net/contextパッケージは使われなくなりました。標準パッケージにcontextが入ることで、多くの標準パッケージでcontext.Contextが使われるようになりました。何が加わったのか確認したい方は、Goのリリースノートやリリースパーティーの資料を見るとよいでしょう。SEにおいてもGo1.8に上がったことで、golang.org/x/net/contextではなく、contextパッケージを使用することになりました。そもそも、golang.org/x/net/contextのContext型はインタフェースであり、Go1.8のcontextパッケージのContext型と互換あります。Goにおいて、インタフェース型の変数への代入はインタフェースで規定しているメソッドを実装しているかどうかで決まります。そのため、golang.org/x/net/contextパッケージのContextインタフェースを実装している型は、同時にGo1.8のcontextパッケージのContextインタフェースも実装していることになります。golang.org/x/net/contextパッケージから標準パッケージのcontextパッケージへの移行は比較的簡単で、基本的にはインポート文を変更するだけで対応できます。fixで置換することが可能です。以下のように実行すると、main.goでインポートしているgolang.org/x/net/contextをcontextに変更することができます。main.goなお、goappを使っていないのは、goappのtoolコマンドにfixが無いためです。移行の際の問題点golang.org/x/net/contextパッケージから標準パッケージのcontextパッケージへの移行は、Contextインタフェースに互換性があるため、比較的簡単であると述べました。基本的には、インポート文を変更するだけで問題なく、たとえ標準パッケージのcontext.Contextをライブラリなどが提供するgolang.org/x/net/context.Contextを取る関数などに引数として渡しても問題ありません。いくつか例外があります。以下のように引数にクロージャを取るような関数などがライブラリで提供されている場合、クロージャの型自体は互換がないため渡すことができません。contextはgolang.org/x/net/contextだとする}また同様にスライスの要素やマップのキーやバリューなどコンポーネント型で使用している場合には互換がありません。map[*http.Request]context.Contextこれらはすべて、引数や要素の型を含めて型として定義されているためで、たとえメソッドが同じであるインタフェースを引数や要素に取っていても、コンポーネント型や関数型の型は異なるためです。このような問題に対応するには、ライブラリ側がビルドタグでGo1.6とGo1.7以降で使用するcontext.Context型を切り替えてやる必要があります。ご自身でライブラリを作られている場合は、osamingo/jsonrpcの対応などを参考にすると良いでしょう。OSSのライブラリがビルドタグで切り替えていない場合には、PRを送るかラップしてその場をしのぐ必要があります。context.Contextの問題はこれだけではありません。ライブラリの中で*http.Requestを元にcontext.Contextを生成するようなライブラリでは多くの場合問題が発生します。以下のようにgorilla/muxではうまくappengine.NewContextでリクエストからコンテキストを生成することができません。mx)}また、同様にlionのv2でもうまくcontext.Contextを取得することができません。これはGAEのコンテキストがリクエストと対になって管理されていることが原因です。make(map[*http.Request]*context),}GAEではappengine.NewContextをすると、引数で渡したリクエストに対応するコンテキストを取得します。その際、以下のようにライブラリの中でRequest.WithContextを用いていると、ハンドラにくる*http.Requestを上書いてしまい、コンテキストが取得できません。val))}この問題はissueになっているのでそのうち対応がされるとは思いますが、結構難しい問題ではないかと考えています。Goのnet/httpパッケージを修正して、Request.WithContextの挙動を変え、*http.Requestをコピーしないという手もありますが、Go側を変えるのは現実的では無いでしょう。GAE側のコンテキストの扱い方を変えるか、Request.WithContextをラップした関数を作り、その内部で上述したマップを書き換えるのが無難ではないかと考えています。1.8にアップデートする利点Go1.6からGo1.8にアップデートするにあたって、何が嬉しいのかざっくり箇条書きにしたいと思います。詳しい話は、Goのリリースノートやリリースパーティーの資料(1.7、1.8)を読むと良いでしょう。SEのコードでインポートしてもビルドできます。cgoを使えない環境ではstubが呼び出されるため、常にplugin.Openはエラーとなります。SEのGo1.8への移行方法と移行の際に問題になりそうな点を挙げました。ベータ版ということなので、これから修正が入るとは思いますが、随時アップデートは見ておこうと思います。何かアップデートがあったら追記したいと思います。2017-08-07にて修正されましたGo1.8用にgo_appengine/goroot-1.8/src/appengine_internal/api_go18.goというファイルが追加されました。このファイル内で、*http.Request経由で取得できるContextからGAE用のcontextを取得しています。これにより、たとえRequest.WithContextで*http.Requestを上書きしたとしても、リクエストが保持しているコンテキストはコピーされ、そこからGAEのコンテキストが取得できるというわけです。CoderPortfolio.。