Я играл с интерфейсами и структурами в Голанге, пытаясь реализовать «наследование», но я уверен, что сделал это неправильно. Это было бы проще объяснить на примере.
Я хочу создавать структуры из разных живых существ. Я хочу, чтобы у них был метод GetName ():
type LivingThingProvider interface {
GetName() string
}
Теперь все они должны иметь имена и дни рождения. Для этого я создаю структуру и встраиваю в нее интерфейс:
type LivingThing struct {
birthday string
name string
LivingThingProvider
}
Я хочу добавить пару методов, которые были бы одинаковыми для всех живых существ:
func (this *LivingThing) Initialize() {
this.birthday = time.Now().Format("02.01.2006")
}
func (this LivingThing) GetBirthday() string {
return this.birthday
}
Теперь вот структуры, которые должны «реализовать» LivingThing:
type Frog struct {
insectsEaten int
LivingThing
}
func (this Frog) GetName() string {
return fmt.Sprintf("%s-the-Frog-proud-eater-of-%d-insects", this.name, this.insectsEaten)
}
type RobotMan struct {
LivingThing
}
func (this RobotMan) GetName() string {
h := sha256.New()
h.Write([]byte(this.birthday))
return fmt.Sprintf("%s-%X", this.name, h.Sum(nil))
}
В основной функции я создаю и добавляю лягушку и робота к срезу, после чего я зацикливаюсь на нем:
func main() {
fr := Frog{}
fr.name = "Dizzy"
fr.insectsEaten = 586
fr.LivingThingProvider = fr
rm := RobotMan{}
rm.name = "Bender"
rm.LivingThingProvider = rm
fr.Initialize()
rm.Initialize()
entities := []LivingThing{fr.LivingThing, rm.LivingThing}
for _, ent := range entities {
fmt.Printf("Hi, I am %s!\n", ent.GetName())
fmt.Printf("I was born on the %s.\n", ent.GetBirthday())
}
}
Все работает как положено, но если я удалю метод GetName () из структуры Frog или RobotMan, он будет компилироваться и паниковать после запуска:
panic: runtime error: invalid memory address or nil pointer dereference
Вот ссылка на игровую площадку: https://play.golang.org/p/h2VgvdcXJQA
У меня следующие вопросы:
1. Что я сделал "грязным" в терминах го? Если да, то как это сделать правильно?
1a. В частности, хорошо ли назначать саму структуру встроенному полю интерфейса (fr.LivingThingProvider = fr)?
2. Почему компилятор Go не проверяет, реализуют ли Frog и RobotMan интерфейс LivingThingProvider?
Заранее большое спасибо!