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

What's new in Go 1.18?

syumai
February 18, 2022

What's new in Go 1.18?

Go 1.18 リリースパーティーにて発表の資料です。
https://gocon.connpass.com/event/234198/

syumai

February 18, 2022
Tweet

More Decks by syumai

Other Decks in Programming

Transcript

  1. Go 1.18 の目玉機能 Generics Fuzzing Workspace mode net/netip package Generics

    以外の 3 つについては、別途発表がありますのでそちらにお 任せします!
  2. 型パラメータ 型定義 (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 }
  3. 型引数、 インスタンス化 パラメータ化された型、関数の型パラメータは 型引数 (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 }
  4. 型推論 型引数は、型推論 (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)) // 上の行と同等 }
  5. 型制約 型パラメータは、型制約 (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 }
  6. インタフェースの記法の拡張 インタフェース要素 (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 }
  7. インタフェースの記法の拡張 加えて、 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 }
  8. インタフェースの記法の拡張 型要素は、旧来のメソッド宣言である メソッド要素 (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 }
  9. 応用編 ( さわりだけ話します) インタフェースは、型集合 (type sets) を表す概念となる。 interface { int

    | string } は、int 型とstring 型のみからなる有限 個の型の集合。 interface { ~int } は、int 型に対して定義された型からなる無限個 の型の集合。 interface { String() string } は、 String() string メソッドを実 装する無限個の型からなる集合。
  10. 応用編 ( さわりだけ話します) インタフェースの実装 (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 型 => 実装している
  11. 応用編 ( 今回はskip) インタフェース要素も、それぞれが型集合を表す。 型要素 int は、int 型のみからなる集合 型要素 ~int

    は、int 型を基底型に持つ型からなる集合 メソッド要素 String() string は、このメソッドを実装している型 からなる集合
  12. 応用編 ( 今回はskip) | の両側の要素、 type term もそれぞれが型集合を表し、全体が各要 素の型集合の 和集合

    (union) を表す。 ~int | ~string は、int 型を基底型に持つ型からなる集合と、string 型を基底型に持つ型からなる集合の和集合 インタフェース全体の型集合は、そのインタフェースが持つインタフ ェース要素それぞれの型集合の積集合。 interface { ~int; String() string } の型集合は、int 型を基底型に 持つ型の集合と、String メソッドを実装している型の集合の積集 合。
  13. 応用編 ( 今回はskip) 他のインタフェースをインタフェースの型要素に含むこともでき、こ れをインタフェースの埋め込み (embedded interface) と言う。 | による和集合、複数のインタフェース要素からなる積集合につい

    てのルールが、インタフェースの埋め込みに対しても適用される。 これによって、旧来のインタフェースの埋め込みと互換性を保つ ことが出来ている。
  14. 型制約の省略記法 利便性のため、型制約内の 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 型を基底型に持つ型) の値を返せるのがポイント。
  15. 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 }
  16. 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 では、ジェネリクスに関連した標準ライブラリの変更は行わ れない。
  17. 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 }
  18. 型エイリアス 型エイリアスが型パラメータを持てるようにする 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 時点では書けないが、将来的には書けるようになる見込み)
  19. メソッド メソッド宣言への型パラメータの追加は、実装上の都合でリリースの 見込みが立っていない 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 ... }
  20. 現時点のジェネリクスで出来ないこと 複合型の要素による型推論 type Ints[T constraints.Integer] []T と言う型があった時、 Ints{1, 2, 3}

    とは書けず、 Ints[int]{1, 2, 3} と型引数を明示す る必要がある 現時点で実装の見込みは立っていない。Type Parameters Proposal に言及あり
  21. 現時点のジェネリクスで出来ないこと ジェネリックな関数の中で型宣言が出来ない Go 1.19 で実装したいとのこと 事前宣言された real, imag, complex 関数を型パラメータ型で宣言さ

    れた関数の引数として渡すことが出来ない Go 1.19 で制限を外したいとのこと 構造体型に型パラメータ型を埋め込むことが出来ない | による型集合の和集合の要素として、メソッドを持つインタフェー スを含むことが出来ない これが許可されるようになるかは未定とのこと
  22. より詳しく知りたい方はこちら 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
  23. 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 のまま。