Golang泛型 - 是否有类似Rust中"Self"类型的等价实现

Golang泛型 - 是否有类似Rust中"Self"类型的等价实现 Rust 泛型有一个“Self”,它是实例化泛型类型的具体类型。Go 中有等效的概念吗?

具体来说,这样我就可以让 Clone() 返回一个 Self。然后我可以有一个实现 Clone 接口的泛型结构体。

类似这样:

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

type Parent[T any] struct {
    parentAttr T
    Cloner[Self] 
}

func (p Parent[T]) Clone() Parent[T] {  return a clone of the parent obj }

type Child[T any] struct {
   Parent[T]
   childAttr string
}

func (c Child[T]) Clone() Child[T] { return a clone of the child obj }


更多关于Golang泛型 - 是否有类似Rust中"Self"类型的等价实现的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

谢谢。

更多关于Golang泛型 - 是否有类似Rust中"Self"类型的等价实现的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


@guettli

为什么不用 cloned := s.Clone() 并让每个 Clone 方法返回特定的类型?

因为那样 Clone 方法将不会实现 Cloner 接口。

如果你的场景不需要 Cloner 接口,你的解决方案当然完全没问题。始终使用尽可能简单的解决方案!

嗨,克里斯托夫,

感谢你的博客文章。

你在文章中使用了这段代码片段:

cloned := CloneAny(s)
if cs, ok := cloned.(CloneableSlice); ok {
    fmt.Println(cs[3])
}

为什么不使用 cloned := s.Clone() 并让每个 Clone 方法都返回特定的类型呢?

这样你就不需要类型断言了。

你好,

确实,接口方法的参数可以引用接口类型本身——详情请参阅这篇文章:

如何使用泛型创建自引用接口

简要说明:

第一步Cloner 接口保持不变。

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

C 目前还没有任何限制,但第二步会处理这个问题。

第二步:一个克隆任意类型的函数使用 Cloner[T] 作为类型约束:

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

然后,对于任何其类型实现了 Cloner 的变量 s,你都可以简单地调用

CloneAny(s)

来克隆 s

Go Playground 链接

这篇博客文章更详细地解释了这个解决方案。

在Go语言中,没有与Rust的Self类型完全等价的实现。Go的泛型系统相对较新,设计上更注重简单性和明确性,因此不支持这种形式的自我类型引用。

不过,你可以通过以下方式实现类似的功能:

package main

import "fmt"

// 定义一个泛型克隆接口
type Cloner[T any] interface {
    Clone() T
}

// 父结构体
type Parent[T any] struct {
    parentAttr T
}

// 父结构体的Clone方法
func (p Parent[T]) Clone() Parent[T] {
    return Parent[T]{parentAttr: p.parentAttr}
}

// 子结构体
type Child[T any] struct {
    Parent[T]
    childAttr string
}

// 子结构体的Clone方法
func (c Child[T]) Clone() Child[T] {
    return Child[T]{
        Parent:    c.Parent.Clone(),
        childAttr: c.childAttr,
    }
}

// 使用接口约束的泛型函数
func CloneAndPrint[T Cloner[T]](original T) {
    cloned := original.Clone()
    fmt.Printf("Original: %+v\n", original)
    fmt.Printf("Cloned: %+v\n", cloned)
}

func main() {
    // 创建Parent实例
    parent := Parent[int]{parentAttr: 42}
    clonedParent := parent.Clone()
    fmt.Printf("Parent cloned: %+v\n", clonedParent)

    // 创建Child实例
    child := Child[string]{
        Parent:    Parent[string]{parentAttr: "parent value"},
        childAttr: "child value",
    }
    clonedChild := child.Clone()
    fmt.Printf("Child cloned: %+v\n", clonedChild)

    // 使用泛型函数
    CloneAndPrint(parent)
    CloneAndPrint(child)
}

另一种方法是使用类型参数约束:

package main

import "fmt"

// 定义可克隆的接口
type Cloneable interface {
    Clone() Cloneable
}

// 具体实现
type MyStruct struct {
    Value int
}

func (m MyStruct) Clone() Cloneable {
    return MyStruct{Value: m.Value}
}

// 泛型包装器
type Container[T Cloneable] struct {
    item T
}

func (c Container[T]) CloneContainer() Container[T] {
    return Container[T]{item: c.item.Clone().(T)}
}

func main() {
    original := Container[MyStruct]{item: MyStruct{Value: 100}}
    cloned := original.CloneContainer()
    fmt.Printf("Original: %+v\n", original)
    fmt.Printf("Cloned: %+v\n", cloned)
}

需要注意的是,Go的泛型设计哲学与Rust不同。Go更倾向于通过接口和明确的类型转换来实现多态,而不是通过复杂的类型系统特性。虽然不能完全复制Rust的Self行为,但通过上述模式可以在Go中实现类似的功能。

回到顶部