Как «наследовать метод» golang?

Сделал простой код из двух структур:
package main

import "fmt"

type Animal struct {
  Name string
}

type Rabbit struct {
  Animal
}

//Метод Walk у каждого свой
func (this *Animal) Walk() *Animal{
  fmt.Println("I walk", this.Name)
  return this
}

//Метод Say один
func (this *Animal) Say() *Animal{
  fmt.Println("Im Animal and my Name is", this.Name)
  return this
}

//Метод Walk изменяется для Rabbit и работает корректно
func (this *Rabbit) Walk() *Rabbit{
  this.Animal.Walk()
  fmt.Println("...and Jump")
  return this
}

func main() {

  animal := Animal{ Name: "Зверь" }
  animal.Walk().Say().Walk()

  fmt.Println("\n---------------------\n")

  rabbit := Rabbit{ }
  rabbit.Name = "Кроль"
  rabbit.Walk().Say().Walk() // Say возвращает ссылку на Animal, поэтому второй вызов Walk срабатывает от Animal (без jump) - как сделать правильно?
  
}

запустить можно тут: play.golang.org/p/RricqVcYx7

Проблема в том, что при чейнинге (rabbit) после "родительского" метода Say, который возвращает указатель на Animal, следующий метод вызывается уже для Animal, а не Rabbit. Понимаю, что в GO нету наследования, но не понимаю, как решать типичные задачи.

Копипастить каждый раз свой метод с возвращением нужного указателя заного? Вообще избегать наследования?
Или как то по другому это делается?
Покажите пожалуйста, как в стиле GO.
  • Вопрос задан
  • 5313 просмотров
Решения вопроса 1
@s_kozlov
package main


import "fmt"

type AnimalIntf interface {
	Walk() AnimalIntf
	Say() AnimalIntf
}

type Animal struct {
	animal    AnimalIntf
	Name string
}

type Rabbit struct {
	Animal
}


// Animal
func NewAnimal(name string) *Animal {
	animal := new(Animal)
	animal.animal = animal
	animal.Name = name
	return animal
}

//Метод Walk у каждого свой
func (this *Animal) Walk() AnimalIntf {
	fmt.Println("I walk", this.Name)
	return this.animal
}

//Метод Say общий
func (this *Animal) Say() AnimalIntf {
	fmt.Println("Im Animal and my Name is", this.Name)
	return this.animal
}


// Rabbit
func NewRabbit(name string) *Rabbit {
	rabbit := new(Rabbit)
	rabbit.animal = rabbit
	rabbit.Name = name
	return rabbit
}

//Метод Walk изменяется для Rabbit и работает корректно
func (this *Rabbit) Walk() AnimalIntf {
	this.Animal.Walk()
	fmt.Println("...and Jump")
	return this.animal
}


func main() {

	animal := NewAnimal("Зверь")
	animal.Walk().Say().Walk()

	fmt.Println("\n---------------------\n")

	rabbit := NewRabbit("Кроль")
	rabbit.Walk().Say().Walk()

}

примерно так, как вариант
вывод:
I walk Зверь
Im Animal and my Name is Зверь
I walk Зверь

---------------------

I walk Кроль
...and Jump
Im Animal and my Name is Кроль
I walk Кроль
...and Jump
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
@mantyr
Пишу много Golang кода с удовольствием:)
То что вы сделали называется embed (встраивание). Можно отойти от него явно и не путаться.

type Animal struct {
  Name string
}

type Rabbit struct {
  Ani Animal
}

func (this *Rabbit) Walk() *Rabbit{
  this.Ani.Walk()
  fmt.Println("...and Jump")
  return this
}

func (this *Rabbit) Say() *Rabbit{
  this.Ani.Say()
  return this
}

Как по мне использовать наименование this вездк где это подразумевается в Golang не лучший выбор, так как усложняется визуальное разделение между разными типами объектов.

Так же можно не дублировть функции так:
rabbit := Rabbit{ }
  rabbit.Ani.Name = "Кроль"
  rabbit.Ani.Walk()
  rabbit.Ani.Say()
  rabbit.Ani.Walk()
Ответ написан
bitver
@bitver
Это называется late binding (позднее связывание) оно делается просто через reflection, но противоречит идее go.
stackoverflow.com/questions/10255926/go-reflection...
Ответ написан
Комментировать
Для этого в GO придуманы интерфейсы.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы