在Go语言中获取特定接口的子集

3
我想创建一个函数,该函数使用接口的切片。
例如,我有一个接口 `ider` 包装了一个 `ID() string` 函数。 然后我有一个类型(`Field`),它实现了 `ider` 接口。 现在我有不同的对象,它们将 `ider` 的切片作为参数。
在我的功能内部,我期望一个 `ider` 切片(`[]ider`)。 该函数应由实现 `ider` 的不同类型使用。
这很难描述。 因此,以下是一个完整的示例,输出以下错误:
"无法将 myObj.Fields (类型 []*Field) 用作 inSlice 参数中的类型 []ider"
type ider interface {
    ID() string
}

type Field struct {
    Name string
}

// Implements ider interface
func (f *Field) ID() string {
    return f.Name
}

type MyObject struct {
    Fields []*Field
}

// uses slice of ider
func inSlice(idSlice []ider, s string) bool {
    for _, v := range idSlice {
        if s == v.ID() {
            return true
        }
    }
    return false
}

func main() {
    fields := []*Field{
        &Field{"Field1"},
    }
    myObj := MyObject{
        Fields: fields,
    }
    fmt.Println(inSlice(myObj.Fields, "Field1"))
}

我已经搜索了答案,但只找到了空接口的解决方案,而没有针对特定类型的解决方案。

https://play.golang.org/p/p8PPH51vxP


可以使用idler接口创建“fields”变量,例如: fields:= []ider{&Field{"Field1"}}。它可以在您的Go Playground链接上运行。 - mgagnon
@mgagnon没错,那个方法可行。我刚刚编辑了问题,因为我的问题嵌套在另一个类型中。 - apxp
1
从Tim Cooper的链接中,有一个参考:https://github.com/golang/go/wiki/InterfaceSlice 我想这会对你有所帮助。 - mgagnon
谢谢。那个链接很有帮助。 - apxp
1个回答

3
https://golang.org/ref/spec#Calls所述,除了一个特殊情况外,参数必须是单值表达式,可分配给F的参数类型,并在调用函数之前进行评估。
因此,在上面的代码中,myObj.Fields[]*Field类型,需要可分配给[]ider才能编译通过。让我们检查一下是否满足此要求。如https://golang.org/ref/spec#Assignability所述,
一个值x可以以以下任意一种情况分配给类型T的变量("x可分配给T"): - x的类型与T相同。 - x的类型V和T具有相同的基础类型,并且V或T中至少有一个不是命名类型。 - T是接口类型,x实现了T。 - x是双向通道值,T是通道类型,x的类型V和T具有相同的元素类型,并且V或T中至少有一个不是命名类型。 - x是预声明标识符nil,T是指针、函数、切片、映射、通道或接口类型。 - x是可由T类型的值表示的未命名常量。
  1. []*Field[]ider是相同的吗?https://golang.org/ref/spec#Type_identity告诉我们:

    如果它们具有相同的元素类型,则两个切片类型是相同的。

    那么*Fieldider是相同的吗?上面的来源告诉我们:

    命名类型和未命名类型始终不同。

    所以答案是否定的,因为*Field是未命名的,而ider是命名的。

  2. []*Field的基础类型是[]*Field[]ider的基础类型是[]ider,并且它们不相同,如1中所检查的。因此这也不适用。请阅读https://golang.org/ref/spec#Types

  3. 不适用,因为[]ider不是接口类型,而是切片类型。请阅读https://golang.org/ref/spec#Slice_types

  4. 不适用,因为没有使用通道

  5. 不适用,因为没有使用nil

  6. 不适用,因为没有使用常量。

总而言之:类型为[]*Field的值不能赋值给[]ider,因此我们无法在参数类型为[]ider的函数调用的参数位置中使用类型为[]*Field的表达式。


在 Go 中,通常会这样做:var asIder []ider; for _, v := range myObj.Fields { asIder = append(asIder, v) }; inSlice(asIder, "Field1") 或者将转换封装在一个函数中。 - typetetris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接