Найти в Дзене

Golang с нуля: структуры и интерфейсы — создаём собственные типы данных

Оглавление

(Статья 5 из цикла "Golang с нуля")

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

🔹 Структуры (structs): как создавать свои типы

Структура — это коллекция полей разного типа, объединённых в один тип. Она похожа на классы в других языках, но без наследования и методов, определённых внутри. Структуры позволяют логически группировать связанные данные.

Пример создания структуры:

package main

import "fmt"

// Создаем структуру User

type User struct {
Name string
Age int
IsAdmin bool

}

func main() {
// Создаем переменную типа User
user1 := User{
Name: "Алиса",
Age: 30,
IsAdmin: true,
}

// Обращение к полям структуры
fmt.Println("Имя:", user1.Name)
fmt.Println("Возраст:", user1.Age)

// Изменение поля
user1.Age = 31
fmt.Println("Новый возраст:", user1.Age)

}

🔹 Методы: функции для структур

К структурам можно привязывать функции, которые в Go называются методами. Метод — это функция, объявленная с так называемым ресивером (receiver), который связывает её со структурой.

Пример метода:

package main

import "fmt"

type User struct {
Name string
Age int

}

// Метод, который выводит информацию о пользователе

func (u User) SayHello() {
fmt.Printf("Привет, меня зовут %s, мне %d лет.\n", u.Name, u.Age)

}

func main() {
user1 := User{Name: "Боб", Age: 25}
user1.SayHello() // Вызов метода

}

🔹 Интерфейсы: поведение, а не реализация

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

Интерфейсы — это основа полиморфизма в Go. Тип автоматически "реализует" интерфейс, если у него есть все методы, описанные в интерфейсе. Явного объявления о реализации не требуется.

Пример интерфейса:

package main

import "fmt"

// Определяем интерфейс Shape

type Shape interface {
Area() float64

}

// Структура для круга

type Circle struct {
Radius float64

}

// Структура для квадрата

type Square struct {
Side float64

}

// Метод Area для Circle

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

}

// Метод Area для Square

func (s Square) Area() float64 {
return s.Side * s.Side

}

func main() {
circle := Circle{Radius: 5}
square := Square{Side: 4}

// Функция, которая принимает любой тип, реализующий интерфейс Shape
printArea(circle)
printArea(square)

}

func printArea(s Shape) {
fmt.Printf("Площадь: %.2f\n", s.Area())

}

В этом примере и Circle, и Square реализуют интерфейс Shape (потому что у них обоих есть метод Area()), и их можно передавать в функцию printArea.

💡 Вывод

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

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

Попробуйте создать собственную структуру с несколькими методами и интерфейсом, который она реализует! Поделитесь своими идеями в комментариях!