Go の気になったコミット (2021 年 10 月)

[golang/go](https://github.com/golang/go) の master ブランチに行われたコミットから個人的に気になったものをリストにしたものです。

前回作成したリストはこちら。

https://qiita.com/sg0hsmt/items/1f75fa66d0f7d0f77d7f

軽く説明を追加していますが勘違いや誤りがあるかもしれません。

## Topic

- ジェネリクスで使用するタイプパラメータに interface{} を省略してそのままタイプセットを書けるようになりました。
- 文字列を 2 つに分割する strings.Cut が追加されました。
- ビルドしたバイナリにバージョン管理情報やビルド時の指定が埋め込まれるようになりました。
- パフォーマンスを理由として wasm で使用される syscall/js から js.Wrapper が削除されました。
- Go に workspace サポートが追加されました。
- sync.Mutex にロックされている場合はブロックせずに戻ってくる TryLock メソッドが追加されました。

## Commits

### 2021-10-01

https://github.com/golang/go/commit/5279e534b5ced1eaea19e8b75968498287ff6228

https://github.com/golang/go/commit/dab16c1c90626ca6c9704959500f120fd09546e6

https://github.com/golang/go/commit/952df981580659389679b27d65e1eceeedf0e2df

https://github.com/golang/go/commit/33576247e295b19311484d943d85495006d2fb39

ジェネリクスで使用するタイプパラメータに interface{} を省略してそのままタイプセットを書けるようにする変更です。 [^1]
constraints パッケージを使うより分かりやすい記述になっています。

[^1]: https://github.com/golang/go/issues/48424

### 2021-10-02

https://github.com/golang/go/commit/cf241a34a2ee8b337e11731958d918cbfd338caf

タイムアウトなどで名前解決に失敗した際に一貫して net.DNSError を返すようになります。 [^2]
これによりエラーの原因を調べやすくなります。

[^2]: https://github.com/golang/go/issues/39178

https://github.com/golang/go/commit/afe43f1e5e0d256341689195454527726b26ccae

Context.Value による値の取り出しが再起呼び出しからループに変更されています。 [^3]
Context はネストされやすく、短命な goroutine では再起呼び出しによるスタックサイズ変更がそれなりのコストになるようです。

[^3]: https://github.com/golang/go/issues/47292

### 2021-10-05

https://github.com/golang/go/commit/cfd74f7727f6ad5a81d574c28cbee52cc13fdc52

https://github.com/golang/go/commit/017ffcd10d980e7fe6ca101e253a12c9326fba37

https://github.com/golang/go/commit/3100dc1a7fe3f3302cf2419298b0585bc8e83890

https://github.com/golang/go/commit/c1a0aa300a1003ab823d5633e521e064a063271c

https://github.com/golang/go/commit/113b52979f48331b611e0fe7dadff97d6393ca27

https://github.com/golang/go/commit/e31c9ab557e9f5ee20a61914f1a2bf94191997dc

シンボル情報の配置を見直すことでロード時間の短縮やリンク時のメモリ消費を削減しているようです。

https://github.com/golang/go/commit/75773b0e7b4dac6b779e869a13096a7b7f0be5bb

https://github.com/golang/go/commit/113b52979f48331b611e0fe7dadff97d6393ca27

https://github.com/golang/go/commit/5758c40ac850f249eccd1676974aac11cb0e8b66

https://github.com/golang/go/commit/e82ed0cd83cec1e6d15ba5a037f77c0b9f1ec8c2

goroutine 起動か関数呼び出しのオーバーヘッドを改善しているようです。
正直なところよくわかっていません。

### 2021-10-06

https://github.com/golang/go/commit/810b08b8ec28ea00bce4c008f7c1b48bc9f3e134

小さなサイズの定数との比較を最適化しているようです。 [^4]

[^4]: https://github.com/golang/go/issues/37275

https://github.com/golang/go/commit/17c513e722e72739a59851e3a052952de36315aa

encoding/binary のエンディアン系関数を使っている場合にインライン化されやすくなりました。 [^5]

[^5]: https://github.com/golang/go/issues/42958

https://github.com/golang/go/commit/4002616f9a34410797e7bbff142c374a1de3ac6b

bytes や strings で ASCII 文字を trim する際のパフォーマンスが大幅に改善されています。 [^6]
8 月に行われていた改善 [^7] では 1 文字限定でしたが複数文字の場合も改善されました。

[^6]: https://github.com/golang/go/issues/46446
[^7]: https://github.com/golang/go/commit/5baf60d47245c792c50a349cd6b8586d23204895

https://github.com/golang/go/commit/c8dd89ed3dde52933d981d7d7c4c200160f47ec3

http.Cookie に値が有効かチェックする Valid メソッドが追加されました。 [^8]

[^8]: https://github.com/golang/go/issues/46370

https://github.com/golang/go/commit/8e36ab055162efa6f67f3b9ee62f625ac8874901

https://github.com/golang/go/commit/4d8db00641cc9ff4f44de7df9b8c4f4a4f9416ee

文字列を 2 つに分割する strings.Cut の追加と置き換えが行われています。
標準ライブラリの使用実態を調査したうえでより分かりやすい関数として実装されたようです。 [^9]

[^9]: https://github.com/golang/go/issues/46336

次の記事で strings.SplitN と比較されていました。
追加の目的は効率ではないとされていますが結果的に効率も改善されたようです。

https://zenn.dev/mattn/articles/01f258a5127ef8

### 2021-10-07

https://github.com/golang/go/commit/ecb2f231fa41b581319505139f8d5ac779763bee

指定値未満のランダムな整数値を取得する処理が fastrand() % n からより速い fastrandn() に変更されています。
両方とも runtime で定義されている関数で fastrand() 自体も一部の CPU で xorshift64+ から wyrand になっていたようです。 [^10] [^11]

[^10]: https://github.com/golang/go/commit/483533df9e35eea46747c5545307b230eca997b6
[^11]: https://github.com/wangyi-fudan/wyhash

https://github.com/golang/go/commit/2043b3b47b3ca76d8ce44f05a77e48d2291b6fc6

32 bit 環境にて uint64 から float32 への変換で丸め誤差が出る不具合の修正です。 [^12]
この commit だけでは不十分だったらしく追加の修正も行われています。 [^13]

[^12]: https://github.com/golang/go/issues/48807
[^13]: https://github.com/golang/go/commit/16a3cefc93d9b896b2053320e387d0e449904aba

https://github.com/golang/go/commit/77f2750f4398990eed972186706f160631d7dae4

wasm_exec.js に大きな引数を与えると wasm モジュールの一部を書き換えてしまう脆弱性修正です。 [^14]
この修正はバックポートされ Go 1.17.2 と Go 1.16.9 がリリースされています。

[^14]: https://github.com/golang/go/issues/48797

### 2021-10-08

https://github.com/golang/go/commit/5b9206f64ef4d8ea3201627cf9ba5c2b86e65022

time.ParseDuration() で int64 の最小値を parse できなかった問題が修正されています。 [^15]
最小値を設定する機会はないと思うのですがこの修正で性能向上しているのが面白いです。

[^15]: https://github.com/golang/go/issues/48629

### 2021-10-09

https://github.com/golang/go/commit/eba91e83b05f146892aec8922615e77b6496d886

WaitGroup の Example Test に含まれている URL が example.com に修正されました。 [^16] [^17]
ドキュメントに書く URL はちゃんと考えたほうがよさそうです。

[^16]: https://github.com/golang/go/issues/48886
[^17]: https://ja.wikipedia.org/wiki/Example.com

https://github.com/golang/go/commit/e1c294a56d5d03cdba1f059cdb6b1225477dc546

encoding/binary に関連した最適化のようです。
amd64 と arm64 にて 8 BYTE のデータを swap 命令を 2 回呼んでコピーしているのを 1 個の move 命令に置き換えています。 [^18]

[^18]: https://github.com/golang/go/issues/41684

### 2021-10-11

https://github.com/golang/go/commit/702e33717486cb8331db17304f2369ef641da61f

正規表現に UTF-8 として無効な文字が与えられた場合の挙動が修正されています。 [^19]
これまでは一貫性がなかったらしいのですが U+FFFD と同じとみなされるように統一されるようです。
本来は U+FFFD とも一致しないのが正しいですが既存動作を壊してしまうため妥協したようです。

[^19]: https://github.com/golang/go/issues/48749

### 2021-10-12

https://github.com/golang/go/commit/9c1dbdf60edbffeff10f58af21fa055eb0fdd29f

image/gif が出力した GIF 画像の互換性問題を解消するために compress/lzw が修正されています。 [^20] [^21]

[^20]: https://github.com/golang/go/issues/26108
[^21]: https://github.com/golang/go/issues/33748

https://github.com/golang/go/commit/732f6fa9d552c643b6225dd56689eb653ad61473

amd64 にて定数値が 32bit に収まる場合の ANDQ を ANDL に書き換える修正です。
これにより Linux x86_64 バイナリが 0.03% 小さくなるとのことです。
性能への影響もあるようですが良くなるものと悪くなるものが混在しているようです。

### 2021-10-14

https://github.com/golang/go/commit/765c9116be44641854f580c19e3589d7b86a3d28

https://github.com/golang/go/commit/434cdd0337b9e6c7e0c369c9293cc14fd38dc80d

https://github.com/golang/go/commit/85a068fdf21bd2e4475a87ee049af4fbe797bcbe

https://github.com/golang/go/commit/a8c5a994d62cc920c134426f7eae892b013ee32d

https://github.com/golang/go/commit/a37bebc042672d20837ea348d45e39740568cb77

https://github.com/golang/go/commit/0fd0639e4c429e147d33bfc42654fcd651f4449f

https://github.com/golang/go/commit/9e8ed86813dd49c4160dd4813901e2ac03de5abd

ビルドしたバイナリにバージョン管理情報やビルド時の指定を埋め込むための修正です。 [^22]
これまでは ldflag などで git の commit ハッシュなどを埋め込んでいましたが runtime から取得できるようになります。
また、実行ファイルのバイナリから埋め込まれた情報を取得する debug/buildinfo パッケージが追加されています。

この後も追加の修正が行われており最終的に Git, Mercurial, Fossil, Bazaar がサポートされたようです。

[^22]: https://github.com/golang/go/issues/37475

https://github.com/golang/go/commit/b59467e0365776761c3787a4d541b5e74fe24b24

https サーバーで ReadHeaderTimeout は設定しているが ReadTimeout を設定していない場合に TLS handshake がタイムアウトしない問題が修正されています。 [^23]

[^23]: https://github.com/golang/go/issues/48120

### 2021-10-18

https://github.com/golang/go/commit/74acbaf94ab3c7aaa7e22fda4f90920e90f11ead

for や switch が含まれる関数もインライン化できるようになったようです。 [^24]

[^24]: https://github.com/golang/go/issues/14768

https://github.com/golang/go/commit/6c0daa733192031eab23d09ed6515c4cd959aa92

パフォーマンスを理由として wasm で使用される syscall/js から js.Wrapper が削除されました。 [^25] [^26]
非互換の変更となりますが syscall/js は実験的な扱いのパッケージで互換性の約束を免除されています。 [^27]

[^25]: https://github.com/golang/go/issues/44006
[^26]: https://github.com/golang/go/issues/39740
[^27]: https://pkg.go.dev/syscall/js

### 2021-10-19

https://github.com/golang/go/commit/ad7db1f90fb66f00f5b020360aabd9f27d1c764f

64 bit アーキテクチャの場合に WaitGroup で行っているアライメントチェックを省略することでパフォーマンスを改善しています。

https://github.com/golang/go/commit/7999fd4710e7f987e86d7b32dd9af31ced4810ba

ドキュメントの修正です。
errors.Is は一致するエラーが見つかるまで unwrap するのでユーザーが実装した Is メソッドで errors.Unwrap を呼び出すべきではないとしています。

https://github.com/golang/go/commit/1d63052782a7535a3d4ce4557fd23fd97699b249

https://github.com/golang/go/commit/d94498470bb09bb0606b0eff3248cb5b35e1a145

Go に workspace サポートを追加するための変更です。 [^28]
設定は go.work というファイルに書くようです。

[^28]: https://github.com/golang/go/issues/45713

### 2021-10-25

https://github.com/golang/go/commit/fcd2d9cd75e6307b5b72fed2201044e231bef40a

mask が image.Alpha の場合の DrawMask のパフォーマンスを改善しています。 [^29]

[^29]: https://github.com/golang/go/issues/46395

### 2021-10-26

https://github.com/golang/go/commit/76cef81bcff371c88d277f17c712ecf22b8c83e7

ビルドしたバイナリに VCS のコミット時刻も含まれるようになりました。

### 2021-10-27

https://github.com/golang/go/commit/79ff663754f4238bd1fe2e56f460c2f603c71b80

ジェネリクスで使用するタイプパラメータに interface{} を省略してそのままタイプセットを書けるようになったため constraints パッケージから Slice/Map/Chan が削除されました。

### 2021-10-28

https://github.com/golang/go/commit/a3bb28e5ffee83c30a2c65963ef032cc2ab73a3c

range を含む関数もインライン化できるようになったようです。

### 2021-10-29

https://github.com/golang/go/commit/645d07819b2224ba4d759829443f7c6442162c69

sync.Mutex にロックされている場合はブロックせずに戻ってくる TryLock メソッドが追加されました。 [^30]
ただし、ほとんどの場合で TryLock の利用は好ましくないと考えているようです。

[^30]: https://github.com/golang/go/issues/45435

https://github.com/golang/go/commit/353d5b6c536c7028eba058ba27014fae0206298a

Windows 環境でクラッシュダンプが作成できるようになったようです。 [^31]

[^31]: https://github.com/golang/go/issues/20498

https://github.com/golang/go/commit/413672fc84e0ced7531cdc7cf0e5db32061e8194

https://github.com/golang/go/commit/4a5d78ff8b7e777d70b18a61698b1ac07bbd623d

https://github.com/golang/go/commit/8e112a7c2a814de9156f68dc8b167e4ef8c98c52

https://github.com/golang/go/commit/9ac1ee2d464eff73077afda83677f155bd69c6b8

https://github.com/golang/go/commit/9da64156a62e4661fb5b0e64a2f196f253ce0dc5

https://github.com/golang/go/commit/994049a9ad3d4230d0835ce36616a34a466f6718

GC をいつ動かすか決定するアルゴリズム (GC Pacer) を再設計するための修正の一部です。 [^32]

[^32]: https://github.com/golang/go/issues/44167

## 感想

Go 1.18 の目玉機能ということもあってジェネリクス関連の修正が多いのですがそれ以外にも多数の改善が行われていました。

また、リストには書いていないのですが GOAMD64 指定による性能改善もいくつかありました。
ビルド環境より実行環境のほうが古いこともあるので自動設定されると怖いですがうまく使えば新しい CPU の恩恵を受けられそうです。