如何创建一个通用的结构体?

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

How to create a generic struct?

问题

如何构建一个通用的结构体?

我尝试了以下代码:

type SafeSet[type T] struct {
	Values map[T]bool
}

我希望能够这样使用:

SafeSet{ Values: make(map[net.Conn]bool) }
SafeSet{ Values: make(map[string]bool) }
SafeSet{ Values: make(map[int]bool) }
英文:

How can I construct a generic struct?

I tried:

type SafeSet[type T] struct {
	Values map[T]bool
}

I want to be able to do e.g.

SafeSet{ Values: make(map[net.Conn]bool) }
SafeSet{ Values: make(map[string]  bool) }
SafeSet{ Values: make(map[int]     bool) }

答案1

得分: 2

你不能在当前的Go版本1.17中这样做。很遗憾,没有其他可以说的了。


在泛型被添加到语言中之后,可能是在Go 1.18(2022年初),根据当前被接受的提案,这样一个参数化类型的语法将会是:

type SafeSet[T comparable] struct {
    Values map[T]bool
}

具体来说:

  • 类型约束出现在类型名T之后。
  • 如果你想将T用作映射的键,你必须使用内置的约束comparable,因为映射的键必须是可比较的,即支持==运算符。

然后,你需要使用实际的类型参数来实例化参数化类型:

示例:

要使用泛型类型,你必须提供类型参数。这被称为实例化。类型参数出现在方括号中,与往常一样。当我们通过提供类型参数来实例化类型时,我们会生成一个类型,其中类型定义中每个对类型参数的使用都被相应的类型参数替换。

s0 := SafeSet[net.Conn]{Values: make(map[net.Conn]bool)}
s1 := SafeSet[string]{Values: make(map[string]bool)}
s2 := SafeSet[int]{Values: make(map[int]bool)}

由于实例化SafeSet字面量看起来有点冗长,你可以使用一个泛型构造函数:

func NewSafeSet[T comparable]() SafeSet[T] {
    return SafeSet[T]{Values: make(map[T]bool)}
}

语法显然是相同的,只是在这种情况下,你明确地使用类型参数来实例化函数:

s3 := NewSafeSet[uint64]()
s3.Values[200] = true

Gotip Playground: https://gotipplay.golang.org/p/Qyd6zTLdkRn

英文:

You can't do that with the current Go version, 1.17. Unfortunately there's nothing else to say.

<hr>

After generics will be added to the language, probably in Go 1.18 (early 2022), the syntax for such a parametrized types, according to the current accepted proposal, will be:

type SafeSet[T comparable] struct {
    Values map[T]bool
}

In particular:

  • The type constraint comes after the type name T
  • If you want to use T as a map key, you must use the built-in constraint comparable, because map keys must be comparable — i.e. support == operator.

Then you have to instantiate the parametrized type with an actual type argument:

Example:

> To use a generic type, you must supply type arguments. This is called instantiation. The type arguments appear in square brackets, as usual. When we instantiate a type by supplying type arguments for the type parameters, we produce a type in which each use of a type parameter in the type definition is replaced by the corresponding type argument.

	s0 := SafeSet[net.Conn]{Values: make(map[net.Conn]bool)}
	s1 := SafeSet[string]{Values: make(map[string]bool)}
	s2 := SafeSet[int]{Values: make(map[int]bool)}

Since instantiating SafeSet literals looks kinda verbose, you can use a generic constructor func:

func NewSafeSet[T comparable]() SafeSet[T] {
	return SafeSet[T]{Values: make(map[T]bool)}
}

The syntax is, obviously, the same, except that in this case you are explicitly instantiating the function with the type arg:

	s3 := NewSafeSet[uint64]()
	s3.Values[200] = true

Gotip Playground: https://gotipplay.golang.org/p/Qyd6zTLdkRn

huangapple
  • 本文由 发表于 2021年9月5日 20:54:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/69063578.html
匿名

发表评论

匿名网友

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

确定