Уроки модуля (1/5)
Интерфейсы: определение поведения
Интерфейс в Go — это набор сигнатур методов. Значение
реализует интерфейс, если у него есть все эти методы — нет
implements, нет extends, нет явной регистрации. Это
модель, часто называемая «структурной типизацией» или «статической утиной типизацией»:
компилятор проверяет соответствие во время компиляции, но на основе
форме, а не по декларациям.
Объявление интерфейса
type Greeter interface {
Greet() string
}Соглашение: имена, заканчивающиеся на -er для интерфейсов с одним методом.
(Reader, Writer, Stringer, Closer). Маленькие интерфейсы
(1–2 метода) являются идиоматическими: стандартная библиотека полна
крошечные интерфейсы, которые объединяются (io.ReadWriter,
io.ReadCloser, …).
Неявная реализация
type Person struct{ Name string }
func (p Person) Greet() string {
return "ciao " + p.Name
}
// Person satisfies Greeter because it has the required method.
var s Greeter = Person{Name: "Ada"}
fmt.Println(s.Greet())Нет ключевого слова. Если тип имеет методы, его можно присвоить переменная этого типа интерфейса. Вот и все.
Полиморфизм через интерфейс
type Robot struct{ ID string }
func (r Robot) Greet() string { return "bip " + r.ID }
func greet(s Greeter) {
fmt.Println(s.Greet())
}
greet(Person{Name: "Ada"})
greet(Robot{ID: "R2"})greet принимает любой тип, удовлетворяющий Greeter. Это путь вперед
полиморфизма: никаких иерархий, только возможности.
Пустой интерфейс
var x interface{} = 42
var y any = "ciao" // any is the built-in alias of interface{}interface{} (или any, начиная с Go 1.18) не требует никаких методов, поэтому любые
стоимость его удовлетворяет. Полезно для общих контейнеров, но для извлечения
конкретное значение, которое вам нужно, утверждение типа или переключение типа
(следующие уроки).
Набор методов: значение и приемник указателя (предварительная версия)
Напомним из Модуля 5:
- Методы с приемником значений входят в набор методов как
T, так и*T. - Методы с приемником указателя находятся ТОЛЬКО в наборе методов
*T.
Практический результат:
type Counter struct{ N int }
func (c *Counter) Inc() { c.N++ }
type Incrementer interface { Inc() }
var i Incrementer = &Counter{} // OK: *Counter has Inc()
// var j Incrementer = Counter{} // ERROR: Counter (value) does NOTЕсли у метода есть приемник указателя, вы должны присвоить указатель переменная интерфейса.
Попробуйте это
Определите интерфейс Greeter с помощью одной строки метода Greet().
Показать подсказку
Синтаксис: `type Name Interface { Method(args) return }`.
Решение доступно после 3 попыток
Внедрите Greeter в роботе нового типа со строкой идентификатора поля; метод возвращает «bip» + ID.
Показать подсказку
Никаких «инструментов»: просто определите метод с правильной сигнатурой.
Решение доступно после 3 попыток
Как объявить, что тип P реализует интерфейс Greeter?
type P struct{}
// ?Резюме
- Интерфейс = набор сигнатур методов; нет
implements. - Неявная реализация: просто используйте методы с правильной сигнатурой.
- Идиоматика: маленькие интерфейсы (1–2 метода), имена в
-er. interface{}/any: принимает любое значение, теряет типобезопасность.- Набор методов: приемник указателя → только
*Tудовлетворяет интерфейсу. — Полиморфизм Go: параметры, типизированные интерфейсом, без иерархий.