Интерфейсы

Введение в интерфейсы

Последнее обновление: 28.12.2017

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

Для определения интерфейса применяется ключевое слово interface:

type имя_интерфейса interface{
	определения_функций
}

Например, простейшее определение интерфейса:

type vehicle interface{
	move()
}

Данный интерфейс называется vehicle. Допустим, данный интерфейс представляет некоторое транспортное средство. Он определяет функцию move(), которая не принимает никаких параметров и ничего не возвращает.

При этом важно понимать, что интерфейс - это именно абстракция, а не конкретный тип, как int, sring или структуры. К примеру, мы не можем напрямую создать объект интерфейса:

var v vehicle = vehicle{}

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

package main

import "fmt"

type Vehicle interface{
	move()
}

// структура "Автомобиль"
type Car struct{ }

// структура "Самолет"
type Aircraft struct{}


func (c Car) move(){
	fmt.Println("Автомобиль едет")
}
func (a Aircraft) move(){
	fmt.Println("Самолет летит")
}

func main() {
	
	var tesla Vehicle = Car{}
	var boing Vehicle = Aircraft{}
	tesla.move()
	boing.move()
}

Здесь определены две структуры: Car и Aircraft, которые, предположим, представляют, автомобиль и самолет соответственно. Для каждой из структур определен метод move(), который имитирует перемещение транспортного средства. Этот метод move соответствует функции move интерфейса vehicle по типу параметров и типу возвращаемых значений. Поскольку между методом структур и функций в интерфейсе есть соответствие, то подобные структуры неявно реализуют данный интерфейс.

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

Поскольку структуры Car и Aircraft реализуют интерфейс Vehicle, то мы можем определить переменные данного интерфейса, передав им объекты структур:

var tesla Vehicle = Car{}
var boing Vehicle = Aircraft{}

Где нам могут помочь интерфейсы? Интерфейсы позволяют определить какую-то обобщенную реализацию без привязки к конкретному типу. Например, рассмотрим следующую ситуацию:

package main

import "fmt"

type Car struct{ }
type Aircraft struct{}


func (c Car) move(){
	fmt.Println("Автомобиль едет")
}
func (a Aircraft) move(){
	fmt.Println("Самолет летит")
}

func driveCar(c Car){
	c.move()
}
func driveAircraft(a Aircraft){
	a.move()
}

func main() {
	
	var tesla Car = Car{}
	var boing Aircraft = Aircraft{}
	driveCar(tesla)
	driveAircraft(boing)
}
}

Допустим, в данном случае определены две структуры Car и Aircraft, которые представляют автомобиль и самолет. Для каждой из структур определен метод перемещения move(), который условно перемещает транспортное средство. И также определены две функции driveCar() и driveAircraft(), которые принимают соответственно структуры Car и Aircraft и предназначены для вождения этих транспортных средств.

И отчетливо видно, что обе функции driveCar и driveAircraft фактически идентичны, они выполняют один и те же действия, только для разных типов. И было бы неплохо, если можно было бы определить одну обобщенную функцию для разных типов. Особенно учитывая, что у нас может быть и больше транспортных средств - велосипед, корабль и т.д. И для вождения каждого транспортного средства придется определять свой метод, что не очень удобно. И как раз в этом случае можно воспользоваться интерфейсами:

package main
import "fmt"

type Vehicle interface{
	move()
}

func drive(vehicle Vehicle){
	vehicle.move()
}

type Car struct{ }
type Aircraft struct{}


func (c Car) move(){
	fmt.Println("Автомобиль едет")
}
func (a Aircraft) move(){
	fmt.Println("Самолет летит")
}

func main() {
	
	tesla := Car{}
	boing := Aircraft{}
	drive(tesla)
	drive(boing)
}

Теперь вместо двух функций определена одна общая функция - drive(), которая в качесте параметра принимает значение типа Vehicle. Поскольку этому интерфейсу соответствуют обе структуры Car и Aircraft, то мы можем передавать эти структуры в функцию drive в качесте аргументов.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850