Slide 1

Slide 1 text

What's new in Go 1.18? syumai Go 1.18 Release Party (2022/2/18)

Slide 2

Slide 2 text

※ 注 Go 1.18 はまだリリースされていません。 本発表内容は、2022 年2 月18 日現在の情報を元にしています。 発表の構成は Go 1.18 Release Notes の Draft (https://tip.golang.org/doc/go1.18) を中心に行っています。

Slide 3

Slide 3 text

Go 1.18 の目玉機能 Generics Fuzzing Workspace mode net/netip package Generics 以外の 3 つについては、別途発表がありますのでそちらにお 任せします!

Slide 4

Slide 4 text

Generics

Slide 5

Slide 5 text

ジェネリクス ジェネリックなコードを書くための 型パラメータ (type parameters) とそれに関連した機能が追加される。 後方互換性が保たれているので、過去のバージョンのコードがコンパ イル出来なくなることはない。

Slide 6

Slide 6 text

型パラメータ 型定義 (type definition) と 関数宣言 (function declaration) に、型パ ラメータを追加することが出来るようになる。 // 型定義の例 type Vector[T any] []T type Map[K comparable, V any] map[K]V // 型パラメータは複数持てる type Pair[A, B any] struct { a A; b B } // 連続する型パラメータの制約が共通な時は省略も可能 // 関数宣言の例 func Min[T constraints.Ordered](a, b T) T { if a < b { return a } return b }

Slide 7

Slide 7 text

型引数、 インスタンス化 パラメータ化された型、関数の型パラメータは 型引数 (type arguments) によって置き換えられ、インスタンス化 (instantiation) さ れる。 インスタンス化の結果、新たな型、関数が生成され、それを使うこ とが出来ると言うイメージ。 func Min[T constraints.Ordered](a, b T) T { ... } // func Min[int](a, b int) int { ... } // `int` への置き換えイメージ // func Min[float64](a, b float64) float64 { ... } // `float64` への置き換えイメージ func main() { fmt.Println(Min[int](1, 2)) // `T` が 型引数 `int` に置き換わる => 1 fmt.Println(Min[float64](1.5, 0.5)) // `T` が 型引数 `float64` に置き換わる => 0.5 }

Slide 8

Slide 8 text

型推論 型引数は、型推論 (type inference) のアルゴリズムによって推論可能 な場合は省略することが出来る。 型推論には 関数引数型推論 (function argument type inference) 、 制約型推論 (constraint type inference) の 2 種類が存在し、これら を組み合わせたアルゴリズムで動作する ( ここでは踏み込んだ解説 を行わない) // 関数の引数から型引数を推論する例 func main() { fmt.Println(Min(1, 2)) // `int` が推論される // fmt.Println(Min[int](1, 2)) // 上の行と同等 fmt.Println(Min(1.5, 0.5)) // `float64` が推論される // fmt.Println(Min[float64](1.5, 0.5)) // 上の行と同等 }

Slide 9

Slide 9 text

型制約 型パラメータは、型制約 (type constraints) によって受け付ける型引 数を制限することができ、型制約によって行える操作も変わる。 型制約は、インタフェース (interfaces) によって表現される。 // fmt.Stringer インタフェースを型制約とする func PrintStringer[T fmt.Stringer](v T) { fmt.Println(v.String()) // ここで String() メソッドを呼べる } type StringableInt int func (i StringableInt) String() string { ... } func main() { PrintStringer(StringableInt(1)) // OK PrintStringer(1) // NG: int does not implement fmt.Stringer }

Slide 10

Slide 10 text

インタフェースの記法の拡張 型制約で、メソッド以外の制約を表現できるようにするために、イン タフェースの記法が拡張された。

Slide 11

Slide 11 text

インタフェースの記法の拡張 インタフェース要素 (interface elements) として、型要素 (type elements) を持つことが出来るようになる。 型要素は、 | で連結された型で表され、例えば、下記のような int 型または string 型のみを受け付ける型を書くことが出来る。 type IntOrString1 interface { int | string } type IntOrStrings1[T IntOrString1] []T func main() { _ = IntOrStrings1[int]{1, 2, 3} // OK _ = IntOrStrings1[string]{"a", "b", "c"} // OK _ = IntOrStrings1[float64]{1.0, 2.0, 3.0} // NG }

Slide 12

Slide 12 text

インタフェースの記法の拡張 加えて、 type MyInt int といった、型定義によって導入された型を 受け付けられるようにするため、 ~ 記号を型要素内の型名に付与す る記法が追加された。 ~T は、T 型を基底型 (underlying type) に持つ型の集合を表す。 type IntOrString1 interface { int | string } // `~` なし type IntOrStrings1[T IntOrString1] []T type IntOrString2 interface { ~int | ~string } // `~` あり type IntOrStrings2[T IntOrString2] []T type MyInt int func main() { _ = IntOrStrings1[MyInt]{1, 2, 3} // NG _ = IntOrStrings2[MyInt]{1, 2, 3} // OK }

Slide 13

Slide 13 text

インタフェースの記法の拡張 型要素は、旧来のメソッド宣言である メソッド要素 (method elements) と合わせて使うことが出来る。 例えば、int 型に対して定義された、 String() string メソッドを持つ 型への制約は次のように書ける。 type IntStringer interface { ~int // 型要素 String() string // メソッド要素 } func PrintIntStringer[T IntStringer](v T) { fmt.Println(v.String()) } type MyStringableInt int func (i MyStringableInt) String() string { ... } func main() { PrintIntStringer(MyStringableInt(100)) // OK }

Slide 14

Slide 14 text

応用編 ( さわりだけ話します) インタフェースは、型集合 (type sets) を表す概念となる。 interface { int | string } は、int 型とstring 型のみからなる有限 個の型の集合。 interface { ~int } は、int 型に対して定義された型からなる無限個 の型の集合。 interface { String() string } は、 String() string メソッドを実 装する無限個の型からなる集合。

Slide 15

Slide 15 text

応用編 ( さわりだけ話します) インタフェースの実装 (implements interface) の概念も変わる。 これまでは、ある型T がインタフェースの持つメソッドを全て実装 していることを指していた。 新しい仕様では、ある型T がインタフェースの型集合に含まれてい ることを 実装している と言う。 type IntOrString interface { int | string } // int 型 => 実装している // float64 型 => 実装していない type Stringer interface { String() string } type MyInt int func (i MyInt) String() string { ... } // int 型 => 実装していない // MyInt 型 => 実装している

Slide 16

Slide 16 text

応用編 ( 今回はskip) インタフェース要素も、それぞれが型集合を表す。 型要素 int は、int 型のみからなる集合 型要素 ~int は、int 型を基底型に持つ型からなる集合 メソッド要素 String() string は、このメソッドを実装している型 からなる集合

Slide 17

Slide 17 text

応用編 ( 今回はskip) | の両側の要素、 type term もそれぞれが型集合を表し、全体が各要 素の型集合の 和集合 (union) を表す。 ~int | ~string は、int 型を基底型に持つ型からなる集合と、string 型を基底型に持つ型からなる集合の和集合 インタフェース全体の型集合は、そのインタフェースが持つインタフ ェース要素それぞれの型集合の積集合。 interface { ~int; String() string } の型集合は、int 型を基底型に 持つ型の集合と、String メソッドを実装している型の集合の積集 合。

Slide 18

Slide 18 text

応用編 ( 今回はskip) 他のインタフェースをインタフェースの型要素に含むこともでき、こ れをインタフェースの埋め込み (embedded interface) と言う。 | による和集合、複数のインタフェース要素からなる積集合につい てのルールが、インタフェースの埋め込みに対しても適用される。 これによって、旧来のインタフェースの埋め込みと互換性を保つ ことが出来ている。

Slide 19

Slide 19 text

拡張されたインタフェースの仕様の制限 型要素を含んだインタフェースの型は、型制約にしか使うことが出来 ない。 変数の型や、関数の引数の型などには使えない。 type Number interface { ~int | ~float64 } func PrintNumber(n Number) { // NG ... } func main() { var n Number // NG }

Slide 20

Slide 20 text

型制約の省略記法 利便性のため、型制約内の interface { } は省略することが出来る。 func PrintInt[T interface { ~int }](v T) { ... } func PrintInt[T ~int](v T) { ... } // 上の行と同等 map, slice, channel などの要素型を持つ型を受け取るジェネリックな 関数を書くのに便利。 下記は、maps (https://pkg.go.dev/golang.org/x/exp/maps) の例 // Clone returns a copy of m. func Clone[M ~map[K]V, K comparable, V any](m M) M // `map[K]V` 型ではなく、 `M` 型 (map[K]V 型を基底型に持つ型) の値を返せるのがポイント。

Slide 21

Slide 21 text

事前宣言された制約の追加 事前宣言された制約として、 any と comparable が追加された。

Slide 22

Slide 22 text

any any は、 interface{} に対する型エイリアス。 型制約に繰り返し interface{} と書くことを避けるために追加され た。 型制約以外でも使うことが出来る。 func F[T any]() {} // OK var v any // OK

Slide 23

Slide 23 text

comparable !=, == によって比較可能なインタフェース以外の型を表す制約。 インタフェース型の場合は、そのインタフェースの含む型が全て比 較可能でないといけない。 comparable は型制約でしか使うことが出来ない。 func Equal[T comparable](a, b T) bool { return a == b } func main() { fmt.Println(Equal(1, 2)) // OK: => false var a, b interface{} a = 1 b = 2 fmt.Println(Equal(a, b)) // NG: interface{} does not implement comparable }

Slide 24

Slide 24 text

constraints, slices, maps ジェネリクスに関連した 3 つの package が golang.org/x/exp に追加 される。 golang.org/x/exp/constraints golang.org/x/exp/slices golang.org/x/exp/maps Go 1.18 では、ジェネリクスに関連した標準ライブラリの変更は行わ れない。

Slide 25

Slide 25 text

constraints package Float , Integer , Ordered といった、頻繁に使われる型制約の定義を まとめた package 。 Ordered は、 < <= >= > 記号で順序付け可能な型に対する制約。 // スライド冒頭の Min 関数の例 import "golang.org/x/exp/constraints" func Min[T constraints.Ordered](a, b T) bool { if a < b { return a } return b }

Slide 26

Slide 26 text

slices, maps package slices.Sort や、 maps.Keys など、さまざまなスライス型やマップ型 に適用可能な便利な関数をまとめた package 。

Slide 27

Slide 27 text

現時点のジェネリクスで出来ないこと 型エイリアス、メソッド宣言は型パラメータを持つことが出来ない

Slide 28

Slide 28 text

型エイリアス 型エイリアスが型パラメータを持てるようにする Proposal は accept されている https://github.com/golang/go/issues/46477 リリースは Go 1.19 以降に持ち越し type Vector[T any] []T type IntVector = Vector[int] // OK ( 型エイリアス宣言は型パラメータを持っていない) type Map[K comparable, V any] map[K]V type StringMap[V any] = Map[string]V // NG (Go 1.18 時点では書けないが、将来的には書けるようになる見込み)

Slide 29

Slide 29 text

メソッド メソッド宣言への型パラメータの追加は、実装上の都合でリリースの 見込みが立っていない https://go.googlesource.com/proposal/+/refs/heads/master/desi gn/43651-type-parameters.md#No-parameterized-methods type Vector[A any] []A // このようなメソッド宣言は書けない func (v Vector[A]) Map[B any](f func(v A) B) Vector[B] { ... } func main() { v := Vector[int]{1, 2, 3} v.Map[string](func (v int) string { ... }).Map ... }

Slide 30

Slide 30 text

メソッド 型パラメータを持つ型に対するメソッドは書くことが出来る 下記の例の、メソッドのレシーバ名 Vector[A] の A は、どんな名 前であってもよい type Vector[A any] []A // First は、 Vector の最初の要素を返すメソッド func (v Vector[A]) First() A { return v[0] }

Slide 31

Slide 31 text

現時点のジェネリクスで出来ないこと 複合型の要素による型推論 type Ints[T constraints.Integer] []T と言う型があった時、 Ints{1, 2, 3} とは書けず、 Ints[int]{1, 2, 3} と型引数を明示す る必要がある 現時点で実装の見込みは立っていない。Type Parameters Proposal に言及あり

Slide 32

Slide 32 text

現時点のジェネリクスで出来ないこと ジェネリックな関数の中で型宣言が出来ない Go 1.19 で実装したいとのこと 事前宣言された real, imag, complex 関数を型パラメータ型で宣言さ れた関数の引数として渡すことが出来ない Go 1.19 で制限を外したいとのこと 構造体型に型パラメータ型を埋め込むことが出来ない | による型集合の和集合の要素として、メソッドを持つインタフェー スを含むことが出来ない これが許可されるようになるかは未定とのこと

Slide 33

Slide 33 text

より詳しく知りたい方はこちら The Go Programming Language Specification - Go 1.18 Draft https://tip.golang.org/ref/spec Type parameters proposal https://go.googlesource.com/proposal/+/refs/heads/master/desi gn/43651-type-parameters.md 初めての型セット - @shino_nobishii https://speakerdeck.com/nobishino/introduction-to-type-sets

Slide 34

Slide 34 text

試したい方はこちら Go 1.18 RC1 https://go.dev/dl/#go1.18rc1 Tutorial: Getting started with generics https://go.dev/doc/tutorial/generics

Slide 35

Slide 35 text

試したい方はこちら Go Playground https://go.dev/play/?v=gotip または https://go.dev/play/ で Go dev branch を選択で実行可能

Slide 36

Slide 36 text

Core library

Slide 37

Slide 37 text

debug/buildinfo package Go コマンドにより実行ファイルに埋め込まれた、モジュールバージョ ン、バージョンコントロール、ビルドフラグ等の情報を取得するのに 使える、新しい package 従来、 runtime/debug.ReadBuildInfo で取得出来た情報と同等

Slide 38

Slide 38 text

net/netip package IP アドレスの型を定義する新しい package メモリ使用量が少なく、不変 (immutable) で、比較可能 (comparable) になった。 詳しくはこの後の発表にて

Slide 39

Slide 39 text

TLS 1.0 and 1.1 disabled by default client- side Config.MinVersion が設定されていなければ、 クライアントサイドの コネクションのデフォルトとして TLS 1.2 をに使うようになった。 Config.MinVersion を指定すれば、 TLS 1.0 / 1.1 も使える。 サーバーサイドのデフォルトは TLS 1.0 のまま。

Slide 40

Slide 40 text

Rejecting SHA-1 certificates crypto/x509 は、自己署名以外の SHA-1 ハッシュ関数で署名された 証明書を受け付けないようになった。

Slide 41

Slide 41 text

Minor changes to the library 入り切らなかったので割愛します… !