Определение и инициализация структур
Структуры похожи на кортежи, о которых говорилось в разделе "Тип кортежа", в том смысле, что и те, и другие хранят несколько связанных значений. Как и кортежи, элементы структуры могут быть разных типов. В отличие от кортежей, в структуре вы будете именовать каждый элемент данных, чтобы было ясно, что значат эти значения. Добавление этих имен означает, что структуры более гибкие, чем кортежи: вам не нужно полагаться на порядок данных для указания или доступа к значениям экземпляра.
Для определения структуры мы вводим ключевое слово struct
и именуем всю структуру. Имя структуры должно описывать значение элементов данных, группируемых вместе. Затем, внутри фигурных скобок, мы определяем имена и типы элементов данных, которые мы называем полями. Например, в Листинге 5-1 показана структура, которая хранит информацию о пользовательском аккаунте.
Filename: src/main.rs
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
Листинг 5-1: Определение структуры User
После определения структуры, чтобы использовать ее, мы создаем экземпляр этой структуры, указав конкретные значения для каждого из полей. Мы создаем экземпляр, указывая имя структуры, а затем добавляем фигурные скобки, содержащие пары ключ: значение, где ключи - это имена полей, а значения - данные, которые мы хотим хранить в этих полях. Мы не обязаны указывать поля в том же порядке, в котором они были объявлены в структуре. Другими словами, определение структуры похоже на общий шаблон для типа, а экземпляры заполняют этот шаблон конкретными данными, чтобы создать значения этого типа. Например, мы можем объявить конкретного пользователя, как показано в Листинге 5-2.
Filename: src/main.rs
fn main() {
let user1 = User {
active: true,
username: String::from("someusername123"),
email: String::from("[email protected]"),
sign_in_count: 1,
};
}
Листинг 5-2: Создание экземпляра структуры User
Для получения конкретного значения из структуры мы используем точку. Например, чтобы получить адрес электронной почты этого пользователя, мы используем user1.email
. Если экземпляр изменяемый, мы можем изменить значение, используя точку и присваивание в конкретное поле. Листинг 5-3 показывает, как изменить значение в поле email
изменяемого экземпляра User
.
Filename: src/main.rs
fn main() {
let mut user1 = User {
active: true,
username: String::from("someusername123"),
email: String::from("[email protected]"),
sign_in_count: 1,
};
user1.email = String::from("[email protected]");
}
Листинг 5-3: Изменение значения в поле email
экземпляра User
Обратите внимание, что весь экземпляр должен быть изменяемым; Rust не позволяет нам помечать только некоторые поля как изменяемые. Как и с любым выражением, мы можем создать новый экземпляр структуры в качестве последнего выражения в теле функции, чтобы неявно вернуть этот новый экземпляр.
Листинг 5-4 показывает функцию build_user
, которая возвращает экземпляр User
с заданным адресом электронной почты и именем пользователя. Поле active
получает значение true
, а поле sign_in_count
получает значение 1
.
fn build_user(email: String, username: String) -> User {
User {
active: true,
username: username,
email: email,
sign_in_count: 1,
}
}
Листинг 5-4: Функция build_user
, которая принимает адрес электронной почты и имя пользователя и возвращает экземпляр User
Смысл в том, чтобы именовать параметры функции тем же именем, что и поля структуры, но приходится повторять имена полей email
и username
и переменные, что немного утомительно. Если структура имела больше полей, повторение каждого имени было бы еще более раздражающим. К счастью, есть удобный сокращение!