Не стоит позволять числу наших потоков быть зависимом от введённых пользователем данных. Что если пользователь решит вставить много пробелов? Мы действительно хотим создать 2000 потоков? Измените программу так, чтобы данные разбивались на ограниченное число блоков, объявленных статической константой в начале программы.
• Потоки
• вектора и итераторы
• замыкания, семантика передачи владения и перемещения (move) в замыканиях
• деструктуризация при присвоениях
• нотация turbofish в помощь механизму вывода типов
• unwrap или expect
Rust предоставляет асинхронные каналы (channel) для взаимодействия между потоками. Каналы обеспечивают однонаправленную передачу информации между двумя конечными точками: отправителем (Sender) и получателем (Receiver).
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;
static NTHREADS: i32 = 3;
fn main() {
// Каналы имеют две конечные точки: Sender<T>` и `Receiver<T>`,
// где `T` - тип передаваемового сообщения.
// (аннотации типов избыточны)
let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
let mut children = Vec::new();
for id in 0..NTHREADS {
// Отправитель может быть скопирован
let thread_tx = tx.clone();
// Каждый поток отправит через канал его id
let child = thread::spawn(move || {
// Поток забирает владение `thread_tx`
// Каждый поток добавляет своё сообщение в очередь канала
thread_tx.send(id).unwrap();
// Отправка - не блокирующая операция, поток незамедлительно
// продолжит работу после отправки сообщения
println!("поток {} завершён", id);
});
children.push(child);
}
// Здесь все сообщения собираются
let mut ids = Vec::with_capacity(NTHREADS as usize);
for _ in 0..NTHREADS {
// Метод `recv` "достаёт" сообщения из канала
// `recv` блокирует текущий поток, если доступных сообщений нет
ids.push(rx.recv());
}
// Ожидаем, когда потоки завершат всю оставшуюся работу
for child in children {
child.join().expect("Упс! Дочерний поток паникует");
}
// Посмотрите порядок, с которым сообщения были отправлeны
println!("{:?}", ids);
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Структура Path представляет пути к файлу в файловой системе. Есть два вида Path: posix::Path, для UNIX - подобных систем, и windows::Path, для Windows. В прелюдии экспортируется соответствующий платформозависимый вариант Path.
Path может быть создан из OsStr, и предоставляет некоторые методы для получения информации о файле или директории, на которые он указывает.
Обратите внимание, что внутренне представление Path не является UTF-8 строкой, но вместо этого хранит вектор байт (Vec<u8>). Следовательно, преобразование Path в &str не бесплатно и может закончиться неудачей (возвращается Option).
use std::path::Path;
fn main() {
// Создаём `Path` из `&'static str`
let path = Path::new(".");
// Метод `display` возвращает показываемую структуру
let _display = path.display();
// `join` соединяет `path` с байтовым контейнером, используя ОС-специфичный
// разделитель, и возвращает новый путь
let new_path = path.join("a").join("b");
// Конвертируем путь в строковый срез
match new_path.to_str() {
None => panic!("новый путь не является действительной UTF-8 последовательностью"),