使用Go语言的通用结构体

35
这段C#代码在Go中的等效代码是什么?我该如何构建它。
    class ModelX<T>
    {
        public T Data { get; set; }
    }

    ModelX<int>

我尝试过类似以下的方法:

    type ModelX<T> struct {
        ModelY
        Data []T
    }

    m := ModelX<T>

如何做到这一点?这是可能的吗?
1个回答

70
从Go 1.18开始,您可以定义泛型类型
type Model[T any] struct {
    Data []T
}

泛型类型在使用时必须被实例化1,实例化需要一个类型参数列表:

func main() {
    // passing int as type parameter
    modelInt := Model[int]{Data: []int{1, 2, 3}}
    fmt.Println(modelInt.Data) // [1 2 3]

    // passing string as type parameter
    modelStr := Model[string]{Data: []string{"a", "b", "c"}}
    fmt.Println(modelStr.Data) // [a b c]
}

有关实例化的更多信息和常见的坑点:Go error: cannot use generic type without instantiation

如果在泛型类型上声明方法,则必须在接收者上重复类型参数声明,即使在方法范围内未使用类型参数 - 在这种情况下,您可以使用下划线_标识符使其明显:

func (m *Model[T]) Push(item T) {
    m.Data = append(m.Data, item)
}

// not using the type param in this method
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 版本中,通用类型中的类型参数列表可以是部分的;这个功能已经被禁用


1
添加 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

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