Generic Structs with Go

huangapple go评论79阅读模式
英文:

Generic Structs with Go

问题

以下是相应的Go代码:

type ModelX[T any] struct {
    Data T
}

func main() {
    m := ModelX[int]{}
}

在Go中,我们使用type关键字定义泛型结构体。在这个例子中,我们定义了一个名为ModelX的泛型结构体,它有一个名为Data的属性,类型为T。在main函数中,我们创建了一个ModelX[int]类型的实例m

请注意,Go语言中的泛型是在Go 1.18版本中引入的新特性。如果你使用的是旧版本的Go编译器,你可能需要使用其他方式来实现类似的功能。

英文:

What is the equivalent of this C# code in Go, how can I build it

    class ModelX<T>
    {
        public T Data { get; set; }
    }

    ModelX<int>

I have tried something like:

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

    m := ModelX<T>

How to do this? Is that possible?

答案1

得分: 66

从Go 1.18开始,你可以定义泛型类型

type Model[T any] struct {
    Data []T
}

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

func main() {
    // 将int作为类型参数传递
    modelInt := Model[int]{Data: []int{1, 2, 3}}
    fmt.Println(modelInt.Data) // [1 2 3]

    // 将string作为类型参数传递
    modelStr := Model[string]{Data: []string{"a", "b", "c"}}
    fmt.Println(modelStr.Data) // [a b c]
}

有关实例化的更多信息和常见问题:https://stackoverflow.com/questions/71274361

如果在泛型类型上声明方法,即使在方法范围内未使用类型参数,也必须在接收器上重复类型参数声明 — 在这种情况下,可以使用下划线 _ 来明确表示:

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

// 在此方法中未使用类型参数
func (m *Model[_]) String() string {
    return fmt.Sprint(m.Data)
}

一个重要的细节是,与函数<sup>2</sup>不同,泛型类型在实例化时必须始终提供所有<sup>3</sup>类型参数。例如,这个类型:

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

Playground: https://go.dev/play/p/n2G6l6ozacj

<hr>

脚注:

1:有关实例化的语言规范:https://golang.org/ref/spec#Instantiations

2:规范中的引用是:“对参数化函数的调用可以提供(可能是部分的)类型参数列表,或者完全省略它,如果省略的类型参数可以从普通(非类型)函数参数推断出来。”。此引用不包括参数化类型。

3:在早期的测试版中,泛型类型中的类型参数列表可以是部分的;这个特性已被禁用

英文:

Starting with Go 1.18, you can define generic types:

type Model[T any] struct {
	Data []T
}

A generic type must be instantiated<sup>1</sup> when used, and instantiation requires a type parameter list:

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{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;}}
	fmt.Println(modelStr.Data) // [a b c]
}

More info and common gotchas about instantiations: https://stackoverflow.com/questions/71274361

If you declare methods on a generic type, you must repeat the type parameter declaration on the receiver, even if the type parameters are not used in the method scope — in which case you may use the blank identifier _ to make it obvious:

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

An important detail is that — unlike functions<sup>2</sup> —, generic types must always supply all<sup>3</sup> type parameters upon instantiation. For example, this type:

type Foo[T any, P *T] struct {
	val T
	ptr P
}

must be instantiated with both types, even if some of them could be inferred:

func main() {
	v := int64(20)
	foo := Foo[int64, *int64]{val:v, ptr: &amp;v}

	fmt.Println(foo)
}

Playground: https://go.dev/play/p/n2G6l6ozacj

<hr>

Footnotes:

1: Language specs about instantiations: https://golang.org/ref/spec#Instantiations

2: The quote from the specs is "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.". This quote excludes parametrized types

3: in early beta releases, the type param list in generic types could be partial; this feature has been disabled.

huangapple
  • 本文由 发表于 2021年6月29日 00:01:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/68166558.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定