I have a struct Foo with a method print:
type Foo struct {
Bar string
}
func (f Foo) print() {
fmt.Println(f.Bar)
}
If I want to print for a slice of Foo, the canonical way perhaps is to write a for loop, and have a function to encapsulate it:
func printFoos(fs []Foo) {
for _, f := range fs {
f.print()
}
}
printFoos([]Foo{})
Coming from an OOP background, I find this approach a bit unappealing.
What I would like to do is to associate printFoos with []Foo:
// Invalid Go code
func (fs []Foo) print() {
for _, f := range fs {
f.print()
}
}
The above doesn't work because in Go, an unnamed type can't be used as the method receiver, as discussed in this Google Group thread.
To circumvent it, it is possible to write:
type Foos []Foo
func (fs Foos) print() {
for _, f := range fs {
f.print()
}
}
To use it, I have to explicitly declare the type as Foos, so still I can't use print on []Foo
fs := []Foo{}
fs.print() // error
var fss Foos = fs
fss.print()
What I'm confused about is, in the above code, fss and fs are clearly of the same type, as I can assign fs to fss without error. However, we can't simply use fs.print() and let Go be smart about the conversion.
Why is this the case?
The full code can be found on playground.
What I'm confused about is, in the above code,
fssandfsare clearly of the same type, as I can assignfstofsswithout error.
You jump to the wrong conclusion. Having the same type is not a must have requirement for assignability.
fss has type Foos, and fs has type []Foo, an unnamed slice type. It's true that they have the same underlying type, that's why you can assign fs to fss, covered in this assignability rule:
A value
xis assignable to a variable of typeT("xis assignable toT") if one of the following conditions applies:
- ...
x's typeVandThave identical underlying types and at least one ofVorTis not a defined type.
Methods are bound to concrete types. So the Foos.print() method is not available for a value of a different type, including []Foo.
But you don't need to create a variable just to call that method, you may simply use a type conversion:
Foos(fs).print()
This conversion does not change the memory layout, just the type, so it's safe and efficient. We used it only to gain access to a method of a type with identical underlying type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With