вторник, 15 января 2019 г.

Основы Go: интерфейсы

Тип интерфейс определяется набором сигнатур его методов.

Значение типа интерфейса может содержать любое значение, реализующее эти методы.

package main

import (
  "fmt"
  "math"
)

type Abser interface {
  Abs() float64
}

func main() {
  var a Abser
  f := MyFloat(-math.Sqrt2)
  v := Vertex{3, 4}

  a = f  // a MyFloat реализует Abser
  a = &v // a *Vertex реализует Abser

  fmt.Println(a.Abs())
}

type MyFloat float64

func (f MyFloat) Abs() float64 {
  if f < 0 {
    return float64(-f)
  }
  return float64(f)
}

type Vertex struct {
  X, Y float64
}

func (v *Vertex) Abs() float64 {
  return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

Вывод:

5

В следующем примере на строке 22 есть ошибка. Vertex (тип значения) не реализует интерфейс Abser, потому что метод Abs объявлен только для *Vertex (для указателя на тип).

package main

import (
  "fmt"
  "math"
)

type Abser interface {
  Abs() float64
}

func main() {
  var a Abser
  f := MyFloat(-math.Sqrt2)
  v := Vertex{3, 4}

  a = f  // a MyFloat реализует Abser
  a = &v // a *Vertex реализует Abser

  // На следующей строке, v является Vertex (не *Vertex)
  // и не реализует Abser.
  a = v

  fmt.Println(a.Abs())
}

type MyFloat float64

func (f MyFloat) Abs() float64 {
  if f < 0 {
    return float64(-f)
  }
  return float64(f)
}

type Vertex struct {
  X, Y float64
}

func (v *Vertex) Abs() float64 {
  return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

Вывод:

prog.go:22:4: 
  cannot use v (type Vertex) as type Abser in assignment:
  Vertex does not implement Abser 
  (Abs method has pointer receiver)

Интерфейсы реализуются неявно

Тип реализует интерфейс путем реализации всех его методов. Нет явного объявления о намерении реализовать интерфейс, и нет ключевого слова "implements".

Неявные интерфейсы отделяют объявление интерфейса от его реализаций, которые могут находиться в любом другом пакете без предварительных согласований.

package main

import "fmt"

type I interface {
  M()
}

type T struct {
  S string
}

// Этот метод означает, что тип T 
// реализует интерфейс I,
// но нам не требуется явно обозначать что он делает это.
func (t T) M() {
  fmt.Println(t.S)
}

func main() {
  var i I = T{"hello"}
  i.M()
}

Вывод:

hello


Читайте также:


Комментариев нет:

Отправить комментарий