Структуры и методы

Структуры объединяют именованные поля в один тип; методы добавляются через блок impl.

Структура (struct) — пользовательский тип, объединяющий несколько именованных полей в одно целое.

Объявление и создание

Структура описывает «вещь» с набором свойств. Сначала объявляют тип с полями, затем создают экземпляры.

struct User {
    name: String,
    age: u32,
    active: bool,
}

fn main() {
    let u = User {
        name: String::from("Аня"),
        age: 28,
        active: true,
    };
    println!("{} ({}), активен: {}", u.name, u.age, u.active);
}

Вывод:

Аня (28), активен: true

Чтобы менять поля экземпляра, всю переменную объявляют как mut — отдельные поля изменяемыми пометить нельзя, изменяемость относится ко всему значению.

Методы через impl

Поведение структуры описывают в блоке impl. Метод, который работает с конкретным экземпляром, первым параметром принимает &self — ссылку на сам объект (аналог this в других языках).

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // метод: читает поля через неизменяемую ссылку на self
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // метод, который меняет self, берёт &mut self
    fn scale(&mut self, factor: u32) {
        self.width *= factor;
        self.height *= factor;
    }
}

fn main() {
    let mut r = Rectangle { width: 3, height: 4 };
    println!("площадь = {}", r.area());
    r.scale(2);
    println!("после увеличения = {}", r.area());
}

Вывод:

площадь = 12
после увеличения = 48

Заметьте связь с владением: &self — заимствование для чтения, &mut self — для изменения. Те же правила, что для обычных ссылок.

Ассоциированные функции и конструкторы

Функция в impl без self — ассоциированная функция, она привязана к типу, а не к экземпляру. Их вызывают через ::. Чаще всего так делают конструкторы по имени new.

struct Point {
    x: i32,
    y: i32,
}

impl Point {
    fn new(x: i32, y: i32) -> Point {
        Point { x, y } // короткая запись, когда имя поля совпадает с переменной
    }

    fn origin() -> Point {
        Point::new(0, 0)
    }
}

fn main() {
    let p = Point::new(2, 3);     // вызов через ::
    let o = Point::origin();
    println!("({}, {}) и ({}, {})", p.x, p.y, o.x, o.y);
}

Вывод:

(2, 3) и (0, 0)

Когда имя поля совпадает с именем переменной (x, y), можно писать просто Point { x, y } вместо Point { x: x, y: y } — это называется сокращённой инициализацией полей.

Кортежные структуры

Иногда имена полей не нужны — тогда удобна кортежная структура: те же поля, но доступ по индексу. Полезно для простых обёрток.

struct Color(u8, u8, u8); // R, G, B

fn main() {
    let red = Color(255, 0, 0);
    println!("R={} G={} B={}", red.0, red.1, red.2);
}

Вывод:

R=255 G=0 B=0

Итог

  • Структура объединяет именованные поля; методы добавляют в блоке impl.
  • Метод экземпляра берёт &self (чтение) или &mut self (изменение) — это те же ссылки.
  • Функции без self — ассоциированные, вызываются через ::; так делают конструкторы new.
Проверьте себя
1. Что первым параметром принимает метод структуры, работающий с экземпляром?
Athis
B&self или &mut self — ссылку на сам объект
CИмя структуры
DНичего
2. Чем ассоциированная функция (например new) отличается от метода?
AНичем
BОна не принимает self и привязана к типу, вызывается через ::
CОна работает только с числами
DОна не может возвращать значение
3. Когда нужно объявить переменную-структуру как mut?
AНикогда
BКогда нужно менять её поля или вызывать методы с &mut self
CТолько для кортежных структур
DВсегда
Поддержать проект