Golang中使用泛型实现多态Clone()方法?

Golang中使用泛型实现多态Clone()方法? 尝试创建一个 Clone() 函数,该函数返回“最终”的具体类型,并使用引用以多态方式创建最终类型的克隆,但遇到了编译错误。欢迎提供想法/解决方案。

是否有可能使下面的代码编译通过,或者是否有惯用的方法来实现带有接口/结构体嵌入的多态克隆?

package main

import "fmt"

type Cloner[T any] interface {
	Clone() T
}

type AI[T any] interface {
	// 希望所有实现都有一个返回最终类型的 Clone() 方法
	Cloner[AI[T]]
}

// 通过嵌入接口来实现 AI 接口
type AS struct {
	AI[int]
	a int
}

func (as AS) Clone() AS {
	return AS{a: as.a}
}

// 通过嵌入接口来实现 AI 接口
type BS struct {
	AI[int]
	b string
}

func (bs BS) Clone() BS {
	return BS{b: bs.b}
}

// 通过嵌入 AS 结构体来实现 AI 接口
type CS struct {
	AS
	c int
}

func (cs CS) Clone() CS {
	return CS{
		AS: cs.Clone(), // 错误:无法将 cs.Clone() (类型为 CS 的值) 用作结构体字面量中的 AS 类型
		c:  cs.c,
	}
}


func main() {
	var aiRef AI[int]

	// 尝试获取具体对象的克隆

	aiRef = &AS{a: 10}
	fmt.Printf("AS: %#v\n", aiRef.Clone())
	// 编译错误:
	//  ./main.go:42:10: 无法将 &AS{…} (类型为 *AS 的值) 作为类型 AI[int] 赋值:
	//  *AS 未实现 AI[int] (Clone 方法的类型错误)
	//  拥有 Clone() AS
	//  需要 Clone() AI[int]

	aiRef = &BS{b: "hello"}
	fmt.Printf("BS: %#v\n", aiRef.Clone())
	// 与上述相同的编译错误

	aiRef = &CS{c: 10}
	fmt.Printf("CS: %#v\n", aiRef.Clone())
	// 与上述相同的编译错误
}

更多关于Golang中使用泛型实现多态Clone()方法?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

你好 @globalflea

我刚刚在这里发布了一个类似问题的答案。这可能也适用于你的情况。

更多关于Golang中使用泛型实现多态Clone()方法?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好,

感谢回复,但这并未解决这一系列问题。我仍然在尝试创建“派生”类型的实例时遇到问题,或者更确切地说,我不知道如何声明一个定义,要求子结构体拥有一个返回子类型的 Clone 方法。

具体来说,我如何确保所有子类型都有一个 Clone 函数?

type AI[T any] interface {
	// 希望所有实现都有一个返回最终类型的 Clone() 方法

	Cloner[AI[T]]
	// ?? 如何声明一个由子类型实现的泛型 Clone()?
	// ??  特别是,由于我并不知道实际的子类型是什么
}

我想在 Rust 中,我可以声明类似 Clone() -> Self 的东西。

另外,在 main() 中:

	var aiRef AI[int]

	aiRef = &AS{a: 10}
	//   ./main.go:56:10: cannot use &AS{…} (value of type *AS) as type AI[int] in assignment:
	//   *AS does not implement AI[int] (wrong type for Clone method)
	//   have Clone() AS
	//   want Clone() AI[int]

注意到,CloneAny() 在调用子结构体的 Clone() 函数时是有效的,对此表示感谢。

	// fmt.Printf("AS: %#v\n", aiRef.Clone()) // 之前有编译错误
	fmt.Printf("AS: %#v\n", CloneAny(aiRef)) // 使用 CloneAny 消除了错误

两位好。虽然没有解决方案,但想分享一个想法:

如何声明一个定义,要求子结构体拥有一个返回子类型的 Clone 方法

你是否可能过于强调强制结构体执行某些操作,而不是限制操作只接收特定类型?

换句话说,与其强制子结构体拥有 clone 方法,为什么不限制自己,要求某些操作接受 Cloner[T] 类型?

func SomethingWithClone[T Cloner[T]](c T) T {
	// ...
	return c.Clone()
}

强制类型实现某些功能是我在 Scala 和 Java 这类语言中的思维方式,但使用 Go 的继承机制时,我倾向于更多地关注“这个操作应该接受能够…的参数”。


