Композиция против наследования с анонимной структурой

Я читал это слайд-шоу, в котором говорится:

var hits struct {
    sync.Mutex
    n int
}

hits.Lock()
hits.n++
hits.Unlock()

Как именно это работает? Похоже, что hits - это не состоит из мьютекс и целое число, а является мьютекс и целое число?

0
0
224
3

Ответы 3

Это называется встраиванием, hits состоит из sync.Mutex и int. Это должно быть правдой, поскольку в Go нет наследования. Это скорее отношения типа «имеет», чем «есть» между членами и структурой.

Прочтите здесь для более полного объяснения

Цитируется по ссылке

The methods of embedded types come along for free

Это означает, что вы можете обращаться к ним как к hits.Lock() вместо более длинной формы hits.Mutex.Lock(), потому что функция Lock() не является двусмысленной.

См. Представление Go-синтаксиса переменной hits:

fmt.Printf("%#v\n", &hits)
// &struct { sync.Mutex; n int }{Mutex:sync.Mutex{state:0, sema:0x0}, n:1}

Когда вы объявляете переменную, она просто инициализирует поля в структуре их значениями по умолчанию.

Кроме того, компилятор автоматически устанавливает имя встроенной структуры как поле. Таким образом, вы также можете получить доступ, например:

hits.Mutex.Lock()
hits.Mutex.Unlock()

И у вас есть доступ ко всем методам и экспортированным полям (если есть) sync.Mutex.

Это композиция. Используя анонимное поле (встроенное поле), содержащая структура будет иметь значение встроенного типа, и вы можете ссылаться на него: неквалифицированное имя типа действует как имя поля.

Таким образом, вы могли бы так же легко написать:

hits.Mutex.Lock()
hits.n++
hits.Mutex.Unlock()

Когда вы встраиваете тип, поля и методы встроенного типа получают продвинутый, поэтому вы можете ссылаться на них без указания имени поля (которое является именем встроенного типа), но это просто синтаксический сахар. Цитата из Спецификация: Селекторы:

A selector f may denote a field or method f of a type T, or it may refer to a field or method f of a nested embedded field of T.

Помимо продвижения поля / метода, набор методов типа внедрения также будет содержать набор методов встроенного типа. Цитата из Спецификация: Типы структур:

Given a struct type S and a defined typeT, promoted methods are included in the method set of the struct as follows:

  • If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.

  • If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.

Это не наследование в смысле ООП, а нечто подобное. Это удобно, когда вы хотите реализовать интерфейс: если вы встраиваете тип, который уже реализует интерфейс, то и ваш тип структуры будет. Вы также можете предоставить свою собственную реализацию некоторых методов, которая дает ощущение переопределения метода, но не следует забывать, что селекторы, которые обозначают методы встроенного типа, получат встроенное значение в качестве получателя (а не значение встроенного средства), и селекторы, которые обозначают ваши методы, определенные в типе структуры (которые могут или не могут «затенять» метод встроенного типа), получат значение структуры внедрения в качестве получателя.

Другие вопросы по теме