Golang: Структуры и методы в Go
Go — язык со строгой типизацией и поддержкой объектного стиля, но без привычного class
. Вместо этого используется сочетание структур (для хранения состояния) и методов (для поведения).
Это позволяет создавать объекты, инкапсулирующие данные и операции над ними — как в ООП, но проще и прямолинейнее.
Объявление структуры
Структура — это пользовательский тип, состоящий из набора полей:
type User struct {
Name string
Age int
}
Структура User
описывает сущность с двумя полями: Name
(строка) и Age
(целое число). Теперь User
— это новый тип данных, который можно использовать, как любой другой. Чтобы создать значение структуры, используют литерал структуры.
// var user User;
user := User{
Name: "Alice",
Age: 30,
}
К полям структуры можно обращаться напрямую:
fmt.Println(user.Name) // => Alice
user.Age = 31
Методы
Go позволяет определять методы — это функции, привязанные к типу (например, к структуре). Они выглядят как обычные функции, но с особым параметром — приёмником (receiver), который указывается в скобках перед именем функции. Обращаться к нему можно так же как и любым другим параметрам:
func (u User) Greet() string {
return "Hi, I'm " + u.Name
}
Этот метод можно вызвать на экземпляре структуры:
user := User{Name: "Alice", Age: 30}
fmt.Println(user.Greet()) // => Hi, I'm Alice
Где описывать методы?
Методы определяются вне структуры, но обязательно в том же пакете. В теле самой структуры можно определить только поля. Вот правильная структура:
package main
import "fmt"
type User struct {
Name string
Age int
}
func (u User) Greet() string {
return "Hi, I'm " + u.Name
}
func main() {
user := User{Name: "Bob"}
fmt.Println(user.Greet()) // => Hi, I'm Bob
}
Порядок не имеет значения — метод может быть описан до или после использования структуры. Главное — чтобы тип, к которому он относится, был определён в том же пакете.
Передача структуры в функцию
Со структурами работают не только методы. Как и любой другой тип, структуру можно передавать в обычные функции. Это позволяет использовать её как единое значение, передавая сразу связанный набор данных.
func PrintAge(u User) {
fmt.Println("Возраст:", u.Age)
}
Функция PrintAge()
получает структуру User
и работает с её полями. При этом структура передаётся по значению, то есть копируется. Если изменить ее внутри функции, то изменится копия — оригинал останется без изменений. Такая же логика действует и для методов.
func ChangeName(u User) {
u.Name = "Неизвестно"
}
func (u User) ResetName() {
u.Name = "Без имени"
}
func main() {
user := User{Name: "Alice", Age: 30}
ChangeName(user)
// не изменилось
fmt.Println(user.Name) // => Alice
user.ResetName()
// не изменилось
fmt.Println(user.Name) // => Alice
}
Чтобы изменения применялись к оригинальной структуре, нужно передавать указатель. Это мы научимся делать в следующих уроках.
Задание
Создайте структуру Package
, которая описывает посылку и содержит два поля:
ID
— строка: идентификатор посылки (например, "PKG-1042")Delivered
— логическое значение (bool), указывающее доставлена ли посылка
Реализуйте метод Status()
, который возвращает статус в виде строки, например:
- Если
Delivered == true
, метод возвращает: "Package PKG-1042 has been delivered" - Если
Delivered == false
, метод возвращает: "Package PKG-1042 is still in transit"
p1 := Package{ID: "PKG-1042", Delivered: true}
p1.Status() // "Package PKG-1042 has been delivered"
p2 := Package{ID: "PKG-2048", Delivered: false}
p2.Status() // "Package PKG-2048 is still in transit"
Полезное
Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект
Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник":
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи. В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества
Ваше упражнение проверяется по этим тестам
package solution
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestPackageStatus(t *testing.T) {
a := assert.New(t)
p1 := Package{ID: "PKG-1042", Delivered: true}
a.Equal("Package PKG-1042 has been delivered", p1.Status())
p2 := Package{ID: "PKG-2048", Delivered: false}
a.Equal("Package PKG-2048 is still in transit", p2.Status())
}
Решение учителя откроется через:
20:00
