Rust - Basic - 05 - Структуры

Структуры

Кратко

  • базовый синтаксис

    // объявление типа
    struct User {
        active: bool,
        username: String,
        email: String,
        sign_in_count: u64,
    }
    
    // создание экземпляра
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    
    // доступ и изменение
    let mut user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    user1.email = String::from("anotheremail@example.com");
    
    // field init shorthand
    fn build_user(email: String, username: String) -> User {
        User {
            email,
            username,
            active: true,
            sign_in_count: 1,
        }
    }
    
    // struct update
    let user2 = User {
        email: String::from("another@example.com"),
        ..user1
    }
    // здесь user1 перемещён, потому что user1.username (тип String) перемещён в user2.username
    // если при создании user2 задать username заново, user1 не будет перемещён
    
  • Методы

    функция внутри блока impl называется method или associated function; method и field могут иметь одинаковые имена

    одновременно может существовать несколько блоков impl

    #[derive(Debug)]
    struct Rectangle {
        width: u32,
        height: u32,
    }
    
    impl Rectangle {
        fn area(&self) -> u32 {  // method
            self.width * self.height
        }
    		fn width(&self) -> bool {  // method и field могут иметь одинаковое имя
            self.width > 0
        }
        fn square(size: u32) -> Rectangle {  // можно и без &self
            Rectangle {
                width: size,
                height: size,
            }
        }
    }
    
    // одновременно может существовать несколько блоков impl
    impl Rectangle {
        fn can_hold(&self, other: &Rectangle) -> bool {
            self.width > other.width && self.height > other.height
        }
    }
    
    fn main() {
        let rect1 = Rectangle {
            width: 30,
            height: 50,
        };
    
        println!(
            "The area of the rectangle is {} square pixels.",
            rect1.area()
        );
    
    		if rect1.width() {
            println!("The rectangle has a nonzero width; it is {}", rect1.width);
        }
    }
    

Источник

https://doc.rust-lang.org/book/ch05-00-structs.html

…

Создание экземпляров из других экземпляров с помощью синтаксиса обновления структуры

Часто бывает полезно создать новый экземпляр структуры, который использует большинство значений старого экземпляра, но некоторые из них меняет. Для этого можно применить синтаксис обновления структуры.

Сначала листинг 5-6 показывает, как создать новый экземпляр User в user2 без синтаксиса обновления. Мы задаём новое значение для email, а в остальном берём те же значения из user1, которые создали в листинге 5-2.


    let user2 = User {
        active: user1.active,
        username: user1.username,
        email: String::from("another@example.com"),
        sign_in_count: user1.sign_in_count,
    };

Листинг 5-6: создание нового экземпляра User с использованием одного из значений user1

С синтаксисом обновления структуры того же эффекта можно добиться меньшим количеством кода, как показано в листинге 5-7. Синтаксис .. указывает, что остальные поля, не заданные явно, должны получить те же значения, что и поля в указанном экземпляре.


    let user2 = User {
        email: String::from("another@example.com"),
        ..user1
    };

Листинг 5-7: использование синтаксиса обновления структуры, чтобы задать новое значение email для экземпляра User, но взять остальные значения из user1

Код в листинге 5-7 тоже создаёт экземпляр user2 с другим значением email, но с теми же значениями полей username, active и sign_in_count из user1. Запись ..user1 должна идти последней, чтобы указать: все оставшиеся поля берут значения из соответствующих полей user1; при этом мы можем задать значения скольких угодно полей в любом порядке, независимо от порядка полей в определении структуры.

Заметим, что синтаксис обновления структуры похож на присваивание через =, потому что он перемещает данные — так же, как в разделе «Взаимодействие переменных и данных: move» . В этом примере мы больше не можем использовать user1 после создания user2, потому что String в поле username из user1 был перемещён в user2. Если бы мы задали user2 новые значения String и для email, и для username и тем самым взяли из user1 только active и sign_in_count, то user1 остался бы валидным после создания user2. Типы active и sign_in_count реализуют трейт Copy, поэтому работает поведение, о котором мы говорили в разделе «Данные только в стеке: Copy» .