Go 1.6 リリースノート

Go 1.6の紹介

最新のGoリリースであるバージョン1.6は、1.5の6ヶ月後にリリースされました。変更のほとんどは、言語、ランタイム、ライブラリのインプリメンテーションに関するものです。言語仕様に変更はありません。常に、このリリースはGo 1の互換性の約束を維持しています。ほとんどすべてのGoプログラムは、これまでどおりコンパイルおよび実行されると予想されます。

このリリースでは、64ビットMIPS上のLinuxと32ビットx86上のAndroidへの新しいポートが追加され、GoポインタとCを共有するためのルールが定義および適用され、透過的で自動的なHTTP/2のサポートが追加され、テンプレートの再利用のための新しいメカニズムが追加されました。

言語の変更

このリリースには言語の変更はありません。

ポート

Go 1.6は、64ビットMIPS上のLinux(linux/mips64およびlinux/mips64le)への実験的なポートを追加します。これらのポートはcgoをサポートしますが、内部リンキングのみです。

Go 1.6は、32ビットx86上のAndroid(android/386)への実験的なポートも追加します。

FreeBSDでは、Go 1.6は外部Cコンパイラとしてgccではなくclangをデフォルトで使用します。

リトルエンディアン64ビットPowerPC上のLinux(linux/ppc64le)では、Go 1.6は外部リンキングによるcgoをサポートするようになり、ほぼ機能的に完成しています。

NaClでは、Go 1.5はSDKバージョンpepper-41を必要としていました。Go 1.6では、それ以降のSDKバージョンがサポートされます。

-dynlinkまたは-sharedコンパイルモードを使用する32ビットx86システムでは、レジスタCXは特定のメモリ参照によって上書きされるようになり、手書きのアセンブリでは避ける必要があります。詳細はアセンブリドキュメントを参照してください。

ツール

Cgo

cgoには、1つのマイナーな変更と合わせて、1つの主要な変更があります。

主要な変更は、GoポインタとCコードの共有に関するルールの定義であり、そのようなCコードがGoのガベージコレクタと共存できるようにすることを目的としています。簡単に言うと、GoとCは、そのメモリへのポインタがcgo呼び出しの一部としてCに渡された場合、Goによって割り当てられたメモリにGoが割り当てたメモリへのポインタが含まれておらず、呼び出しが返された後、Cがポインタを保持しない限り、Goによって割り当てられたメモリを共有できます。これらのルールは、プログラム実行中にランタイムによってチェックされます。ランタイムが違反を検出すると、診断を出力してプログラムをクラッシュさせます。環境変数GODEBUG=cgocheck=0を設定することでチェックを無効にできますが、チェックによって識別されたコードの大部分は、何らかの形でガベージコレクションと微妙に互換性がありません。チェックを無効にすると、通常はより謎めいた失敗モードにつながるだけです。問題のコードを修正することは、チェックをオフにするよりも強く推奨されます。詳細はcgoドキュメントを参照してください。

マイナーな変更は、Goのcomplex64complex128とは別に、明示的なC.complexfloatC.complexdouble型を追加したことです。他の数値型と同様に、Cの複素数型とGoの複素数型は互換性がなくなりました。

コンパイラツールチェーン

コンパイラツールチェーンはほとんど変更されていません。内部的には、最も重要な変更は、パーサーがyaccから生成されるのではなく、手書きになったことです。

コンパイラ、リンカ、goコマンドには、-raceと同様で、linux/amd64でのみ使用可能な新しいフラグ-msanがあり、Clang MemorySanitizerとの相互運用を有効にします。このような相互運用は、疑わしいCまたはC++コードを含むプログラムのテストに主に役立ちます。

リンカには、cgoコードをリンクするときのCコンパイラサポートライブラリの予想される場所を設定するための新しいオプション-libgccがあります。このオプションは、-linkmode=internalを使用する場合にのみ参照され、サポートライブラリの使用を無効にするためにnoneに設定できます。

Go 1.5で開始されたビルドモードの実装が、より多くのシステムに拡張されました。このリリースでは、android/386android/amd64android/arm64linux/386linux/arm64でのc-sharedモード、linux/386linux/armlinux/amd64linux/ppc64leでのsharedモード、そして新しいpieモード(位置独立実行可能ファイルの生成)がandroid/386android/amd64android/armandroid/arm64linux/386linux/amd64linux/armlinux/arm64linux/ppc64leでサポートされるようになりました。詳細は設計ドキュメントを参照してください。

念のためですが、リンカの-XフラグはGo 1.5で変更されました。Go 1.4以前では、次のように2つの引数を受け取っていました。

-X importpath.name value

