Slice of a specific interface in Go

huangapple go评论79阅读模式
英文:

Slice of a specific interface in Go

问题

我想创建一个函数,该函数使用接口的切片。

例如,我有一个接口ider,它包装了一个ID() string函数。然后我有一个类型(Field),它实现了ider接口。现在我有不同的对象,它们的参数是ider的切片。

在我的函数内部,我期望一个ider的切片([]ider)。这个函数应该被实现了ider接口的不同类型使用。

这很难描述。所以这里有一个完整的示例,它输出以下错误:

无法将myObj.Fields(类型为[]*Field)作为参数传递给inSlice中的类型[]ider

type ider interface {
	ID() string
}

type Field struct {
	Name string
}

// 实现ider接口
func (f *Field) ID() string {
	return f.Name
}

type MyObject struct {
	Fields []*Field
}

// 使用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"))
}

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

英文:

I want to create a function, which uses a slice of an interface.

For example I have an interface ider which wraps one ID() string function. Then I have a type (Field), which implements the ider interface. Now I have different objects, which have slice of ider as parameter.

Inside my function I expect a slice of ider ([]ider). That function should be used by different types, which are implementing the ider.

This is hard to describe. So here is a complete example, which outputs the following error:

> cannot use myObj.Fields (type []*Field) as type []ider in argument to inSlice

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

I already searched for answers, but I did just found solutions for empty interfaces and not for specific ones.

答案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 的表达式。

英文:

As one can read in https://golang.org/ref/spec#Calls
> Except for one special case, arguments must be single-valued expressions assignable to the parameter types of F and are evaluated before the function is called.

So in the above code myObj.Fields is of type []*Field which needs to be assignable to []ider for the code to compile. Let's check wether that is the case. As one can read in https://golang.org/ref/spec#Assignability

> A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:
>
> - x's type is identical to T.
> - x's type V and T have identical underlying types and at least one of V or T is not a named type.
> - T is an interface type and x implements T.
> - x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type.
> - x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
> - x is an untyped constant representable by a value of type T.

  1. Are []*Field and []ider identical?
    https://golang.org/ref/spec#Type_identity tells us
    > Two slice types are identical if they have identical element types.

    So are *Field and ider identical?
    The above source tells us
    > A named and an unnamed type are always different.

    So no and no, as *Field is unnamed and ider is named.

  2. The underlying type of []*Field is []*Field and the underlying type of []ider is []ider, and those are not identical, as we checked in 1. so this is also not applicable. Read here https://golang.org/ref/spec#Types

  3. is not applicable as []ider is not an interface type, but a slice type. Read here https://golang.org/ref/spec#Slice_types

  4. also not applicable as there is no channel used

  5. also not applicable as there is no nil used

  6. also not applicable as there is no constant used.

So summing up: A value of type []*Field is not assignable to []ider and therefore we can't use an expression of type []*Field in a parameter position
of a function call with parameter type []ider.

huangapple
  • 本文由 发表于 2017年4月12日 18:06:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/43366452.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定