Структуры представляют составной тип данных, который представляет какую-то определенную сущность и который объединяет набор данных, описывающих эту сущность.
Для определения структуры применяется ключевое слово struct:
struct имя_структуры { переменная1: тип_данных, переменная2: тип_данных, ....................... переменнаяN: тип_данных, }
После слова struct указывается имя структуры, а затем внутри фигурных скобок через запятую перечисляются ее переменные. Переменные структуры еще называются полями. Для каждого поля определяется название и его тип.
Например, определение простейшей структуры:
struct Person // структура - человек { name: String, // имя age: u8, // возраст height: f32 // рост }
В данном случае определена структура Person, которая представляет сущность "человек". Названия структур обычно начинаются с большой буквы. Эта структура имеет три поля, которые описывают соответственно имя, возраст и рост человек.
Обратите внимание, что имя человека - поле name
представляет тип String, который представляет расширяемую строку и который также
является встроенной в Rust структурой. Таким образом, одни структуры могут быть полями других структур.
Создав структуру, мы можем определить ее переменную. При инициализации такой переменной необходимо указать значения для всех полей структуры:
let tom = Person{ name: "Tom".to_string(), age: 36, height: 1.78 };
Здесь обращаю внимание, что значение для поля указывается после двоеточия (:), а не после знака равно, как при обычном присвоении. Кроме того,
полю name
присваивается не просто строка "Tom", а результат метода "Tom".to_string()
, который преобразует строковый литерал к
типу String
.
Затем через имя переменной структуры мы сможем обращаться к ее полям:
название_переменной.поле_структуры
После названия переменной через точку указывается поле структуры.
Например, используем вышеописанную структуру в программе:
fn main(){ let tom = Person{ name: "Tom".to_string(), age: 36, height: 1.78 }; println!("name = {}", tom.name); println!("age = {}", tom.age); println!("height = {}", tom.height); } struct Person // структура - человек { name: String, // имя age: u8, // возраст height: f32 // рост }
Консольный вывод программы:
name = Tom age = 36 height = 1.78
Если мы хотим изменять значения полей структуры, то переменная структуры должна быть определена с ключевым словом mut:
fn main(){ let mut tom = Person{ name: "Tom".to_string(), age: 36, height: 1.78 }; println!("name={} age = {} height={}", tom.name, tom.age, tom.height); // меняем значения полей tom.age = 25; tom.height = 1.81; println!("name={} age = {} height={}", tom.name, tom.age, tom.height); } struct Person // структура - человек { name: String, // имя age: u8, // возраст height: f32 // рост }
Консольный вывод:
name = Tom age = 36 height = 1.78 name = Tom age = 25 height = 1.81
Если полям структуры передаются значения переменных или параметров метода, имена которых совпадают с именами полей структуры, то можно сократить инициализацию структуры.
fn main(){ let age = 22; let height = 1.68; let tom = Person{ name: "Tom".to_string(), age, height }; println!("name={} age = {} height={}", tom.name, tom.age, tom.height); } struct Person { name: String, age: u8, height: f32 }
Здесь названия переменных age
и height
совпадает с названиями полей. Поэтому вместо
let age = 22; let height = 1.68; let tom = Person{ name: "Tom".to_string(), age: age, height: height };
Можно написать:
let age = 22; let height = 1.68; let tom = Person{ name: "Tom".to_string(), age, height };
Иногда возникает необходимость передать одной переменной структуры при инициализации значения другой переменной этой структуры. И тут Rust тоже позволяет сократить код:
fn main(){ let bob = Person{ name: "Bob".to_string(), age: 33, height: 1.70 }; let tom = Person{ name: "Tom".to_string(), ..bob }; println!("name={} age = {} height={}", tom.name, tom.age, tom.height); } struct Person { name: String, age: u8, height: f32 }
Выражение ..bob
указывает, что переменная структуры будет наполняться из переменной bob
. Если мы хотим для отдельных полей
определить другие значения, то мы можем их прописать явно:
let tom = Person{ name: "Tom".to_string(), ..bob };
В данном случае переменная tom берет из переменной bob значения для полей age и height, а для поля name определяет свое значение.
Rust позволяет раскладывать структуры на переменные. Для этого применяется оператор let:
let структура{поле_структуры: переменная} = объект_структуры;
Рассмотрим пример с декомпозицией структуры Person:
struct Person { name: String, age: u8, height: f32 } fn main(){ let tom = Person{ name: "Tom".to_string(), age: 33, height: 1.70 }; let Person{name: username, age: userage, height: _} = tom; println!("name = {} age = {}", username, userage); }
Здесь выражение
let Person{name: username, age: userage, height: _} = tom;
указывает, что из структуры tom
значение поля name
надо передать в переменную username
, а значение поля age
- в
переменную userage
. Переменные username и userage определяются автоматически. А поле height
, к примеру, мы не хотим использовать, поэтому ему передается прочерк _
.
И далее мы сможем использовать переменные username и userage.