Go 1.5では、それ自体がname=valueペアである単一の引数を使用する代替構文が追加されました。

-X importpath.name=value

Go 1.5では、古い構文は引き続き受け入れられ、代わりに新しい構文を使用することを提案する警告が出力されました。Go 1.6は古い構文を受け入れ続け、警告を出力します。Go 1.7では、古い構文のサポートが削除されます。

Gccgo

GCCとGoプロジェクトのリリーススケジュールは一致しません。GCCリリース5には、Go 1.4バージョンのgccgoが含まれています。次のリリースであるGCC 6には、Go 1.6.1バージョンのgccgoが含まれます。

Goコマンド

goコマンドの基本操作は変更されていませんが、注目すべき変更がいくつかあります。

Go 1.5では、環境変数GO15VENDOREXPERIMENT1に設定することで有効になる、ベンダーサポートの実験的なサポートが導入されました。Go 1.6は、実験的ではなくなったベンダーサポートを維持し、デフォルトで有効にします。環境変数GO15VENDOREXPERIMENT0に設定することで明示的に無効にできます。Go 1.7では、環境変数のサポートが削除されます。

デフォルトでベンダーサポートを有効にすることによって発生する可能性が高い問題は、新しいベンダーセマンティクスに従って解釈されることを期待していない既存のディレクトリvendorを含むソースツリーで発生します。この場合、最も簡単な修正方法は、ディレクトリ名をvendor以外のものに変更し、影響を受けるインポートパスを更新することです。

ベンダーサポートの詳細については、goコマンド設計ドキュメントのドキュメントを参照してください。

LLVMメモリサニタイザのサポートを使用してGoをコンパイルする新しいビルドフラグ-msanがあります。これは、メモリサニタイザを使用してチェックされているCまたはC++コードに対してリンクする場合に主に使用することを目的としています。

Go docコマンド

Go 1.5では、go docコマンドが導入され、go doc httpのように、パッケージ名のみを使用してパッケージを参照できるようになりました。曖昧さが発生した場合、Go 1.5の動作は、辞書順で最も早いインポートパスを持つパッケージを使用することでした。Go 1.6では、要素の数が少ないインポートパスを優先し、辞書順比較を使用してタイを解消することで曖昧さを解決します。この変更の重要な影響は、パッケージの元の複製が、ベンダーされた複製よりも優先されるようになったことです。検索が成功する頻度も向上する傾向があります。

Go vetコマンド

go vetコマンドは、f()が意図されていた場合にfを渡すなど、関数またはメソッドの値をPrintfの引数として渡すことを診断するようになりました。

パフォーマンス

常に、変更は非常に一般的で多様であるため、パフォーマンスに関する正確な記述を行うことは困難です。プログラムによっては実行速度が速くなる場合もあれば、遅くなる場合もあります。平均して、Go 1ベンチマークスイートのプログラムは、Go 1.6でGo 1.5よりも数パーセント高速に実行されます。ガベージコレクタの一時停止は、Go 1.5よりもさらに短く、特に大量のメモリを使用するプログラムでは顕著です。

compress/bzip2compress/gzipcrypto/aescrypto/ellipticcrypto/ecdsasortパッケージの実装に10%以上の改善をもたらす大きな最適化が行われました。

標準ライブラリ

HTTP/2

Go 1.6は、新しいHTTP/2プロトコルに対してnet/httpパッケージで透過的なサポートを追加します。Goクライアントとサーバーは、HTTPSを使用する場合、必要に応じて自動的にHTTP/2を使用します。HTTP/1.1に固有のエクスポートされたAPIがないのと同じように、HTTP/2プロトコル処理の詳細に固有のエクスポートされたAPIはありません。

HTTP/2を無効にする必要があるプログラムは、Transport.TLSNextProto(クライアントの場合)またはServer.TLSNextProto(サーバーの場合)を非nilの空のマップに設定することで実行できます。

HTTP/2プロトコル固有の詳細を調整する必要があるプログラムは、golang.org/x/net/http2、特にそのConfigureServer関数とConfigureTransport関数をインポートして使用できます。

ランタイム

ランタイムは、マップの同時実行による誤用を検出するための軽量で最善を尽くす検出機能を追加しました。常に、あるゴルーチンがマップに書き込んでいる場合、他のゴルーチンは同時にそのマップを読み書きすべきではありません。ランタイムがこの状態を検出すると、診断を出力してプログラムをクラッシュさせます。問題の詳細を知る最善の方法は、race detector を使用してプログラムを実行することです。これにより、競合状態をより確実に特定し、より詳細な情報を提供します。

