Материал проходит вычитку — возможны неточности.
Урок 46 из 118

Method set и встраивание

Для потокового чтения Миша завёл новый тип FileStream и вложил в него Reader. Методы чтения появились у FileStream сами, без единой строчки кода. Аня на ревью напомнила: это композиция, а не наследование.

Главная мысль

набор методов указателя шире, чем у значения — от него зависит, какие интерфейсы тип удовлетворяет; а встраивание — это композиция, при которой методы и поля продвигаются наружу.

Method set

Набор методов типа определяет, какие интерфейсы он удовлетворяет. Формулируется просто:

  • методы типа T — все, у которых получатель T;
  • методы типа *T — методы с получателем T и методы с получателем *T.
type Greeter interface{ Greet() string }

type English struct{}

func (English) Greet() string { return "Hello" } // value-метод

var g  Greeter = English{}  // ок
var g2 Greeter = &English{} // тоже ок

Пока метод value-receiver, разницы нет. Стоит сделать его pointer-receiver — и English{} интерфейс уже не удовлетворит.

Встраивание

Поле без имени встраивает другой тип, и его методы и поля «продвигаются» наружу. Так в FileStream встроен Reader — весь набор методов чтения доступен бесплатно:

type FileStream struct {
    io.Reader // встроенный Reader — методы продвигаются наружу
    offset    int64
}

f, _ := os.Open("report.pdf")
fs := FileStream{Reader: f, offset: 0}
data, err := fs.Read(buf) // метод Read продвинут от встроенного io.Reader

Продвигаются и поля встроенной структуры:

type Meta struct {
    Name string
}

func (m Meta) DisplayName() string { return m.Name }

type FileStream struct {
    Meta
    Offset int64
}

fs := FileStream{Meta: Meta{Name: "report.pdf"}, Offset: 0}
fmt.Println(fs.Name)           // report.pdf — поле продвинуто
fmt.Println(fs.DisplayName())  // report.pdf — метод продвинут

Это не наследование

FileStream сам удовлетворяет всему, что умеет Meta. Но встраивание — композиция, а не наследование: Meta остаётся отдельным полем, FileStream не становится подтипом Meta, и методы Meta получают копию Meta, а не FileStream целиком. Попытка сделать из встраивания классическое наследование обычно заканчивается путаницей.

В следующем уроке

Вы узнаете:

  • как интерфейсы собираются из method set'ов
  • как решаются конфликты имён при встраивании двух типов
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

User встраивает Named, но имеет и собственное поле Name. Что вернёт u.DisplayName() и u.Name?

Вопрос 2 из 3

Встраивание по указателю *Named — какие методы продвинуты в method set значения User?

Вопрос 3 из 3

Чем method set значения отличается от method set указателя?

Итоги

Method set: у указателя — оба набора методов, у значения — только value-методы. Встраивание продвигает поля и методы, но это композиция.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки