为什么即使泛型的类型参数相同,一个泛型也不能赋值给另一个泛型?

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

Why a generic can't be assigned to another even if their type arguments can?

问题

以下是代码的翻译:

// 抽象
type Generic interface {
	ID() string
}

type Props[G Generic] struct{}

// 示例
type Example struct {
	id string
}

func (example Example) ID() string {
	return example.id
}

var ExampleProps = Props[Example]{}

// 问题
func Problem() Props[Generic] {
	return ExampleProps
}

我的问题是:由于Example实现了Generic接口,为什么Go不允许将Props[Example]赋值给Props[Generic]

英文:

Following code throws a compilation error

> cannot use ExampleProps (variable of type Props[Example]) as Props[Generic] value in return statement

// Abstract
type Generic interface {
	ID() string
}

type Props[G Generic] struct{}

// Example
type Example struct {
	id string
}

func (example Example) ID() string {
	return example.id
}

var ExampleProps = Props[Example]{}

// Problem
func Problem() Props[Generic] {
	return ExampleProps
}

My question is: as Example implements Generic, why does Go not allow assigning Props[Example] to Props[Generic]?

答案1

得分: 4

实例化具有不同类型参数的泛型类型会产生两个新的不同命名类型。

请注意,每次提供类型参数时,包括在函数参数或返回类型中,都会实例化泛型类型:

// Props 使用类型参数 'Generic' 进行实例化
func Problem() Props[Generic] {
    return ExampleProps
}

因此,Props[Example]Props[Generic] 是不同的类型,你不能在期望另一个类型的地方使用其中一个类型的值。无论作为参数使用的类型本身是否满足某些可分配条件,例如接口和实现者,都无关紧要。

对于使用 any 实例化的泛型也是如此。类型 any 只是另一种静态类型 - interface{} 的别名。它不等于 T,也不等于“任何类型”。

简单来说,这就好像你在期望 string 的地方使用了 int

要修复这个问题并保持一定的灵活性,你可以使用类型参数实例化 Props - 是否有意义取决于你实际上计划如何使用此函数。无论如何,以下是一个示例:

// 添加一个字段,使其不那么牵强
type Props[G Generic] struct{ Value G }

// 使用 T 实例化的 Props,适当受限
func Problem[T Generic](v T) Props[T] {
    return Props[T]{ Value: v }
}

func main() {
    a := Problem(Example{})
    fmt.Println(a)
}

Playground: https://gotipplay.golang.org/p/wcDOtJ6z80u

英文:

Instantiating a generic type with different type arguments produces two new different named types.

Note that every time you supply a type argument, including in function arguments or return types, you are instantiating the generic type:

// Props is instantiated with type argument 'Generic'
func Problem() Props[Generic] {
    return ExampleProps
}

Therefore Props[Example] is just not the same type as Props[Generic] and you can't use values of one type wherever the other one is expected. It does not matter if the types used as arguments themselves meet some condition for assignability, e.g. interfaces and implementors.

This is also true of generics instantiated with any. The type any is just another static type — alias of interface{}. It's not equal to T and it's not equal to "whatever type".

In simpler terms it’s as if you were using int where string is expected.

What you can do fix it and keep some flexibility is to instantiate Props with a type parameter — whether this makes sense or not depends on how you actually plan to use this function. Anyway, as demonstration:

// adding a field to make this a bit less contrived
type Props[G Generic] struct{ Value G }

// Props instantiated with T, adequately constrained
func Problem[T Generic](v T) Props[T] {
	return Props[T]{ Value: v }
}

func main() {
	a := Problem(Example{})
	fmt.Println(a)
}

Playground: https://gotipplay.golang.org/p/wcDOtJ6z80u

huangapple
  • 本文由 发表于 2022年3月9日 02:08:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/71399641.html
匿名

发表评论

匿名网友

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

确定