Go1.18のGenericsで出来ないこと
はじめに
先日Go1.18がリリースされました.
リリースノートを見るとGo1.18の時点でのlimitationsが書いてあるのでコード書いて確認します.
全部で6つあります.
1つ目
The Go compiler cannot handle type declarations inside generic functions or methods. We hope to provide support for this feature in Go 1.19.
genericな関数やメソッドの中で型宣言できない.
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
}
func GenericsF[T any]() {
// [NG] type declarations inside generic functions are not currently supported
type s struct{}
}
func F() {
type s struct{}
}
関連issue: https://github.com/golang/go/issues/47631
2つ目
The Go compiler does not accept arguments of type parameter type with the predeclared functions real, imag, and complex. We hope to remove this restriction in Go 1.19.
real等の事前宣言された関数にgenericな型の引数を渡せない.
package main
import "fmt"
type MyFloat float64
func main() {
fmt.Println("Hello, 世界")
}
func GenericsF[T ~float64](a T) {
// [NG] a (variable of type T constrained by ~float64) not supported as argument to complex for go1.18 (see issue #50937)
_ = complex(a, a)
}
関連issue: https://github.com/golang/go/issues/45049
3つ目
The Go compiler only supports calling a method m on a value x of type parameter type P if m is explicitly declared by P's constraint interface. Similarly, method values x.m and method expressions P.m also are only supported if m is explicitly declared by P, even though m might be in the method set of P by virtue of the fact that all types in P implement m. We hope to remove this restriction in Go 1.19.
明示的に宣言されたメソッドしか呼び出せない.
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
}
type S1 struct{}
func (s S1) m() {}
type S2 struct{}
func (s S2) m() {}
type Constraint interface {
S1 | S2
m2()
}
func GenericsF[P Constraint](x P) {
// [NG] x.m undefined (type P has no field or method m)
x.m()
// [OK]
x.m2()
}
4つ目
The Go compiler does not support accessing a struct field x.f where x is of type parameter type even if all types in the type parameter's type set have a field f. We may remove this restriction in Go 1.19.
type parameterに渡せるすべての型が共通のフィールドを持っていたとしても,そのフィールドにはアクセスできない.
package main
import "fmt"
type S1 struct {
f int
}
type S2 struct {
f int
}
type Constraint interface {
S1 | S2
}
func main() {
fmt.Println("Hello, 世界")
}
func GenericsF[T Constraint](x T) {
// NG: x.f undefined (type T has no field or method f)
fmt.Println(x.f)
}
関連issue: https://github.com/golang/go/issues/48522
5つ目
Embedding a type parameter, or a pointer to a type parameter, as an unnamed field in a struct type is not permitted. Similarly, embedding a type parameter in an interface type is not permitted. Whether these will ever be permitted is unclear at present.
type parameterやそのポインタの埋め込みはできない.
package main
import "fmt"
type Embed[T any] struct {
field T // OK
T // NG: embedded field type cannot be a (pointer to a) type parameter
}
type EmbedPointer[T any] struct {
field *T // OK
*T // NG: embedded field type cannot be a (pointer to a) type parameter
}
type I[T any] interface {
T | int // NG: cannot embed a type parameter
}
func main() {
fmt.Println("Hello, 世界")
}
6つ目
A union element with more than one term may not contain an interface type with a non-empty method set. Whether this will ever be permitted is unclear at present.
空でないメソッドセットをもつinterface型はunion elementに使えない.
package main
import "fmt"
// interface type with a non-empty method set
type I1 interface {
Func()
}
type I2 interface{}
type I3 interface {
I1 | I2 // NG: cannot use main.I1 in union (main.I1 contains methods)
}
type I4 interface {
int32 | int64
}
type I5 interface {
float32 | float64
}
type I6 interface {
I4 | I5 // OK
}
func main() {
fmt.Println("Hello, 世界")
}
おまけ
Go1.19のマイルストーンはココから見られます.
「こういうことできないの?」が発生したら探せば見つかるかも.
Discussion