Go错误:无法在未实例化的情况下使用通用类型

34

我正在学习Go语言的泛型,但遇到了一个我无法解决的错误。我已经将代码简化到最简单的形式:

type opStack[T any] []T

func main() {

    t := make(opStack)
    //  t := new(opStack)
    t = append(t, 0)
    fmt.Println(t[0])
}

在 playground 中,make() 调用(以及被注释掉的 new 的调用)会引起以下错误信息:

cannot use generic type opStack[T any] without instantiation

但是,make() 是一个实例化函数。所以,我认为我可能缺少一些语法细节。Go 有什么抱怨,并需要什么样的更正呢?
3个回答

30
无论何时使用参数化类型,包括在内置的make中需要类型参数的任何地方,都必须使用实际类型替换其定义中的类型参数。这就是所谓的实例化。请保留html标记。
t := make(opStack[int], 0)
t = append(t, 0)

如果您将泛型类型用作另一个泛型类型的类型参数,则必须实例化它:

type Data[T any] struct {
    data T
}

d := Data[opStack[int]]{ data: []int{0, 1, 2} }

你可以使用类型参数进行实例化,例如在函数签名、字段和类型定义中:
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 }

语言规范中相关的引用(目前)分别在两个不同的位置,类型定义

如果类型定义指定了类型参数,则类型名称表示通用类型。必须在使用时实例化通用类型。

以及实例化

通过将类型参数替换为类型参数来实例化通用函数或类型。[...]

在其他编程语言中,“实例化”可能指创建对象的实例 - 在Go中,该术语特指用具体类型替换类型参数。在我看来,术语的使用仍然是一致的,尽管在Go中它不一定意味着分配。


请注意,您可以调用没有显式类型参数的通用函数。实例化也会发生在那里,只是类型参数可能全部从函数参数中推断出来:

func Print[T, U any](v T, w U) { /* ... */ }

Print("foo", 4.5) // T is inferred from "foo", U from 4.5

推理(Inference)过去在通用的类型中也可以工作,但是有一个限制,即类型参数列表必须非空。然而,这个功能已经被禁用了,因此您必须显式地提供所有类型参数。

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

非常感谢您提供的这个非常有帮助的回复。我对您的第一个代码片段不太确定:make()接受any而不需要定义类型:t := make(opStack[any], 0),请参见我设置的playground示例中的第10行。 - platypusguy
1
@platypusguy 第一个代码片段的意思是,你必须提供一个类型参数来实例化 opStack 并在 make 中使用它。opStack[any] 也是一个使用 any 实例化的别名为 interface{} 的类型。 - blackgreen

3

因为你需要

t = append(t, 0)

数据类型可以是int或float类型的组。

这段代码应该可以正常工作。

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])
}

谢谢。那个有效。我稍微修改了你的更正,以反映“任何”方面,这也有效: t := make(opStack[any], 0) - platypusguy

0

非常感谢您对此的详细解释。我曾经在寻找相关问题的答案,即如何使用泛型进行 struct typing Go Structural typing with Generics。我找到了一种方法,并认为它可能有助于类似的情况。

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])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接