🐥

Go1.18のGenericsで出来ないこと

2022/03/22に公開

はじめに

先日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