English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
В Rust структуры (Struct) и кортежи (Tuple) могут скомбинировать несколько типов данных, не обязательно одинаковых, в единое целое, но у каждого члена структуры и самой структуры есть имя, что позволяет не запоминать индексы при доступе к членам. Кортежи часто используются для передачи нескольких значений без определения, а структуры используются для стандартизации часто используемых структур данных. Каждый член структуры называется "полем".
Это определение структуры:
struct Site { domain: String, name: String, nation: String, found: u32 }
Внимание: если вы часто используете C/C++, запомните, что в Rust оператор struct используется только для определения, а не для объявления примера, в конце не ставится символ ;, и каждый определенный字段 разделяется запятой.
Многие аспекты Rust оказывают влияние от JavaScript, при создании структуры используется синтаксис key: value JSON-объекта для определения:
let w3codebox = Site { domain: String::from("ru.oldtoolbag.com"), name: String::from("w3codebox"), nation: String::from("China"), found: 2013 };
Если вы не знакомы с JSON-объектами, вы можете не обращать на них внимания, запомните только формат:
Имя класса структуры { Имя поля : значение поля, ... }
Эта польза заключается в том, что это делает программу более интуитивной, и нет необходимости вводить значения членов в порядке, определенном в определении.
Если структура, которую вы примеряете, имеет поля с именами, которые совпадают с именами существующих переменных, можно упростить запись: }}
let domain = String::from("ru.oldtoolbag.com"); let name = String::from("w3codebox"); let w3codebox = Site { domain, // Эквивалентно domain: domain, name, // Эквивалентно name: name, nation: String::from("China"), traffic: 2013 };
Такая ситуация: вы хотите создать пример структуры, где большинство свойств должны быть установлены так же, как у существующей структуры, но необходимо изменить только одно или два поля, можно использовать синтаксис обновления структуры:
let site = Site { domain: String::from("ru.oldtoolbag.com"), name: String::from("w3codebox"), ..w3codebox };
Внимание: после ..w3codebox не может быть запятой. Этот синтаксис не позволяет копировать структуру в неизменном виде, что означает, что нужно至少 изменить значение одного поля, чтобы ссылаться на значения других примеров.
Есть более простой способ определения и использования структуры:Структура с tuples.
Структура с tuples - это структура, которая является формой tuples.
Разница с tuples в том, что у него есть имена и фиксированная структура типа. Его цель - обработка тех данных, которые требуют определения типа (часто используется) и не хотят быть слишком сложными:
struct Color(u8, u8, u8); struct Point(f64, f64); let black = Color(0, 0, 0); let origin = Point(0.0, 0.0);
"Цвет" и "координаты точки" - это два常用的 данных типа, но если при примере пишется большая скобка и два имени, это жертвует читаемостью в угоду удобству, Rust не оставляет этой проблемы. Использование структуры с tuples и их доступ через . и индексы:
fn main() { struct Color(u8, u8, u8); struct Point(f64, f64); let black = Color(0, 0, 0); let origin = Point(0.0, 0.0); println!("black = ({}, {}, {})", black.0, black.1, black.2); println!("origin = ({}, {})", origin.0, origin.1); }
Результат выполнения:
black = (0, 0, 0) origin = (0, 0)
Структура体型 должна контролировать обладание значением полей, так как при выходе структуры体型 все поля будут освобождены.
Вот почему в примерах этой главы используется тип String, а не &str.
Это не означает, что в структуре体型 не определяются полевые ссылки, это необходимо реализовать через механизм "жизненного цикла".
Но трудно объяснить концепцию "жизненного цикла", поэтому она будет объяснена в后面的 главах.
В отладке очень полезно полностью отображать пример структуры体型. Но если бы мы вручную записали это, это было бы очень неудобно. Поэтому Rust предоставляет удобный способ вывода всего структуры体型:
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } fn main() { let rect1 = Rectangle { width: 30, height: 50 }; println!("rect1 is {:?}", rect1); }
Как показано в первом ряду: обязательно импортируйте библиотеку отладки #[derive(Debug)] Затем в макросах println и print можно использовать占ачник {:?} для вывода всего структуры体型:
rect1 is Rectangle { width: 30, height: 50 }
Если много свойств, можно использовать другой占ачник {:#?} .
Результат вывода:
rect1 is Rectangle { width: 30, height: 50 }
Метод (Method) и функция (Function) похожи, но метод используется для работы с экземплярами структуры体型.
Если вы изучали некоторые объектно-ориентированные языки, то вам, возможно, известно, что функции обычно размещаются в определении класса, и в функции используется this для указания на操作的 экземпляр.
Язык Rust не ориентирован на объекты, это可以看出 из инноваций в механизме обладания. Но идеи ориентации на объекты могут быть реализованы в Rust.
Первый параметр метода структуры体型 должен быть &self, тип не указывается, так как self не стиль, а ключевое слово.
Рассчитать площадь прямоугольника:
struct Rectangle { width: u32, height: u32, } impl Rectangle { fn area(&self) -> u32 { self.width * self.height } } fn main() { let rect1 = Rectangle { width: 30, height: 50 }; println!("Площадь rect1 составляет {}", rect1.area()); }
Результат вывода:
Площадь rect1 составляет 1500
Обратите внимание, что при вызове методов структуры体型 не нужно填写 self, это сделано для удобства использования.
Одна много параметрическая инстанция:
struct Rectangle { width: u32, height: u32, } impl Rectangle { fn area(&self) -> u32 { self.width * self.height } fn wider(&self, rect: &Rectangle) -> bool { self.width > rect.width } } fn main() { let rect1 = Rectangle { width: 30, height: 50 }; let rect2 = Rectangle { width: 40, height: 20 }; println!("{}", rect1.wider(&rect2)); }
Результат выполнения:
false
Этот程序 определяет, является ли rect1 шире rect2.
Причина, по которой "метод структуры" не называют "функцией структуры", заключается в том, что "функция" это имя,留给这样一种 функции: она определена в impl-блоке, но не имеет параметра &self.
Эти функции не зависят от примера, но для их использования необходимо声明, в каком impl-блоке они определены.
Функция String::from, которую мы используем всегда, является "ассоциированной функцией".
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } impl Rectangle { fn create(width: u32, height: u32) -> Rectangle { Rectangle { width, height } } } fn main() { let rect = Rectangle::create(30, 50); println!("{:?}", rect); }
Результат выполнения:
Rectangle { width: 30, height: 50 }
Совет:Блок impl структуры может быть написан несколько раз, и это эквивалентно объединению их содержимого!
Структура может быть использована только как символ, не требуя никаких членов:
struct UnitStruct;
Мы называем такие структуры без тела структурами-единицами (Unit Struct).