Интерфейсы
Интерфейсы Go реализуются неявно: тип подходит, если у него есть нужные методы.
Интерфейс — это набор сигнатур методов. Тип реализует интерфейс автоматически, если имеет все эти методы — никакого
implementsписать не нужно.
Неявная реализация — главная идея
В Java или C# вы пишете class Dog implements Animal. В Go такого нет. Интерфейс — это контракт «какие методы должны быть», а тип удовлетворяет ему просто фактом наличия этих методов. Это называется структурной типизацией или «утиной типизацией на этапе компиляции».
package main
import "fmt"
// интерфейс: контракт из одного метода
type Shape interface {
Area() float64
}
type Circle struct{ R float64 }
type Square struct{ Side float64 }
// Circle и Square нигде не пишут "implements Shape" —
// они реализуют его автоматически, просто имея метод Area.
func (c Circle) Area() float64 { return 3.14159 * c.R * c.R }
func (s Square) Area() float64 { return s.Side * s.Side }
func describe(sh Shape) {
fmt.Printf("площадь: %.2f\n", sh.Area())
}
func main() {
describe(Circle{R: 2})
describe(Square{Side: 3})
}Вывод:
площадь: 12.57 площадь: 9.00
Функция describe принимает любой Shape. И Circle, и Square подходят, потому что у них есть Area(). Добавите новый тип с Area() — он тоже заработает, не меняя describe.
Пустой интерфейс
Интерфейс без методов interface{} (с Go 1.18 есть псевдоним any) удовлетворяется любым типом. Это аналог Object в Java или any в TypeScript — переменная, способная хранить что угодно.
package main
import "fmt"
func main() {
var x any // то же, что interface{}
x = 42
fmt.Println(x)
x = "строка"
fmt.Println(x)
}Вывод:
42 строка
Type assertion: достаём конкретный тип
Когда значение лежит в интерфейсе, его конкретный тип «спрятан». Достать его обратно помогает type assertion с проверкой ok — она безопасна и не паникует, если тип не тот.
package main
import "fmt"
func main() {
var v any = "привет"
if s, ok := v.(string); ok {
fmt.Println("строка длиной", len(s))
}
if _, ok := v.(int); !ok {
fmt.Println("это не int")
}
}Вывод:
строка длиной 12 это не int
Для разбора по нескольким типам удобен switch v := x.(type) — это type switch, ветвление по динамическому типу значения.
Итог
- Интерфейс — набор методов; тип реализует его неявно, просто имея эти методы.
- Пустой интерфейс
any(interface{}) принимает значение любого типа. - Type assertion
v.(T)с проверкойokбезопасно достаёт конкретный тип.