也许这不可能实现?

我不知道你想做的是否可能实现,因为方法不能有类型参数,而接口是在方法中实现的。所以要求一个类型拥有 AI[int] 似乎(乍一看)是不可能的,因为方法没有类型参数。

在你分享的评论中,还有一点我认为可能是错误的(但语义上不完全确定):通过嵌入接口来实现 AI 接口,据我所知,除非你嵌入了一个已经实现该接口的结构体,否则接口不能通过嵌入来实现。在这种情况下,你直接嵌入了接口类型。

无论如何,这很有趣,我了解得还不够,我会去阅读关于泛型的内容,看看是否能在我脑海中点亮一盏灯。


补充说明:

我认为 CS 中的 Clone 方法:

func (cs CS) Clone() CS {
	return CS{
		AS: cs.Clone(), // 错误:无法将 cs.Clone()(CS 类型的值)用作结构体字面量中的 AS 类型
		c:  cs.c,
	}
}

应该是:

func (cs CS) Clone() CS {
	return CS{
		AS: cs.AS.Clone(),
		c:  cs.c,
	}
}

这样错误就会消失。

在Go中,使用泛型实现多态Clone()方法的关键是正确设计接口和实现关系。以下是修正后的代码:

package main

import "fmt"

type Cloner[T any] interface {
    Clone() T
}

type AI[T any] interface {
    Cloner[AI[T]]
}

// 基础实现
type BaseAI[T any] struct {
    value T
}

func (b *BaseAI[T]) Clone() AI[T] {
    return &BaseAI[T]{value: b.value}
}

// AS 实现
type AS struct {
    BaseAI[int]
    a int
}

func (as *AS) Clone() AI[int] {
    return &AS{
        BaseAI: BaseAI[int]{value: as.value},
        a:      as.a,
    }
}

// BS 实现
type BS struct {
    BaseAI[int]
    b string
}

func (bs *BS) Clone() AI[int] {
    return &BS{
        BaseAI: BaseAI[int]{value: bs.value},
        b:      bs.b,
    }
}

// CS 实现(嵌入AS)
type CS struct {
    AS
    c int
}

func (cs *CS) Clone() AI[int] {
    return &CS{
        AS: AS{
            BaseAI: BaseAI[int]{value: cs.value},
            a:      cs.a,
        },
        c: cs.c,
    }
}

func main() {
    var aiRef AI[int]

    aiRef = &AS{a: 10}
    clonedAS := aiRef.Clone()
    fmt.Printf("AS: %#v\n", clonedAS)

    aiRef = &BS{b: "hello"}
    clonedBS := aiRef.Clone()
    fmt.Printf("BS: %#v\n", clonedBS)

    aiRef = &CS{c: 10}
    clonedCS := aiRef.Clone()
    fmt.Printf("CS: %#v\n", clonedCS)
}

或者使用更简洁的方法,通过类型参数约束:

package main

import "fmt"

type Cloneable[T any] interface {
    Clone() T
}

type AI[T any] interface {
    Cloneable[AI[T]]
}

type AS struct {
    a int
}

func (as *AS) Clone() AI[int] {
    return &AS{a: as.a}
}

type BS struct {
    b string
}

func (bs *BS) Clone() AI[int] {
    return &BS{b: bs.b}
}

type CS struct {
    AS
    c int
}

func (cs *CS) Clone() AI[int] {
    return &CS{
        AS: AS{a: cs.a},
        c:  cs.c,
    }
}

func CloneAll[T AI[E], E any](items []T) []AI[E] {
    result := make([]AI[E], len(items))
    for i, item := range items {
        result[i] = item.Clone()
    }
    return result
}

func main() {
    items := []AI[int]{
        &AS{a: 10},
        &BS{b: "hello"},
        &CS{c: 20},
    }

    for _, item := range items {
        cloned := item.Clone()
        fmt.Printf("Cloned: %#v\n", cloned)
    }
}

对于需要返回具体类型的情况,可以使用类型断言:

func CloneToConcrete[T any](ai AI[int]) T {
    cloned := ai.Clone()
    return cloned.(T)
}

func main() {
    as := &AS{a: 10}
    clonedAS := CloneToConcrete[*AS](as)
    fmt.Printf("Concrete AS: %#v\n", clonedAS)
}

这些实现确保了类型安全,同时提供了多态的Clone()功能。

回到顶部