Структуры

Последнее обновление: 30.05.2024

Структуры представляют составной тип данных, который представляет какую-то определенную сущность и который объединяет набор данных, описывающих эту сущность.

Для определения структуры применяется ключевое слово struct:

struct имя_структуры;

После ключевого слова struct указывается имя структуры. Например:

struct Person;

В данном случае определена структура Person. Структура представляет новый тип, поэтому, создав структуру, мы можем определить ее переменную:

struct Person;

fn main() {
    let tom: Person = Person{};
    // или так
    //  let tom = Person;
    println!("Person Tom created"); 
}

Здесь определяется переменная tom, которая представляет тип Person. В качестве значения переменной присваивается Person{} - после названия структуры идут пустые фигурные скобки. Также мы можем сократить определение, убрав фигурные скобки и определение типа:

let tom = Person;

Пока мы никак не используем структуру, и после создания ее переменной просто выводим некоторое диагностическое сообщение.

Одной из задач структур является хранение или объединение некоторого набора данных. Для этого структура определяется в следующем виде:

struct имя_структуры {
	переменная1: тип_данных,
	переменная2: тип_данных,
	.......................
	переменнаяN: тип_данных,
}

После имени структуры внутри фигурных скобок через запятую перечисляются переменные структуры. Переменные структуры еще называются полями. Для каждого поля определяется название и его тип.

Например, определение простейшей структуры:

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.

Структура как параметр и результат функции

Как и любой другой тип, структура может представлять параметр функции или ее возвращаемое значение. Например:

struct Person
{
    name: String,
	age: u8
}
fn print_person(person: Person){

    println!("Name: {}  Age: {}", person.name, person.age); 
}
fn main() {
    let tom: Person = Person{ name: "Tom".to_string(), age: 40};
    print_person(tom);  // передача владения структурой Person в функцию
}

Здесь функция print_person в качестве параметра принимает структуру Person и выводит значения ее полей на консоль. Однако обратите внимание, как передается структура - при передаче структуры в функцию также передается владение этой структурой. Соответственно после вызова функции мы не сможем использовать структуру в функции main:

fn main() {
    let tom = Person{ name: "Tom".to_string(), age: 40};
    print_person(tom);  // передача владения структурой Person в функцию
    print_person(tom); // ! Ошибка - функция main уже не владеет структурой Person
}

Потому часто целесообразнее передавать структуру по ссылке, как и в случае с данными других типов:

struct Person
{
    name: String,
	age: u8
}
fn print_person(person: &Person){

    println!("Name: {}  Age: {}", person.name, person.age); 
}
fn main() {
    let tom: Person = Person{ name: "Tom".to_string(), age: 40};
    print_person(&tom);  // Name: Tom  Age: 40
    print_person(&tom); // Ошибки нет - Name: Tom  Age: 40
}

Возвращение структуры из функции также не отличается от возвращения значений любых других типов:

struct Person
{
    name: String,
	age: u8
}
fn create_person(name: String, age: u8) -> Person{

    Person {name, age}
}
fn main() {
    let tom = create_person("Tom".to_string(), 40);
    println!("Name: {}  Age: {}", tom.name, tom.age);  // Name: Tom  Age: 40
}

Здесь функция create_person() принимает два параметра и из них создает структуру Person.

Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850