English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Структуры Rust

В 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.

Разница с 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).