Модульні уроки (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. Це шлях Go
створення поліморфізму: жодних ієрархій, лише можливості.
Порожній інтерфейс
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().
Показати підказку
Синтаксис: `тип Назва інтерфейсу { Метод (аргументи) повернення }`.
Рішення доступне після 3 спроб
Реалізуйте Greeter на новому типі Robot із рядком ID поля; метод повертає 'bip ' + ID.
Показати підказку
Ніяких `реалізацій`: просто визначте метод із правильною сигнатурою.
Рішення доступне після 3 спроб
Як оголосити, що тип P реалізує інтерфейс Greeter?
type P struct{}
// ?Підведення підсумків
- Інтерфейс = набір сигнатур методу; ні
implements. - Неявна реалізація: просто мати методи з правильною сигнатурою.
- Ідіоматичні: малі інтерфейси (1–2 методи), імена в
-er. interface{}/any: приймає будь-яке значення, втрачає безпеку типу.- Набір методів: приймач вказівника → тільки
*Tзадовольняє інтерфейс. — Поліморфізм Go: параметри типу інтерфейсу, відсутність ієрархій.