Golang泛型:如何使用类型近似实现通用结构体

Golang泛型:如何使用类型近似实现通用结构体 我正在尝试使用泛型,并在下面的示例代码中尝试使用类型近似,但出现了编译错误。

我的问题是:

  1. 如何对泛型结构体使用类型近似,参见 EmbedApprox
  2. 如何创建一个包含对另一个结构体进行类型近似的结构体,参见 ContainContain2
package main

import "fmt"

type Embed[T any] struct {
	AttrEmbed T
}

type EmbedApprox[T any] interface {
	~Embed[T] // A: 编译错误:~ 的无效使用(Embed[T] 的底层类型是 struct{AttrEmbed T})
}

type Contain[T EmbedApprox[T]] struct {
	Embed[T]
	AttrContain T
}

type EmbedApprox2[T any] interface {
	~struct{ AttrEmbed T } // 编译通过
}

type Contain2[T EmbedApprox2[T]] struct { // 编译通过
	Embed[T]
	AttrContain T
}

func main() {
	e := Embed[int]{AttrEmbed: 10}

	c := Contain[Embed[int]]{Embed[int]{AttrEmbed: 10}, AttrContain: 10} // 编译错误

	c2 := Contain2[Embed[int]]{Embed[int]{AttrEmbed: 10}, AttrContain: 10} // 编译错误

	fmt.Println(e, c)
}

编译错误:

# github.com/globalflea/trygenerics
./main.go:10:2: invalid use of ~ (underlying type of Embed[T] is struct{AttrEmbed T})
./main.go:30:15: cannot implement EmbedApprox[Embed[int]] (empty type set)
./main.go:30:27: cannot use Embed[int]{…} (value of type Embed[int]) as type Embed[Embed[int]] in struct literal
./main.go:30:65: mixture of field:value and value elements in struct literal
./main.go:32:2: c2 declared but not used
./main.go:32:17: Embed[int] does not implement EmbedApprox2[Embed[int]]
./main.go:32:29: cannot use Embed[int]{…} (value of type Embed[int]) as type Embed[Embed[int]] in struct literal
./main.go:32:67: mixture of field:value and value elements in struct literal

更多关于Golang泛型:如何使用类型近似实现通用结构体的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang泛型:如何使用类型近似实现通用结构体的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


类型近似在泛型结构体中的正确用法

你的代码存在几个关键问题。类型近似(~)只能用于类型约束中的类型字面量或类型别名,不能用于泛型类型实例。以下是修正方案:

1. 修正 EmbedApprox 接口

package main

import "fmt"

type Embed[T any] struct {
    AttrEmbed T
}

// 正确:类型近似只能用于具体类型,不能用于泛型类型实例
// 需要为 Embed[T] 创建类型别名
type MyEmbed[T any] Embed[T]

// 方法1:使用类型别名进行近似约束
type EmbedApprox[T any] interface {
    ~MyEmbed[T]
}

// 方法2:直接约束结构体类型
type EmbedApprox2[T any] interface {
    ~struct{ AttrEmbed T }
}

// 方法3:使用类型集合约束
type EmbedApprox3[T any] interface {
    Embed[T] | MyEmbed[T]
}

2. 修正 Contain 结构体

// 正确:Contain 应该接受一个类型参数,该类型满足 EmbedApprox 约束
type Contain[T any, E EmbedApprox[T]] struct {
    Embedder E
    AttrContain T
}

// 或者更简洁的写法
type Contain2[T any, E interface{ ~Embed[T] }] struct {
    Embedder E
    AttrContain T
}

3. 完整可运行的示例代码

package main

import "fmt"

type Embed[T any] struct {
    AttrEmbed T
}

// 创建类型别名以便使用类型近似
type MyEmbed[T any] Embed[T]

// 约束1:使用类型别名
type EmbedApprox[T any] interface {
    ~MyEmbed[T]
}

// 约束2:直接约束结构体类型
type EmbedApprox2[T any] interface {
    ~struct{ AttrEmbed T }
}

// Contain 结构体:正确使用类型约束
type Contain[T any, E EmbedApprox[T]] struct {
    Embedder E
    AttrContain T
}

// Contain2 结构体:使用内联约束
type Contain2[T any, E interface{ ~struct{ AttrEmbed T } }] struct {
    Embedder E
    AttrContain T
}

func main() {
    // 使用类型别名
    e1 := MyEmbed[int]{AttrEmbed: 10}
    c1 := Contain[int, MyEmbed[int]]{
        Embedder:    e1,
        AttrContain: 20,
    }
    fmt.Printf("Contain: Embedder.AttrEmbed=%d, AttrContain=%d\n", 
        c1.Embedder.AttrEmbed, c1.AttrContain)

    // 使用自定义类型(基于 Embed)
    type CustomEmbed[T any] struct {
        AttrEmbed T
        Extra     string
    }
    
    // CustomEmbed 满足 ~struct{ AttrEmbed T } 约束
    e2 := CustomEmbed[int]{AttrEmbed: 30, Extra: "test"}
    c2 := Contain2[int, CustomEmbed[int]]{
        Embedder:    e2,
        AttrContain: 40,
    }
    fmt.Printf("Contain2: Embedder.AttrEmbed=%d, Extra=%s, AttrContain=%d\n",
        c2.Embedder.AttrEmbed, c2.Embedder.Extra, c2.AttrContain)

    // 使用泛型函数演示
    printContain(c1)
    printContain2(c2)
}

// 泛型函数示例
func printContain[T any, E EmbedApprox[T]](c Contain[T, E]) {
    fmt.Printf("Generic function: AttrEmbed=%v, AttrContain=%v\n",
        c.Embedder.AttrEmbed, c.AttrContain)
}

func printContain2[T any, E interface{ ~struct{ AttrEmbed T } }](c Contain2[T, E]) {
    fmt.Printf("Generic function2: AttrEmbed=%v, AttrContain=%v\n",
        c.Embedder.AttrEmbed, c.AttrContain)
}

4. 关键要点

  1. 类型近似限制~ 只能用于具体类型(类型字面量或类型别名),不能用于泛型类型实例 Embed[T]
  2. 类型别名的作用:通过 type MyEmbed[T any] Embed[T] 创建别名,使 ~MyEmbed[T] 成为有效约束
  3. 结构体字面量:初始化时需要指定字段名,避免混合使用字段:值和值元素
  4. 类型参数顺序Contain[T any, E EmbedApprox[T]] 中,T 必须在 E 之前声明

这个修正后的代码可以正常编译运行,展示了如何在泛型结构体中正确使用类型近似约束。

回到顶部