Golang 如何使用 struct 泛型?

2022-02-21 18:12:26 +08:00
 blue7wings

代码:


type A struct {
	AID string
}
type B struct {
	BID string
}

type AB interface {
	A | B
}

func Get[val AB]() val {
	return A{
		AID: "AID",
	}
}

定义了两个 struct ,A 和 B ,并用定义了一个 constraint 包含了 A ,B 两个 struct ,那么 Get 函数返回 A ,为什么会提示"cannot use (A literal) (value of type A) as val value in return"?

刚刚接触 go 的泛型,还不是特别理解,网上也没搜到相关问题,请教一下大家,这里是哪里的错误?

6153 次点击
所在节点    Go 编程语言
19 条回复
imkerberos
2022-02-21 18:34:32 +08:00
大道至简
proxytoworld
2022-02-21 18:45:36 +08:00
楼主代码确定没问题吗,为什么我报错了
GM
2022-02-21 18:46:25 +08:00
大道至简 /go 头
lesismal
2022-02-21 18:58:12 +08:00
interface 相当于虚基类,配合切面使用基本就能达到其他语言 class 的效果:

gist.github.com/lesismal/e2203edd06a17fa5043bbfdbf6cbbaf7
janxin
2022-02-21 19:13:27 +08:00
因为这里泛型不能这么用...

定义 A|B 的时候不是或关系,而是需要 AB 都满足相同约束,你这个地方是不满足的。甚至你把 B 改成

type B struct {
AID string
BID string
}

都是不行的... 原因是 A 不满足 BID 约束
dcalsky
2022-02-21 20:04:42 +08:00
@janxin
type A struct {
AID string
BID string
}

type B struct {
AID string
BID string
}

这样也是不行的
thevita
2022-02-21 20:10:11 +08:00
@janxin

func Show[val AB](v val) {
fmt.Println(v)
}

func main() {
a := A{AID: "aid"}
b := B{BID: "bid"}
Show(a)
Show(b)
}

----
约束应该是可以这么用的

还没认真看过 go 的范型,所以不是很了解

大概逻辑是,范型展开的时候,需要根据具体的 代码(及 调用 Get/Show 的代码)中的类型信息( concrete type )进行约束检查,并展开成 concrete type 的代码, 不能用具体返回值来推断 函数返回类型 不然如下代码应该怎么办呢

----
func FuncA[val AB](yes bool) val {
if yes {
return A{
AID: "aid"
}
} else {
return B{
BID: "bid"
}
}
}
----
eastphoton
2022-02-21 20:24:12 +08:00
你想用的是多态吧。。。
eastphoton
2022-02-21 20:40:39 +08:00
type A struct {
AID string
}
type B struct {
BID string
}

type AB interface {
}

func Get() AB {
return A{
AID: "AID",
}
}

// -------------------

type AX struct {
AID string
}
type BX struct {
AID string
}

type ABX interface {
AX | BX
}

func GetX[val ABX]() val {
return val{
AID: "AID",
}
}

// -------------------

func main() {
fmt.Println(Get())
fmt.Println(GetX[AX](), GetX[BX]())
}
ZSeptember
2022-02-21 21:04:07 +08:00
union 不支持 struct ,只支持基本类型
thevita
2022-02-21 21:20:11 +08:00
@ZSeptember 测试了下,应该是支持的,只不过很鸡肋,貌似没啥卵用。

```
package main

import (
"fmt"
"runtime"
)

type A struct {
AID string
}

type B struct {
BID string
}

type AB interface {
A | B
}

func Show[val AB](v val) {
pc := make([]uintptr, 10) // at least 1 entry needed
runtime.Callers(0, pc)
f := runtime.FuncForPC(pc[0])
fmt.Printf("%s => %x\n", f.Name(), f.Entry())
fmt.Println(v)
}

func main() {
a := A{AID: "aid"}
b := B{BID: "bid"}
Show(a)
Show(b)
Show(A{AID: "test"})

}

```

=====
main.Show[...] => 108b0a0
{aid}
main.Show[...] => 108b280
{bid}
main.Show[...] => 108b0a0
{test}
=====

如上, A, B 两个类型,展开成了两个,Show 函数, 不过 貌似 v val 在 Show 里面什么都做不了,如果要转型成 A 或者 B 需要用 反射,要这范型何用。

请哪位大佬解惑
janxin
2022-02-21 21:33:25 +08:00
@thevita 因为你这个地方的约束是用的 fmt.Stringer

上面的程序中直接 return 一个 var v val 就会成功,但是你直接 return 了特定类型,相当于缩小了这个约定。

@dcalsky 抱歉这个地方忘记指明一个地方要调整了,就是上面说的那个原因。这种你这个具体例子中的情况可以使用下面的返回:

return val{
AID: "AID",
}
janxin
2022-02-21 21:35:13 +08:00
@janxin 具体应该不是这个约束...记不太清具体是那个了
thevita
2022-02-21 21:46:06 +08:00
@janxin

不是的,不是实例化 Stringer 类型

那个 binary 的符号表如下(过滤了下)

Show 对 A B 两个类型有两个实例

[![HvvkV0.jpg]( https://s4.ax1x.com/2022/02/21/HvvkV0.jpg)]( https://imgtu.com/i/HvvkV0)
janxin
2022-02-21 21:51:23 +08:00
@thevita 你这是编译完成后展开之后的情况,编译成功之后就会被展开。我说的是编译期间约束检查。
janxin
2022-02-21 22:01:29 +08:00
@thevita 换句话说,对于#6 中的例子中,你使用 fmt.Println(v.AID)是可以编译成功的,但是对顶楼和#7 例子结合的情况,编译是无法通过的。
lysS
2022-02-22 11:19:14 +08:00
go 的泛型还没发布吧,要拉对应分支自己编译 go
macscsbf
2022-02-22 13:20:04 +08:00
go 官网提供的泛型教程感觉就不太行
https://taoshu.in/go/generics/design.html?utm_source=wechat_session&utm_medium=social&utm_oi=643495174752309248

不知道这个能不能解决你的问题
cmdOptionKana
2022-02-22 20:12:10 +08:00
刚刚看到一篇文章 《 Go 泛型简明入门教程》,感觉应该这样写:(我没验证)

type A struct {
AID string
}
type B struct {
BID string
}

func Get[val A | B]() val {
return A{
AID: "AID",
}
}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/835462

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX