Golang 如何使用 struct 泛型? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
blue7wings
V2EX    Go 编程语言

Golang 如何使用 struct 泛型?

  blue7wings 2022-02-21 18:12:26 +08:00 6632 次点击
这是一个创建于 1326 天前的主题,其中的信息可能已经有所发展或是发生改变。

代码:

 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 的泛型,还不是特别理解,网上也没搜到相关问题,请教一下大家,这里是哪里的错误?

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

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

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

type B struct {
AID string
BID string
}

都是不行的... 原因是 A 不满足 BID 约束
dcalsky
    6
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
    7
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
    8
eastphoton  
   2022-02-21 20:24:12 +08:00
你想用的是多态吧。。。
eastphoton
    9
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]())
}
looplj
    10
looplj  
   2022-02-21 21:04:07 +08:00
union 不支持 struct ,只支持基本类型
thevita
    11
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
    12
janxin  
   2022-02-21 21:33:25 +08:00
@thevita 因为你这个地方的约束是用的 fmt.Stringer

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

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

return val{
AID: "AID",
}
janxin
    13
janxin  
   2022-02-21 21:35:13 +08:00
@janxin 具体应该不是这个约束...记不太清具体是那个了
thevita
    14
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
    15
janxin  
   2022-02-21 21:51:23 +08:00
@thevita 你这是编译完成后展开之后的情况,编译成功之后就会被展开。我说的是编译期间约束检查。
janxin
    16
janxin  
   2022-02-21 22:01:29 +08:00
@thevita 换句话说,对于#6 中的例子中,你使用 fmt.Println(v.AID)是可以编译成功的,但是对顶楼和#7 例子结合的情况,编译是无法通过的。
lysS
    17
lysS  
   2022-02-22 11:19:14 +08:00
go 的泛型还没发布吧,要拉对应分支自己编译 go
macscsbf
    18
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
    19
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",
}
}
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5704 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 27ms UTC 03:06 PVG 11:06 LAX 20:06 JFK 23:06
Do have faith in what you're doing.
ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86