プログラムを終了させるパニックの場合、ランタイムはデフォルトで実行中のゴルーチンのスタックのみを出力し、既存のすべてのゴルーチンのスタックは出力しません。通常、パニックに関連するのは現在のゴルーチンのみであるため、他のゴルーチンのスタックを出力しないことで、クラッシュメッセージの不要な出力が大幅に削減されます。クラッシュメッセージで全ゴルーチンのスタックを表示するには、環境変数 `GOTRACEBACK` を `all` に設定するか、クラッシュ前に `debug.SetTraceback` を呼び出して、プログラムを再実行してください。詳細は、ランタイムドキュメント を参照してください。

更新事項: タイムアウトの検出時や受信したシグナルを明示的に処理する場合など、プログラム全体の状態をダンプすることを目的としたキャッチされないパニックは、パニックを起こす前に `debug.SetTraceback("all")` を呼び出す必要があります。`signal.Notify` の使用箇所を検索すると、そのようなコードを特定するのに役立つ場合があります。

Windows では、Go 1.5 以前の Go プログラムは、起動時に `timeBeginPeriod(1)` を呼び出すことで、グローバルな Windows タイマー解像度を 1ms に強制していました。Go は優れたスケジューラのパフォーマンスのためにこれ以上必要なくなり、グローバルなタイマー解像度の変更は一部のシステムで問題を引き起こしていたため、この呼び出しは削除されました。

アーカイブまたは共有ライブラリをビルドするために `-buildmode=c-archive` または `-buildmode=c-shared` を使用する場合、シグナルの処理が変更されました。Go 1.5 では、アーカイブまたは共有ライブラリはほとんどのシグナルに対してシグナルハンドラをインストールしていました。Go 1.6 では、Go コードでのランタイムパニックを処理するために必要な同期シグナル(SIGBUS、SIGFPE、SIGSEGV)に対してのみシグナルハンドラをインストールします。詳細は、os/signal パッケージを参照してください。

リフレクション

`reflect` パッケージは、エクスポートされたフィールドを含む埋め込み非エクスポート構造体タイプに関する、gc と gccgo ツールチェーン間の長年の非互換性を解決しました。リフレクションを使用してデータ構造を巡回し、特に `encoding/json``encoding/xml` パッケージのようにシリアライゼーションを実装するコードは、更新が必要になる場合があります。

この問題は、リフレクションを使用して埋め込み非エクスポート構造体タイプのフィールドからその構造体のエクスポートされたフィールドに巡回する場合に発生します。この場合、`reflect` は、空の `Field.PkgPath` を返すことで、埋め込みフィールドを誤ってエクスポート済みとして報告していました。現在は、フィールドを正しく非エクスポート済みとして報告しますが、構造体内に含まれるエクスポートされたフィールドへのアクセスを評価する際にはその事実を無視します。

更新事項: 以前は構造体を巡回し、

f.PkgPath != ""

を使用してアクセスできないフィールドを除外していたコードは、現在では

f.PkgPath != "" && !f.Anonymous

を使用する必要があります。例として、`encoding/json``encoding/xml` の実装への変更を参照してください。

ソート

`sort` パッケージでは、`Sort` の実装が書き直され、`Interface` の `Less` と `Swap` メソッドへの呼び出しが約 10% 削減され、それに伴って全体的な処理時間が短縮されました。新しいアルゴリズムでは、等しいと比較される値(`Less(i,` `j)` と `Less(j,` `i)` が偽であるペア)に対して、以前とは異なる順序が選択されます。

更新事項: `Sort` の定義では、等しい値の最終的な順序については何も保証されていませんが、新しい動作によって、特定の順序を期待するプログラムが壊れる可能性があります。そのようなプログラムでは、目的の順序を報告するように `Less` 実装を改良するか、等しい値の元の入力順序を保持する `Stable` に切り替える必要があります。

テンプレート

text/template パッケージには、テンプレートの作成を容易にする2つの重要な新機能があります。

まず、テンプレートアクションの周りのスペースをトリミング することが可能になりました。これにより、テンプレート定義の可読性が向上します。アクションの先頭にマイナス記号を付けると、アクションの前にあるスペースがトリミングされ、アクションの末尾にマイナス記号を付けると、アクションの後にスペースがトリミングされます。たとえば、次のテンプレート

{{23 -}}
   <
{{- 45}}

は `23<45` としてフォーマットされます。

第二に、新しい`{{block}}` アクションと、名前付きテンプレートの再定義を許可することで、異なるインスタンスで置き換えることができるテンプレートの部分を簡単に定義できます。この新機能を示す例は、`text/template` パッケージにあります

ライブラリへのマイナーな変更