Reputation: 525
Studying Go generics, I'm running into an error I can't seem to untangle. I've boiled it down to the simplest code:
type opStack[T any] []T
func main() {
t := make(opStack)
// t := new(opStack)
t = append(t, 0)
fmt.Println(t[0])
}
In playground, this bonks at the make()
call (and similarly on the new
call that's commented out) with the following error message:
cannot use generic type opStack[T any] without instantiation
But make()
is an instantiating function. So, I expect I'm missing some syntactical subtlety. What is Go complaining about and what's the needed correction?
Upvotes: 41
Views: 49729
Reputation: 155
Thanks for detailed explanation on it. I was trying to find the answer for a related question on how to do struct typing
with generics Go Structural typing with Generics. I found the way to do it thought it might be helpful in similar cases.
package main
type Queue[T any] struct {
}
// Get implements Ops.
func (*Queue[T]) Get() T {
panic("unimplemented")
}
type Ops[T any] interface {
Get() T
}
var _ Ops[any] = new(Queue[any])
Upvotes: 0
Reputation: 44697
Whenever you use a parametrized type, including anywhere a type argument is required, like in the built-in make
, you must replace the type parameters in its definition with actual types. This is called instantiation.
t := make(opStack[int], 0)
t = append(t, 0)
A generic type must be instantiated also if you use it as a type argument to another generic type:
type Data[T any] struct {
data T
}
d := Data[opStack[int]]{ data: []int{0, 1, 2} }
You can instantiate with a type parameter, for example in function signatures, fields and type definitions:
type FooBar[T any] struct {
ops opStack[T]
}
type OpsMap[T any] map[string]opStack[T]
func echo[T any](ops opStack[T]) opStack[T] { return ops }
The relevant quotes from the language specs are (currently) in two different places, Type definitions:
If the type definition specifies type parameters, the type name denotes a generic type. Generic types must be instantiated when they are used.
and Instantiations
A generic function or type is instantiated by substituting type arguments for the type parameters. [...]
In other programming languages, "instantiation" may refer to creating an instance of an object — in Go the term specifically refers to replacing type params with concrete types. In my view, the usage of the term is still consistent, although in Go it doesn't necessarily imply allocation.
Note that you may call generic functions without explicit type arguments. Instantiation happens there too, simply the type arguments might all be inferred from the function arguments:
func Print[T, U any](v T, w U) { /* ... */ }
Print("foo", 4.5) // T is inferred from "foo", U from 4.5
Inference used to work also in generic types, with the restriction that the type parameter list had to be non-empty. However this feature has been disabled, so you must supply all type params explicitly.
type Vector[T any] []T
// v := Vector[int]{} -> must supply T
type Matrix[T any, U ~[]T] []U
// m := Matrix[int, []int]{} -> must supply T and U
Upvotes: 38
Reputation: 1450
because you want
t = append(t, 0)
the data type can be int or float group.
this code should work
package main
import "fmt"
func main() {
type opStack[T any] []T
t := make(opStack[int], 0) // You must initialize data type here
t = append(t, 0)
fmt.Println(t[0])
}
Upvotes: 3