Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go1.18最新情報(ジェネリクス、Fuzzing、Workspaceモード) - tennt...

Go1.18最新情報(ジェネリクス、Fuzzing、Workspaceモード) - tenntenn Conference 2022

この資料はtenntenn Conference 2022にて発表を行った際に用いた資料です。

■ tenntenn Conferenceとは
tenntenn Conferenceはtenntennが主催し、そしてすべてのセッションがtenntennによる登壇のカンファレンスです。

イベントページ:https://tenntenn.connpass.com/event/226562/
ハッシュタグ:#tennconn
資料(Google スライド):https://tenn.in/go118
動画:https://tenn.in/go118-video
再生リスト:https://tenn.in/conn22-videolist

■ 内容
Go1.18のリリースではジェネリクス(型パラメタ)、Fuzzing、Workspaceモードの3つの大きな機能を含んでいます。このセッションでは、2022年1月現在における最新情報をまとめています。

・ジェネリクス(型パラメタ)
・Fuzzing
・Workspaceモード
・Go1.18

■ 登壇者&主催者

・名前:tenntenn / 上田拓也
・HP:https://tenntenn.dev
・Twitter:https://twitter.com/tenntenn

メルカリ/メルペイ所属。バックエンドエンジニアとして日々Goを書いている。Google Developer Expert (Go)。一般社団法人Gophers Japan代表。Go Conference主催者。大学時代にGoに出会い、それ以来のめり込む。人類をGopherにしたいと考え、Goの普及に取り組んでいる。複数社でGoに関する技術アドバイザーをしている。大学においてGoに関する集中講義も担当している。マスコットのGopherの絵を描くのも好き。

■ Gopher道場 自習室

https://gopherdojo.org/studyroom/

Gopher道場とは、実践的なGoを体系的に学べる場です。
Gopher道場 自習室では、以下のようなコンテンツや学びの場を提供します。

・Gopher道場の講義を録画した動画(10時間以上分)
・Slackにおける受講者同士のコミュニティ
・Gopher道場卒業生による課題のレビュー(ボランティアでご協力頂いているのでベストエフォートです)

■ Meety(カジュアル面談)

・ソフトウェアエンジニアの地方移住ってどうなの?:https://meety.net/matches/jyZgDkEEwmMk
・メルカリグループにおけるGoの使いどころ:https://meety.net/matches/LbeVbIACxLqk
・地方からの技術コミュニティへの貢献:https://meety.net/matches/gVeMtImLkWJE

■ お仕事の依頼について

副業にて技術顧問やアドバイザーなどを行っています。過去の実績や問い合わせフォームは以下のURLからご確認ください。
https://tenntenn.dev/ja/job/

tenntenn - Takuya Ueda

January 15, 2022
Tweet

More Decks by tenntenn - Takuya Ueda

Other Decks in Programming

