Интерфейс с методами

Интерфейс с методами в Go определяет контракт, который должен реализовать тип. В интерфейсе перечисляются сигнатуры методов без их реализации. Тип удовлетворяет интерфейсу, если он реализует все методы с такими же именами, параметрами и возвращаемыми значениями. Это основа полиморфизма в Go.

Синтаксис

gotype InterfaceName interface {
  MethodName(param1 Type1, param2 Type2) ReturnType
  AnotherMethod(param Type) (ReturnType1, ReturnType2)
}

Для объявления интерфейса используется ключевое слово interface, в фигурных скобках перечисляются методы. Каждый метод описывается своим именем, параметрами и возвращаемыми значениями.

Пример

Давайте объявим интерфейс Shape с методами Area и Perimeter, а затем реализуем его для структуры Rectangle:

gopackage main

import "fmt"

type Shape interface {
  Area() float64
  Perimeter() float64
}

type Rectangle struct {
  width  float64
  height float64
}

func (r Rectangle) Area() float64 {
  return r.width * r.height
}

func (r Rectangle) Perimeter() float64 {
  return 2 * (r.width + r.height)
}

func main() {
  rect := Rectangle{width: 5, height: 3}
  var s Shape = rect
  fmt.Println("Area:", s.Area())
  fmt.Println("Perimeter:", s.Perimeter())
}

Результат выполнения кода:

go"Area: 15"
"Perimeter: 16"

Структура Rectangle автоматически удовлетворяет интерфейсу Shape, так как реализует оба метода. Переменная типа интерфейса может хранить значение любого типа, реализующего этот интерфейс.

Пример

Создадим интерфейс Stringer с методом String и реализуем его для структуры Person:

gopackage main

import "fmt"

type Stringer interface {
  String() string
}

type Person struct {
  name string
  age  int
}

func (p Person) String() string {
  return fmt.Sprintf("Name: %s, Age: %d", p.name, p.age)
}

func main() {
  p := Person{name: "Alice", age: 30}
  var s Stringer = p
  fmt.Println(s.String())
}

Результат выполнения кода:

go"Name: Alice, Age: 30"

Метод String возвращает строковое представление объекта. Этот интерфейс широко используется в стандартной библиотеке, например, в пакете fmt для форматированного вывода.

Пример

Интерфейсы могут содержать несколько методов с разными параметрами. Рассмотрим интерфейс Calculator для математических операций:

gopackage main

import "fmt"

type Calculator interface {
  Add(a, b int) int
  Subtract(a, b int) int
  Multiply(a, b int) int
}

type BasicCalc struct{}

func (c BasicCalc) Add(a, b int) int {
  return a + b
}

func (c BasicCalc) Subtract(a, b int) int {
  return a - b
}

func (c BasicCalc) Multiply(a, b int) int {
  return a * b
}

func main() {
  calc := BasicCalc{}
  var c Calculator = calc
  fmt.Println("Add:", c.Add(10, 5))
  fmt.Println("Subtract:", c.Subtract(10, 5))
  fmt.Println("Multiply:", c.Multiply(10, 5))
}

Результат выполнения кода:

go"Add: 15"
"Subtract: 5"
"Multiply: 50"

Тип BasicCalc реализует все три метода интерфейса Calculator и может использоваться везде, где требуется этот интерфейс.

Смотрите также

  • объявление интерфейса interface,
    которое содержит общую информацию об интерфейсах
  • неявную реализацию интерфейсов implicit-implementation,
    которая позволяет типам автоматически удовлетворять интерфейсам
  • встраивание интерфейсов embedding,
    которое позволяет комбинировать интерфейсы
  • интерфейс error,
    который является стандартным интерфейсом для обработки ошибок