let rc_b: Rc<String> = Rc::clone(&rc_a);
println!("Количество ссылок на rc_b: {}", Rc::strong_count(&rc_b));
println!("Количество ссылок на rc_a: {}", Rc::strong_count(&rc_a));
// Два `Rc` равны, если равны их внутренние значения
println!("rc_a и rc_b равны: {}", rc_a.eq(&rc_b));
// Мы можем напрямую использовать методы внутреннего значения
println!("Размер значения внутри rc_a: {}", rc_a.len());
println!("Значение rc_b: {}", rc_b);
println!("--- rc_b удаляется ---");
}
println!("Количество ссылок на rc_a: {}", Rc::strong_count(&rc_a));
println!("--- rc_a удаляется ---");
}
// Ошибка! `rc_examples` уже перемещена в `rc_a`
// И когда `rc_a` удалилась, `rc_examples` удалилась вместе с ней
// println!("rc_examples: {}", rc_examples);
// TODO ^ Попробуйте удалить комментарий эту строку
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Многие другие типы предоставляются стандартной библиотекой для вспомогательных целей, например:
• Потоки
• Каналы
• Операции файлового ввода/вывода
Они расширяют возможности, которые предоставляют примитивы.
примитивы и стандартная библиотека
Rust предоставляет механизм для создания собственных потоков операционной системы через функцию spawn. Аргументом этой функции является замыкание, которое принимает владение захваченным ею окружением.
use std::thread;
static NTHREADS: i32 = 10;
// Это главный поток `main`
fn main() {
// Создаём вектор дочерних потоков.
let mut children = vec![];
for i in 0..NTHREADS {
// Создаём очередной поток
children.push(thread::spawn(move || {
println!("этот поток номер {}", i);
}));
}
for child in children {
// Ждём пока поток завершится и вернёт результат.
let _ = child.join();
}
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Эти потоки будут запланированы ОС.
Rust позволяет очень легко распределить обработку данных между потоками, без головной боли, традиционно связанной с попыткой сделать это.
Стандартная библиотека предоставляет отличные примитивы для работы потоками из коробки. Они в сочетании с концепцией владения и правилами алиасинга в Rust, автоматически предотвращают гонки данных.
Правила алиасинга (одна уникальная ссылка на запись или много ссылок на чтение) автоматически не позволяет вам манипулировать состоянием, которое видно другим потокам. (Где синхронизация необходима, есть примитивы синхронизации, такие как mutex (мьютексы) или channel (каналы).)
В этом примере мы вычислим сумму всех цифр в блоке чисел. Мы сделаем это, разбив куски блока на разные потоки. Каждый поток будет суммировать свой крошечный блок цифр, и впоследствии мы будем суммировать промежуточные суммы, полученные каждым потоком.
Обратите внимание на то, что хоть мы и передаём ссылки через границы потоков, Rust понимает, что мы только передаём неизменяемые ссылки, которые можно только читать, и что из-за этого не может быть никакой небезопасности и гонок данных. Так как мы перемещаем (move) сегменты данных в поток, Rust также уверен, что данные будут жить до тех пор, пока поток не завершится, и висящих указателей не появится.