Transcript

  1. The Go gopher was designed by Renée French. The gopher

    stickers was made by Takuya Ueda. Licensed under the Creative Commons 3.0 Attributions license. Go1.18最新情報 ジェネリクス、Fuzzing、Workspaceモード 2022/01/15(土) tenntenn Conference 2022 資料:https://tenn.in/go118 動画:https://tenn.in/go118-video
  2. 上田拓也 Go ビギナーズ
 Go Conference
 @tenntenn tenntenn.dev Google Developer Expert

    (Go) 一般社団法人 Gophers Japan 代表理事 Experts Team
  3. Go1.18 リリースパーティ ▪ 詳細はこちらのイベントで! • 2022年02月18日(金) 19:00 〜 • https://gocon.connpass.com/event/234198/

    • Remoを使って開催予定! ◦ YouTube Liveでの配信はありません ◦ アーカイブは残す予定です
  4. Goの開発サイクル ▪ Goは毎年8月と2月にリリースされる • マイナーバージョンがアップされる • リリース3ヶ月前からDeveloper Freezeになる ◦ バグ修正とドキュメント修正以外は基本的に行われない

    • リリース2ヶ月前からベータ版がリリースされる • リリース1ヶ月前からRC版がリリースされる 引用元:Go Release Cycle 参考:Goのリリースプロセスとブランチ戦略 - YAMAGUCHI::weblog
  5. Go1の後方互換 ▪ Go1の間は言語の後方互換が保たれる • https://go.dev/doc/go1compat • 言語仕様に破壊的変更が加わらない • 標準ライブラリも後方互換が保たれる •

    一部例外はある ◦ セキュリティ、重大なバグなど • Go1.0で書いたコードはGo1.16でもビルドできる ◦ 場合によってはgo fixやgo fmtを掛ける必要がある • Go1を対象に執筆された書籍やブログは言語仕様に関しては 互換が保たれているためGo1.xの間は有効である ◦ ランタイムやgo toolに関しては変更される可能性あり
  6. Goの開発プロセスとGo2 ▪ Goの開発プロセス • 実際にGoを使った中で問題を見つける • 解決策をコミュニティに提案し議論する • 実装して評価する •

    問題なければリリースされる ▪ Go2とは? • https://blog.golang.org/toward-go2 • 明確なターゲットがあるわけではない • Go1.xとして開発されていき、Go1の後方互換が 保てなくなるような変更を加える必要になったら Go2としてリリースされる Goの開発プロセス
  7. Go1.18で入る予定の機能 ▪ Go 1.18で入る予定の機能 • Two New Tutorials for 1.18

    - The Go Blog • 型パラメタ(ジェネリクス) ◦ 型セット • Fuzzing • Workspace mode ▪ Go 1.19+で入る予定の機能 • 標準パッケージでの型パラメタの利用 ◦ golang.org/x/expでmapsパッケージとslicesパッケージは開発中 • 脆弱DB(未承認) ◦ pkg.go.devでexperiment=vulnsフラグをつけると出る
  8. Go1.18 Beta1を試す ▪ go1.18beta1コマンドをインストールする • 公式で複数のバージョンをインストールできる方法を提供している # Go1.18 Beta1をインストールする $

    go install golang.org/dl/go1.18beta1@latest $ go1.18beta1 download # Go1.16.1をインストールする $ go install golang.org/dl/go1.16.1@latest $ go1.16.1 download # dev.fuzzブランチをビルドしてインストールする $ go install golang.org/dl/gotip@latest $ gotip download dev.fuzz # ブランチ名は省略可 ※ Go1.15以前は go getコマンドを用いる
  9. gpコマンドを使う ▪ github.com/tenntenn/goplayground • The Go PlaygroundのAPI クライアント • gpというコマンドも付属している

    ◦ -backendというオプションがある # インストール $ go install github.com/tenntenn/goplayground/cmd/gp@latest # 実行 $ gp run -backend gotip main.go # フォーマット $ gp format -backend gotip main.go # シェアURLの生成 $ gp share -backend gotip main.go ダウンロード $ gp dl -backend gotip https://go.dev/play/p/SnqdM4Dvvjt?v=gotip
  10. 型パラメタを持つ関数の定義 ▪ 関数名の後ろに型パラメータを指定する • 関数呼び出しで型引数を指定する(インスタンス化) • 実際は型パラメタTは型引数で指定した型として扱われる • anyは任意の型を指定できることを表す(詳細は後述) •

    パッケージ関数のみ func Print[T any](s []T) { for _, v := range s { fmt.Print(v) } } func main() { Print[string]([]string{"Hello, ", "playground\n"}) Print[int]([]int{10, 20}) } Playgroundで動かす 型パラメタ 13 型引数
  11. 型パラメタを持つ関数のインスタンス化 ▪ 型引数を指定することでインスタンス化できる • 変数への代入なども行える • インスタンス化しないと呼び出しなどはできない 14 var printStr

    func([]string) = Print[string] printStr([]string{"Hello, ", "playground\n"}) Playgroundで動かす Print[T] Print[string] func([]string) Print[int] func([]int) T => string T => int インスタンス化
  12. 型推論 ▪ 型推論により型引数を省略することが可能 • 型推論は関数呼び出しのみ行われる • 型統一アルゴリズムを用いる(2パスアルゴリズム) ◦ 1: 型なしの定数を無視して統一化する

    ◦ 2: 型なしの定数をそのデフォルトの型とみなして扱う func main() { Print([]string{"Hello, ", "playground\n"}) Print([]int{1, 2, 3}) } Playgroundで動かす
  13. 型パラメタを持つ型 ▪ 型定義でも型パラメタを使用できる • 型名の後ろに型パラメタを指定する • 型エイリアスを用いてもインスタンス化できる // Vector型は型パラメタとしてTを持つ type

    Vector[T any] []T // 型引数を指定してインスタンス化する var ns Vector[int] = Vector[int]{10, 20, 30} // 型エイリアスを用いたインスタンス化 type IntVector = Vector[int] ms := IntVector{100, 200, 300} Playgroundで動かす
  14. 型パラメタを持つ型のメソッド ▪ 型パラメタを持つ型にメソッドを設けることは可能 • メソッドで新たに型パラメタを増やすことはできない 18 type Vector[T any] []T

    func (v *Vector[T]) Push(x T) { *v = append(*v, x) } func main() { var ns Vector[int] = Vector[int]{10, 20, 30} ns.Push(40) fmt.Println(ns) // [10 20 30 40] } Playgroundで動かす
  15. 型パラメタへの制約 ▪ インタフェースによって制約を加える • anyは任意の型を許可する ◦ interface{}の型エイリアス • [T fmt.Stringer]はTをfmt.Stringer型を実装した型に限る

    20 type Hex int func (h Hex) String() string { return fmt.Sprintf("%x", int(h)) } func Print[T fmt.Stringer](s []T) { for _, v := range s { fmt.Printf("0x%s\n", v.String()) } } func main() { Print([]Hex{100, 200}) } Playgroundで動かす 制約
  16. 組み込みの制約 ▪ 比較可能な型を表すcomparable • 定義することが不可能のため組み込みである必要がある • マップのキーにできる 21 func Keys[K

    comparable, V any](m map[K]V) []K { keys := make([]K, 0, len(m)) for k := range m { keys = append(keys, k) } return keys } func main() { m := map[string]int{"cat": 3, "dog": 2} fmt.Println(Keys(m)) // [cat dog] } Playgroundで動かす
  17. 制約と型セット ▪ インタフェース要素が拡張される • https://tip.golang.org/ref/spec#Interface_types • TypeElem:int | stringのように記述できるようになった •

    UnderlyingType: ~intや~stringのように記述 • 制約以外に使えるインタフェース(今までのインタフェース) ◦ MethodElemおよびTypeElemがインタフェースのみからなる 22 参考:https://zenn.dev/nobishii/articles/99a2b55e2d3e50 InterfaceType = "interface" "{" { InterfaceElem ";" } "}" . InterfaceElem = MethodElem | TypeElem . MethodElem = MethodName Signature . MethodName = identifier . TypeElem = TypeTerm { "|" TypeTerm } . TypeTerm = Type | UnderlyingType . UnderlyingType = "~" Type .
  18. Underlying type ▪ すべての型はUnderlying typeを持つ • int型やstring型などの組み込み型は自分自身 • 型リテラルで記述された型も自分自身 •

    Defined typeはtype X YのYのUnderlying type • 型階層が作れないようになっている • Underlying typeのメソッドセットを引き継ぐ ◦ 例:type I interface{ F() }、type T I 23 int []string struct {N int} X type X struct {N int} Y type Y X 参考:https://speakerdeck.com/dqneo/go-language-underlying-type
  19. 型セットとインタフェース ▪ インタフェースを実装するとは • その型セットの要素であること 24 インタフェース 型セット interface{} すべての型の集合

    interface{ e1; e2 } インタフェース要素e1とe2の型セットの共通部分 interface{ m1(); m2() } m1とm2をメソッドセットに持つ型の集合 interface{ T } 型Tだけからなる集合(型 Tは非インタフェース) interface{ ~T } 型Tのunderlying typeからなる集合 interface { t1 | t2 } Type term t1とt2の型セットの和集合
  20. interface{ … }の省略 ▪ 制約で省略して記述できる • https://go.dev/issue/48424 • constraintsパッケージで提供する制約を減らせる ◦

    新しく導入される制約を提供するパッケージ // interface{ ~map[K] V }を~map[K] Vと書ける func Keys[M ~map[K]V, K comparable, V any](m M) []K { keys := make([]K, 0, len(m)) for k := range m { keys = append(keys, k) } return keys } func main() { m := url.Values{"a":{"v1"}, "b":{"v2"}} fmt.Println(Keys(m)) // [a b] } Playgroundで動かす
  21. ファジングとは ▪ ランダムに大量の入力データを与えるテスト手法 • go-fuzzが有名 ◦ 標準パッケージやコンパイラのバグを多く発見している • コーパスと呼ばれるデータ群からデータを生成する •

    手入力で作ったテストデータでは難しいデータを作成 ◦ 大量のデータ ◦ バイアスのかかってないデータ • 予期しない入力によりクラッシュする可能性をテストする ◦ パニック • スタックオーバーフロー • インデックスが範囲を超える
  22. Go1.18で導入される機能 ▪ go testでファジングが利用できる • http://go.dev/doc/fuzz • 環境構築不要でファジングができる ◦ 実装がすべてGoで標準で用意される

    • testing.Fの追加 ◦ シードコーパスの追加 ◦ テスト関数の指定 • go test -fuzzでファジングを実行 ◦ デフォルトでは実行されないようにする • 通常はマシンパワーを使って長時間実行されるため • Rob Pike氏のコメント • すでにいくつかバグを見つけてるみたい ◦ Fuzzing trophy case - Go Wiki
  23. テスト関数の書き方 ▪ testing.Fを用いる • (*testing.F).Addメソッドでシードコーパスを追加 ◦ 基本型 • (*testing.F).Fuzzメソッドでテスト関数を指定 ◦

    引数に入力データが与えられる func FuzzFibo(f *testing.F) { f.Add(2) f.Fuzz(func(t *testing.T, n int) { if Fibo(n) != Fibo(n-2)+Fibo(n-1) { t.Fatal("NG") } }) }
  24. 実行の仕方 ▪ go testコマンドに-fuzzオプションを指定する • -fuzzオプションには正規表現が指定できる • -fuzzオプションを指定しない場合はシードコーパスのみでテスト ◦ testdata/corpus以下も読み込む

    • testdata/corpus以下のコーパスも使用される $ go test -fuzz FuzzFibo -fuzztime MAXの実行時間。デフォルトは無限。 -keepfuzzing クラッシュしても続けるか その他 -race、-parallel、-runなども対応