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.
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
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.
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
.