Почему в Go нет наследования? Его отсутствие - ошибка создателей языка?

3320
18 Августа 2025

Создатели Go (Пайк, Томпсон, Грибс) сознательно не добавили классическое наследование — и это не ошибка, а философия языка.

Почему в Go нет наследования

  1. Избежать избыточной сложности. В языках с классическим ООП (Java, C++, C#) наследование часто ведёт к запутанным иерархиям классов, где изменения в базовом классе ломают кучу кода.
  2. Сделать акцент на композиции. Вместо is-a (является) → Go предлагает has-a (содержит). Это проще для понимания и делает код гибче.
  3. Интерфейсы проще и мощнее. В Go нет явного объявления реализации интерфейса: если структура имеет нужные методы, она автоматически считается реализацией. Это называется структурная типизация.
  4. Прозрачность кода. Код читается плоско, без скрытой магии и сложных цепочек наследования.

А был ли минус?

  • Для разработчиков из классического ООП сначала непривычно: хочется extends и super.
  • Иногда нужно больше писать вручную, без автопереноса логики из базового класса.
  • Но это окупается: код проще сопровождать, нет проблем от глубоких иерархий.

Итог

Создатели Go считают, что наследование даёт больше проблем, чем пользы. Они сделали ставку на композицию и интерфейсы, которые в большинстве случаев гибче и безопаснее.

Пример без наледования

package main

import "fmt"

// Базовая структура
type Car struct {
    Brand string
    Speed int // км/ч
}

// Метод структуры Car
func (c Car) Drive() {
    fmt.Printf("%s едет со скоростью %d км/ч\n", c.Brand, c.Speed)
}

// Структура ActionCar "встраивает" Car
type ActionCar struct {
    Car
}

// Дополнительный метод для ActionCar
func (a ActionCar) Drift() {
    fmt.Printf("%s уходит в дрифт!\n", a.Brand)
}

func main() {
    myCar := ActionCar{
        Car: Car{Brand: "Nissan Skyline", Speed: 120},
    }

    // Методы Car доступны через ActionCar
    myCar.Drive()

    // Методы ActionCar тоже работают
    myCar.Drift()
}

поделиться в:
ruenkzzh