Рассмотрим следующий пример кода на Go:
package main
import "fmt"
type animal interface {
makeSound()
}
type cat struct {}
type dog struct {}
func (c cat) makeSound() {
fmt.Println("meow")
}
func (d dog) makeSound() {
fmt.Println("woof")
}
func main() {
var cat1, dog1 animal = cat{}, dog{}
cat1.makeSound()
dog1.makeSound()
var cat2, dog2 animal = &cat{}, &dog{}
cat2.makeSound()
dog2.makeSound()
}
Этот код работает - программа гавкает и мяукает как по значению, так и по ссылке. Но давайте немного изменим код:
package main
import "fmt"
type animal interface {
makeSound()
}
type cat struct {}
type dog struct {}
func (c *cat) makeSound() {
fmt.Println("meow")
}
func (d *dog) makeSound() {
fmt.Println("woof")
}
func main() {
var cat1, dog1 animal = cat{}, dog{}
cat1.makeSound()
dog1.makeSound()
var cat2, dog2 animal = &cat{}, &dog{}
cat2.makeSound()
dog2.makeSound()
}
Теперь вызовы cat1.makeSound()
и dog1.makeSound()
не компилируются, выдавая ошибки вроде следующей:
.\test.go:21:6: cannot use cat{} (type cat) as type animal in assignment:
cat does not implement animal (makeSound method has pointer receiver)
При этом вызовы cat2.makeSound()
и dog2.makeSound()
продолжают работать.
Почему такое неконсистентное поведение и почему передача того, что в других языках называется this
или self
в Go не унифицирована? В отличии от других языков программист на Go должен думать не только о сигнатуре метода, но и о способе передачи аналога this
или self
.
Кстати, объявить одновременно два варианта метода нельзя. Например если написать вот так:
func (c *cat) makeSound() {
fmt.Println("meow")
}
func (c cat) makeSound() {
fmt.Println("meow")
}
Будет ошибка:
.\test.go:16:6: method redeclared: cat.makeSound
method(*cat) func()
method(cat) func()