The following code results in the error "invalid composite literal type T".
package main
import "fmt"
func main() {
fmt.Println(createThing[foo]())
}
type thing interface {
foo | bar
}
type foo struct {
id int
a string
}
type bar struct {
id int
b int
}
func createThing[T thing, P *T]() P {
return &T{}
}
If I only include foo
in interface thing
, or remove a string
and b int
so foo
and bar
are exactly the same, the code will run without error. However, doesn't this defeat the purpose of generics? Why can't I instantiate a generic type like this, especially when I'm not even accessing any fields?
Possibly related to https://github.com/golang/go/issues/48522
CodePudding user response:
Most generic types are not valid types for composite literals. This isn't a problem though, as there are other ways to create values of generic types.
To create a pointer to a new zero value:
func createThing[T thing]() *T {
return new(T)
}
Or to create a non-pointer zero value:
func createThing[T thing]() T {
var value T
return value
}
As for why the error occurs in this way, here's the explanation from the spec, revised to address your specific question.
For composite literals:
The LiteralType's core type T must be a struct, array, slice, or map type
What is the core type?
An interface T has a core type if [...] there is a single type U which is the underlying type of all types in the type set of T
No other interfaces have a core type.
What is the underlying type?
Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its declaration.
A "type literal" can refer to a literal struct type, like struct{int id}
. So, when foo
and bar
both have an underlying type of struct{int id}
, then thing
has a core type of struct{int id}
, and so composite literals are possible. When foo
and bar
don't have the same underlying type, then thing
has no core type, and composite literals are not possible, hence your error.
The formal definition may seem complicated, but the result and practical takeaway is simple: generic code is only capable of expressing common behaviour across the possible types. Besides in the special case where all underlying types are the same, literal values are not a common behaviour.