英文:
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 的值表示的无类型常量。
-
[]*Field
和[]ider
是否相同?
根据 https://golang.org/ref/spec#Type_identity 的说明,如果两个切片类型具有相同的元素类型,则它们是相同的。那么
*Field
和ider
是否相同?
上述来源告诉我们,命名类型和未命名类型始终不同。所以答案是不相同,因为
*Field
是未命名类型,而ider
是命名类型。 -
[]*Field
的基础类型是[]*Field
,[]ider
的基础类型是[]ider
,它们不相同,根据我们在问题1中的检查结果,这也不适用。请参阅 https://golang.org/ref/spec#Types -
不适用,因为
[]ider
不是接口类型,而是切片类型。请参阅 https://golang.org/ref/spec#Slice_types -
不适用,因为没有使用通道。
-
不适用,因为没有使用 nil。
-
不适用,因为没有使用常量。
综上所述:类型为 []*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.
-
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
andider
identical?
The above source tells us
> A named and an unnamed type are always different.So no and no, as
*Field
is unnamed andider
is named. -
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 -
is not applicable as []ider is not an interface type, but a slice type. Read here https://golang.org/ref/spec#Slice_types
-
also not applicable as there is no channel used
-
also not applicable as there is no nil used
-
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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论