Golang Go语言如何使用 struct 泛型?

发布于 1周前 作者 vueper 来自 Go语言

Golang Go语言如何使用 struct 泛型?

代码:


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


更多关于Golang Go语言如何使用 struct 泛型?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

20 回复

大道至简

更多关于Golang Go语言如何使用 struct 泛型?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


楼主代码确定没问题吗,为什么我报错了

大道至简 /go 头

interface 相当于虚基类,配合切面使用基本就能达到其他语言 class 的效果:

gist.github.com/lesismal/e2203edd06a17fa5043bbfdbf6cbbaf7

因为这里泛型不能这么用…

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

type B struct {
AID string
BID string
}

都是不行的… 原因是 A 不满足 BID 约束


type A struct {
AID string
BID string
}

type B struct {
AID string
BID string
}

这样也是不行的



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

你想用的是多态吧。。。

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 GetXval ABX val {
return val{
AID: “AID”,
}
}

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

func main() {
fmt.Println(Get())
fmt.Println(GetXAX, GetXBX)
}

union 不支持 struct ,只支持基本类型

测试了下,应该是支持的,只不过很鸡肋,貌似没啥卵用。

<br>package main<br><br>import (<br> "fmt"<br> "runtime"<br>)<br><br>type A struct {<br> AID string<br>}<br><br>type B struct {<br> BID string<br>}<br><br>type AB interface {<br> A | B<br>}<br><br>func Show[val AB](v val) {<br> pc := make([]uintptr, 10) // at least 1 entry needed<br> runtime.Callers(0, pc)<br> f := runtime.FuncForPC(pc[0])<br> fmt.Printf("%s =&gt; %x\n", <a target="_blank" href="http://f.Name" rel="nofollow noopener">f.Name</a>(), f.Entry())<br> fmt.Println(v)<br>}<br><br>func main() {<br> a := A{AID: "aid"}<br> b := B{BID: "bid"}<br> Show(a)<br> Show(b)<br> Show(A{AID: "test"})<br><br>}<br><br>

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

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

请哪位大佬解惑

因为你这个地方的约束是用的 fmt.Stringer

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

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

return val{
AID: “AID”,
}

具体应该不是这个约束…记不太清具体是那个了



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

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

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

[![HvvkV0.jpg]( https://s4.ax1x.com/2022/02/21/HvvkV0.jpg)]( https://imgtu.com/i/HvvkV0)

你这是编译完成后展开之后的情况,编译成功之后就会被展开。我说的是编译期间约束检查。

换句话说,对于#6 中的例子中,你使用 fmt.Println(v.AID)是可以编译成功的,但是对顶楼和#7 例子结合的情况,编译是无法通过的。

go 的泛型还没发布吧,要拉对应分支自己编译 go

go 官网提供的泛型教程感觉就不太行
https://taoshu.in/go/generics/design.html?utm_source=wechat_session&utm_medium=social&utm_oi=643495174752309248

不知道这个能不能解决你的问题

刚刚看到一篇文章 《 Go 泛型简明入门教程》,感觉应该这样写:(我没验证)

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

func Getval A | B val {
return A{
AID: “AID”,
}
}

在Go语言中,泛型是Go 1.18版本引入的一个重要特性,它允许你编写更加通用和可复用的代码。虽然Go的泛型实现相对简单,但它为处理类型参数提供了强大的支持,特别是在使用struct时。

要使用struct泛型,你需要定义一个带有类型参数的泛型类型。例如:

package main

import "fmt"

// 定义一个泛型struct,T是一个类型参数
type Pair[T any] struct {
    First  T
    Second T
}

func main() {
    // 使用int类型实例化Pair
    intPair := Pair[int]{First: 1, Second: 2}
    fmt.Println(intPair)

    // 使用string类型实例化Pair
    stringPair := Pair[string]{First: "Hello", Second: "World"}
    fmt.Println(stringPair)
}

在这个例子中,Pair是一个泛型struct,它有一个类型参数T,这个参数可以是任何类型(由any约束表示)。然后,我们分别用intstring类型实例化了Pair

值得注意的是,Go的泛型实现采用了类型参数列表的语法(例如[T any]),这与一些其他编程语言(如C++或Java)的泛型语法有所不同。此外,Go的泛型约束相对简单,目前只支持接口作为约束条件,这有助于保持Go语言的简洁性和易用性。

希望这个解释能帮助你理解如何在Go语言中使用struct泛型。

回到顶部