Реализация интерфейса

Реализация интерфейса в Go - это процесс, при котором конкретный тип (структура или пользовательский тип) удовлетворяет требованиям интерфейса. Для реализации интерфейса тип должен определить все методы, объявленные в интерфейсе. В Go реализация интерфейса происходит неявно - нет необходимости явно указывать, что тип реализует интерфейс. Это делает код более гибким и упрощает тестирование.

Синтаксис реализации интерфейса

gotype InterfaceName interface {
  MethodName(param type) returnType
}

type MyType struct {
  // поля структуры
}

func (m MyType) MethodName(param type) returnType {
  // реализация метода
  return result
}

Пример базовой реализации интерфейса

Давайте создадим интерфейс 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("%s (%d years old)", p.Name, p.Age)
}

func main() {
  person := Person{Name: "Alice", Age: 30}
  var s Stringer = person
  res := s.String()
  fmt.Println(res)
}

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

go"Alice (30 years old)"

Пример реализации с указателем на структуру

Методы могут быть реализованы как с получателем-значением, так и с получателем-указателем. Рассмотрим пример с получателем-указателем, который позволяет изменять состояние структуры:

gopackage main

import "fmt"

type Counter interface {
  Increment()
  Value() int
}

type MyCounter struct {
  count int
}

func (c *MyCounter) Increment() {
  c.count++
}

func (c *MyCounter) Value() int {
  return c.count
}

func main() {
  counter := &MyCounter{count: 0}
  var c Counter = counter
  c.Increment()
  c.Increment()
  res := c.Value()
  fmt.Println(res)
}

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

go2

Пример реализации нескольких интерфейсов

Один тип может реализовывать несколько интерфейсов. Рассмотрим структуру, которая реализует два интерфейса - Reader и Writer:

gopackage main

import "fmt"

type Reader interface {
  Read() string
}

type Writer interface {
  Write(data string)
}

type DataStore struct {
  data string
}

func (d *DataStore) Read() string {
  return d.data
}

func (d *DataStore) Write(data string) {
  d.data = data
}

func main() {
  store := &DataStore{data: "initial"}
  var r Reader = store
  var w Writer = store
  
  w.Write("new data")
  res := r.Read()
  fmt.Println(res)
}

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

go"new data"

Пример неявной реализации интерфейса

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

gopackage main

import "fmt"

type Shape interface {
  Area() float64
}

type Rectangle struct {
  Width  float64
  Height float64
}

func (r Rectangle) Area() float64 {
  return r.Width * r.Height
}

type Circle struct {
  Radius float64
}

func (c Circle) Area() float64 {
  return 3.14 * c.Radius * c.Radius
}

func printArea(s Shape) {
  res := s.Area()
  fmt.Println(res)
}

func main() {
  rect := Rectangle{Width: 5, Height: 10}
  circle := Circle{Radius: 3}
  
  printArea(rect)
  printArea(circle)
}

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

go50
28.26

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

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