从Go 1.18开始,您可以定义
泛型类型:
type Model[T any] struct {
Data []T
}
泛型类型在使用时必须被实例化1,实例化需要一个类型参数列表:
func main() {
modelInt := Model[int]{Data: []int{1, 2, 3}}
fmt.Println(modelInt.Data)
modelStr := Model[string]{Data: []string{"a", "b", "c"}}
fmt.Println(modelStr.Data)
}
有关实例化的更多信息和常见的坑点:Go error: cannot use generic type without instantiation
如果在泛型类型上声明方法,则必须在接收者上重复类型参数声明,即使在方法范围内未使用类型参数 - 在这种情况下,您可以使用下划线_
标识符使其明显:
func (m *Model[T]) Push(item T) {
m.Data = append(m.Data, item)
}
func (m *Model[_]) String() string {
return fmt.Sprint(m.Data)
}
重要的一点是,与函数不同2,泛型类型必须在实例化时始终提供所有3类型参数。例如,这个类型:
type Foo[T any, P *T] struct {
val T
ptr P
}
必须使用两种类型来实例化,即使其中一些可以推断出来:
func main() {
v := int64(20)
foo := Foo[int64, *int64]{val:v, ptr: &v}
fmt.Println(foo)
}
游乐场: https://go.dev/play/p/n2G6l6ozacj
脚注:
1: 关于实例化的语言规范: https://golang.org/ref/spec#Instantiations
2: 规范中的引用是"Calls to parameterized functions may provide a (possibly partial) type argument list, or may omit it entirely if the omitted type arguments are inferrable from the ordinary (non-type) function arguments."。此引用不包括参数化类型。
3: 在早期的 beta 版本中,通用类型中的类型参数列表可以是部分的;这个功能已经被禁用。
func NewModel[T any](data []T) Model[T] { return Model[T]{data} }
可以通过利用类型推断来简化一些用例;然后你可以这样做,例如:modelInt := NewModel([]int{1, 2, 3})
而不需要重复int
。 请参见 https://go.dev/play/p/t-brVDwpQ-V - antichris