在给定实现该接口的结构列表时如何使用该接口

问题描述 投票:0回答:1

当我们在 Go 中定义接口时,最好在辅助函数中使用该接口,这样我们就可以通用地处理该接口。这就像 Go 中的魅力一样。但是当我们有一片实现接口的结构时,使用起来似乎非常麻烦。

公开接口的示例包:

package tryshit

import "fmt"

type HelloAble interface {
    Hello()
}

type Foo struct {
    Name string
}

func (receiver *Foo) Hello() {
    fmt.Println("Hello: " + receiver.Name)
}

type Bar struct {
    Alias string
}

func (receiver *Bar) Hello() {
    fmt.Println("Hello: " + receiver.Alias)
}

func ConsumeInterface(helloAble HelloAble) {
    helloAble.Hello()
}

func ConsumeInterfaces[T HelloAble](helloAbles []T) {
    for _, h := range helloAbles {
        h.Hello()
    }
}

我们现在可以这样运行:

package main

import (
    "tryShit/pkg/tryshit"
)

func main() {

    foo := &tryshit.Foo{
        Name: "foo",
    }
    bar := &tryshit.Bar{
        Alias: "bar",
    }

    // Works straight forward and like a charm
    tryshit.ConsumeInterface(foo)
    tryshit.ConsumeInterface(bar)

    // This on the other hand requires `foos` to be a pointer slice 
    // otherwise calling `tryshit.ConsumeInterfaces` won't work.
    // Or we need to set the receiver on Foo to a value instead of a pointer
    foos := []*tryshit.Foo{
        {Name: "Foo1"},
        {Name: "Foo2"},
        {Name: "Foo3"},
    }

    tryshit.ConsumeInterfaces(foos)
}

https://go.dev/play/p/vmQSc3w4qsT

我的问题是我有一个已经定义且无法更改的结构。我收到的切片是带有值的切片,而不是带有指针的切片。为了使这段代码工作,我必须做类似的事情:

var foosPointerSlice []*HelloAble
copier.Copy(&b.foos, &foosPointerSlice)
tryshit.ConsumeInterfaces(foosPointerSlice)

我在想:如果这是解决这个问题的唯一方法,为什么还要编写一个辅助函数,同时在每个需要辅助函数的地方循环,就像使用辅助函数一样麻烦:

for _, foo := range foos {
    tryshit.ConsumeInterface(&foo)
}

有没有办法处理这个惯用且干净的?

go generics interface slice
1个回答
0
投票

您需要使指针接收器成为显式约束:

type HelloAblePtr[T any] interface {
    HelloAble
    *T
}

*Foo
满足
HelloAblePtr[Foo]
并且
*Bar
满足
HelloAblePtr[Bar]
,所以你可以将
ConsumeInterfaces
定义为:

func ConsumeInterfaces[T any, HA HelloAblePtr[T]](helloAbles []T) {
    for _, h := range helloAbles {
        (HA)(&h).Hello()
    }
}

去游乐场:https://go.dev/play/p/i0f5h5g-v6S

© www.soinside.com 2019 - 2024. All rights reserved.