Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 25 из 107.

Интерфейс (interface) в Go определяет набор сигнатур методов без их реализации. Он описывает, что тип может делать, а не то, как он это делает. Любой тип, который реализует все методы интерфейса, автоматически удовлетворяет этому интерфейсу.

Вот как определяется интерфейс:

type Speaker interface {
    Speak() string
}

Этот интерфейс Speaker требует, чтобы любой реализующий его тип имел метод Speak(), который возвращает строку. Теперь любую структуру с этим методом можно использовать везде, где ожидается Speaker.

type Dog struct {
    Name string
}

func (d Dog) Speak() string {
    return d.Name + " says woof!"
}

type Cat struct {
    Name string
}

func (c Cat) Speak() string {
    return c.Name + " says meow!"
}

Оба типа Dog и Cat удовлетворяют интерфейсу Speaker, так как каждый из них имеет метод Speak() с правильной сигнатурой. Теперь вы можете писать функции, которые принимают любой Speaker:

func MakeSound(s Speaker) {
    fmt.Println(s.Speak())
}

func main() {
    dog := Dog{Name: "Buddy"}
    cat := Cat{Name: "Whiskers"}
    
    MakeSound(dog)  // Buddy говорит woof!
    MakeSound(cat)  // Whiskers говорит meow!
}

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

challenge icon

Задание

Легко

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

Вы организуете свой код в двух файлах:

  • vehicles.go: Определите интерфейс Describer с единственным методом Describe() string. Затем создайте две структуры, которые удовлетворяют этому интерфейсу:
    • Car с полями Brand и Model (оба типа string)
    • Bicycle с полями Type (string) и Gears (int)
    Каждая структура должна иметь метод Describe(), который возвращает строку с описанием транспортного средства.
  • main.go: Создайте функцию с именем PrintDescription, которая принимает любой Describer и выводит результат вызова его метода Describe(). Считайте информацию о транспортных средствах из входных данных, создайте объекты Car и Bicycle и используйте свою функцию для вывода описания каждого из них.

Будут предоставлены следующие входные данные:

  • Строка 1: Марка автомобиля (Car brand)
  • Строка 2: Модель автомобиля (Car model)
  • Строка 3: Тип велосипеда (Bicycle type)
  • Строка 4: Количество передач (целое число)

Ваши методы Describe() должны возвращать строки в следующих форматах:

  • Car: [Brand] [Model]
  • Bicycle: [Type] bike with [Gears] gears

Например, для входных данных Toyota, Camry, Mountain и 21 ваш вывод должен быть следующим:

Toyota Camry
Mountain bike with 21 gears

Ключевая идея заключается в том, что ваша функция PrintDescription работает с любым типом, имеющим метод Describe() — ей не нужно знать, имеет ли она дело с Car, Bicycle или любым другим типом транспортного средства, который вы можете добавить позже.

Шпаргалка

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

Определение интерфейса:

type Speaker interface {
    Speak() string
}

Типы, реализующие необходимые методы, удовлетворяют интерфейсу:

type Dog struct {
    Name string
}

func (d Dog) Speak() string {
    return d.Name + " says woof!"
}

type Cat struct {
    Name string
}

func (c Cat) Speak() string {
    return c.Name + " says meow!"
}

Функции могут принимать любой тип, удовлетворяющий интерфейсу:

func MakeSound(s Speaker) {
    fmt.Println(s.Speak())
}

func main() {
    dog := Dog{Name: "Buddy"}
    cat := Cat{Name: "Whiskers"}
    
    MakeSound(dog)  // Buddy says woof!
    MakeSound(cat)  // Whiskers says meow!
}

Попробуйте сами

package main

import (
	"fmt"
)

// TODO: Создайте функцию PrintDescription, которая принимает любой Describer
// и выводит результат вызова его метода Describe()

func main() {
	// Чтение входных данных
	var carBrand string
	var carModel string
	var bicycleType string
	var gears int

	fmt.Scanln(&carBrand)
	fmt.Scanln(&carModel)
	fmt.Scanln(&bicycleType)
	fmt.Scanln(&gears)

	// TODO: Создайте Car с маркой и моделью из входных данных

	// TODO: Создайте Bicycle с типом и количеством передач из входных данных

	// TODO: Используйте PrintDescription для вывода описания автомобиля

	// TODO: Используйте PrintDescription для вывода описания велосипеда
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование