Please enable JavaScript.
Coggle requires JavaScript to display documents.
RUST - Coggle Diagram
RUST
Общее
Указатели в памяти
Box<T> указатель на то, что требуется хранить значение в куче, а не в стеке.
Используется для значений с указателем Dyn - например, если есть trait с дженериком, то мы не можем положить структуру реализующую трейт в стек. и значение необходимо упаковать в бокс
Второй - мы используем рекурсивные структуры данных, когда одна структура содержит поле c Option<такаяже структура> - опять же, мы не можем положить это в стек, поэтому поле должно быть упаковано в Box
-
-
Rc<T> - подсчет ссылок на объект, если требуется разделить обращение к объекту между несколькими объектами, которым не нужно знать друг о друге
Чтобы передать права на чтение другому объекту, без боязни, что с объектом что-то случится за это время нужно передать ему указатель
Rc::clone
let object_1 : Rc<object_type> = object_tyoe::new()
borrower1 = bororower(Rc::clone(&object_1))
borrower_2 = borrower(object_1)
в данном случае второй владелец это настоящий
-
-
Arc<T> - тоже самое, что Rc, но для асинхронщины
-
-
RefCell - способ обойти правила заимствования. Позволяет менять значение переменной, даже если оно только для чтения. Очень похож на Box, но бокс при нарушении правил заимствования выдаст ошибку на этапе компиляции, а RefCell в рантайме
Типичная ситуация - объект должен менять свое внутреннее значение сам, но быть неизменяемым для другой части кода
чтобы в рантайме получить ссылку на изменение неизменяемого объекта, нужен метод borrow_mut
struct object {....., tasks: RefCell<Vec<.....>>}
let object_instance = {......, RefCell<Vec::new(....)>}
....
&object_instance.borrow_mut().push(....)
RefCell не отменяет правил заимствования. просто вместо ошибки компиляции будет паника. Если будет существовать более одной изменяемой ссылки
Соответственно, разрешен единственный владелец
в отличие от Cell вовзращается не копия, а именно ссылка. в т.ч мутабельная
Cell - Создает единственной значение, которое можно изменять при полностью неизменяемой структуре
-
Значение должно реализовывать Copy, потому что возвращается его копия
Для того, чтобы стать указателем, нужно реализовать типажи Deref (как ссылка) и Drop(код, который выполнится после покидания зоны видимости)
Deref определяет поведение оператора разыменовывания *
-
-
Weak<T> - слабая ссылка. как Rc, но не передает владения
Ссылки, время жизни, borrow
Время жизни никогда не оказывает влияния на машинный код. Лишь различие в типах затставит раст генерировать разные функции
-
Самый простой способ создать две мутабельные ссылки на объект - оюъявить новую зону видимости
let mut s = String::from,,,
{
let s1 = &mut s
}
let s2 = &mut s
макрос дебаг - забирает владение width: dbg!(30 * scale),
-
Управление
-
-
if let это синтаксический сахар. по сути это матч с обработкой всего одного значения. Блок после if let выполнгитеся, если паттерн совпадет.
if let Some(max) = config_max {println!("The maximum is configured to be {}", max);}
Ошибки
У ошибок есть возможность матчиться через match error.kind() - вернется енам io::ErrorKind
полезная конструкция let greeting_file = File::open("hello.txt").unwrap_or_else(|error| {
выполнит код, если нет возможности сделать unwrap
Оператор ? вызывает метод From, который приводит ошибку к тому типу, который указан в сигнатуре
-
-
Итераторы
разница межде iter() и into_iter() - первый получает мутабельную ссылку
второй принимает владение и возвращзает
-
-
трейт итератора mut args: impl Iterator<Item = String>,
-
Асинхронщина
-
join() прекращает дейтсиве текущего потока, пока не выполнится тот, который был
let (tx, rx) = mpsc::channel();
в потоках
tx.send(val).unwrap();
let received = rx.recv().unwrap();
-
mpsc можно клонировать продюсеров
let (tx, rx) = mpsc::channel(); let tx1 = tx.clone();
-
Типаж Send - если реализован, можно передавать объект между потоками
-
Оператор take берет из Option его значение и помещает заместо него None, чтобы не нарушать ту структуру в которой он находится
трейты
Traits
Нельзя напрямую создать объект реализующий трейт
let write: Write = buf
но можно сделать с типом трейта ссылку на обхект
let writer: *mut Write = &mut buf;
Это называется Объект характеристики
Объекты характеристик как правило нужны для коллекций с чем попало. Хотя их нельзя засунуть в структуру напрямую
struct Salad {veggies: Vec<Vegetables> } - ошибка - компилятор не знает размеров всех объектов с таким трейтом, НО
можно сделать струтктуру указателей
struct Salad {veggies: Vec<Box<Vegetables>> }
-
объект характеристики это на самом деле толстый указатель. на сам объект 1 машинное слово и 1 на место, на реализацию метода
Параметрические или Универсальные функции.
Не совсем понятно чем отличаются от просто функций с указанием Трейта. используются бля более явного ограничения типа как я понял
fn top_ten<T: Debug + Hash + Eq>(values: &Vec<T>){} - только типы реализаующие все трейты
есть вариант со словом where если параметров слишком много
fn run_query<M,R>(data: &DataSet, map: M, reduce: R) -> Results
where M: Mapper + Serialize,
R: Reducer + Serialize
{........}
Также параметры можно пихать вместе с временем жизни
fn nearest<'t, 'c, P>(target: &'t P, candidates: &'c [P]) -> *'c P
where P : Write
Универсальные функции выбирают чаще - из плюсов - скорость
Второе - не у всего есть объект - например статические функции
-
Если в трейте использовано Self, то это трейт дельзя использовать как характеристику объекта в функциях
impl Splicebla for x(&self) -> Self
impl Splicebale foy y(&self) -> Self
fn splice(z: &Splicable, h: &Splicebalr) {let j = z.splice(h)} Ошибка
-
можно сделать дефолтную реализацию pub trait Summary { fn summarize(&self) -> String { String::from("(Read more...)") }}
-
-
если нужно чтобы оба параметра имели и один тип и имплементацию трейта pub fn notify<T: Summary>(item1: &T, item2: &T) {
возможно указывать несколько типажей
pub fn notify(item: &(impl Summary + Display)) {
pub fn notify<T: Summary + Display>(item: &T) {
есть альтернативный синтаксиси, если много всего так обозначено
fn some_function<T, U>(t: &T, u: &U) -> i32 where T: Display + Clone, U: Clone + Debug, {
Dyn - ключевое слово для того, чтобы указать в типе трейт. частый вариант Box<dyn имя_трейта>
ограничения типажей для обобщённых типов VS типаж-объектов - разница , что в первом случае будет мономорфизация - коммпилятор склонирует все функции как надо.
крейты, модули
-
в корневом крейте может быть несколько бинарных крейтов, но только 1 библиотечный
модуль можно хранить или в файле с таим же названием,или в папке с названием и файле mod
mymodule.rs или
mymodule/mod.rs
-
Workspace - это набор пакетов, которые используют один и тот же Cargo.lock и директорию для хранения результатов компиляции.
-
Типы данных
Перечисления
Можно указывать какие именно числа использовать в памяти для перечислений
enum HttpStatus {
Ok = 200,
Not Modified = 304}
-
-
-
с помощью перечислений в раст достаточно легко реализовывать структуры данных типа бинарного дерева или JSON схемы
в перечислениях можно передавать в управлющий код ссылки и мутабельные ссылки
match x {
OK(ref mut line) => {do(line)},
Но можно также и матчить то, что является ссылкой сами ссылки
match x {
&Point {x,y,z} => ...} // для любой ссылки содержащей казание на поинт с координатами
передавая по ссылке значение не имеющще копи надо указывать ссылку
match x {
Some(&Car {ref engine} ..) - ok
Some(&Car {engine} ..) - ошибка
можно делать if в матче {
Some(x) if x < 0 => ..,
Somex => ,,,}
Но только без передачи значения
-
enum Message { Move { x: i32, y: i32 } }
Коллекции
Кортеж - может хранить разные типы данных, но не меняется в размерах
let tup: (i32, f64, u8) = (500, 6.4, 1);
кортеж в переменные - деструктуризацией,
let (x, y, z) = tup;
-
-
-
Вектор
Нельзя добавлять в вектор, если есть живые ссылки на любой его элемент
если нужен вектор для хранений значений разных типов, то можно сделать вектор из enum
Hashmap
-
-
Варианты вставки значений
- затереть старое scores.insert(String::from("Blue"), 10);
- вставить, только если раньше такого не было scores.entry(String::from("Blue")).or_insert(50);
- сделать новое на основе старого
let count = map.entry(word).or_insert(0);
*count += 1;
по умолчанию кеширование идет через siphash, который считается безопасным, но это можно заменить
-
Строки и срезы
функция принимающая на вход срез от строки, может также и обрабатывать и String. т.е. следует писать идиоматически
fn first_word(s: &str) -> &str {
вместо
fn first_word(s: &String) -> &str {
-
в раст у строк нельзя взять индекс.поскольку для части букв они будут 1 байт, для други два, а в некоторых случаях будут т.н. кластеры графем, когда несколько символов образуют один.
все это делает взятие индекса многозначным, что именно нужно взять.
а также стандартное время индексирования обычно считается O(1) , а в данном случае этого не получится добиться
срезы возвращают байты, а не символы
let hello = "Здравствуйте";
let s = &hello[0..4];
вернет Зд
-
Структуры
Изменяемой или нет может быть вся структура, но не отдельные поля
если нужно сделать копию структуры, лишь с некоторыми изменёнными полями, то есть синтаксис обновления структуры
user2 = User {
email: String::from("something"),
..user1}
Однако стоит быть осторожным. Поскольку если у user1 есть хоть одно заимствование без типажа Copy - это сделает user1 недействительным
кортежные структуры - те в которых поля не именуются. прост опереименованные кортежи, к которым можно напихать методов
единичные структуры, они же юнит структуры, не имеют данных
struct AlwaysEqual;
Нужны затем, чтобы ...
- когда надо реализовать трейт, для чего-то не имеющего полей
- когда нужно указать конкретный тип, но не нужно указывать данных. например
struct EndOfStream
fn ... -> Result<String, endofStream> - теперь есть конкретный тип для обработки ошибки, и нам не нужна строка
-