Перейти к основному содержимому
Модуль 6 · Урок 1 из 526/50 в курсе~12 min
Уроки модуля (1/5)

Интерфейсы: определение поведения

Интерфейс в Go — это набор сигнатур методов. Значение реализует интерфейс, если у него есть все эти методы — нет implements, нет extends, нет явной регистрации. Это модель, часто называемая «структурной типизацией» или «статической утиной типизацией»: компилятор проверяет соответствие во время компиляции, но на основе форме, а не по декларациям.

Объявление интерфейса

Go
type Greeter interface {
    Greet() string
}

Соглашение: имена, заканчивающиеся на -er для интерфейсов с одним методом. (Reader, Writer, Stringer, Closer). Маленькие интерфейсы (1–2 метода) являются идиоматическими: стандартная библиотека полна крошечные интерфейсы, которые объединяются (io.ReadWriter, io.ReadCloser, …).

Неявная реализация

Go
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())

Нет ключевого слова. Если тип имеет методы, его можно присвоить переменная этого типа интерфейса. Вот и все.

Полиморфизм через интерфейс

Go
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.

Практический результат:

Go
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

Если у метода есть приемник указателя, вы должны присвоить указатель переменная интерфейса.

Попробуйте это

Упражнение#go.m6.l1.e1
Попыток: 0Загрузка…

Определите интерфейс Greeter с помощью одной строки метода Greet().

Загрузка редактора…
Показать подсказку

Синтаксис: `type Name Interface { Method(args) return }`.

Решение доступно после 3 попыток

Упражнение#go.m6.l1.e2
Попыток: 0Загрузка…

Внедрите Greeter в роботе нового типа со строкой идентификатора поля; метод возвращает «bip» + ID.

Загрузка редактора…
Показать подсказку

Никаких «инструментов»: просто определите метод с правильной сигнатурой.

Решение доступно после 3 попыток

Quiz#go.m6.l1.e3
Готово

Как объявить, что тип P реализует интерфейс Greeter?

Go
type P struct{}
// ?
Варианты ответа

Резюме

  • Интерфейс = набор сигнатур методов; нет implements.
  • Неявная реализация: просто используйте методы с правильной сигнатурой.
  • Идиоматика: маленькие интерфейсы (1–2 метода), имена в -er.
  • interface{} / any: принимает любое значение, теряет типобезопасность.
  • Набор методов: приемник указателя → только *T удовлетворяет интерфейсу. — Полиморфизм Go: параметры, типизированные интерфейсом, без иерархий.