Трейт Send
Трейт Send - это маркерный трейт, который
сообщает компилятору, что значение типа можно
безопасно перемещать в другой поток. Тип реализует
Send автоматически, если все его поля также
являются Send. Трейт не содержит методов и
используется как ограничение в дженериках и
многопоточных примитивах, например в
thread::spawn.
Параметров у трейта нет, так как это маркерный трейт без методов. Основное применение - указывать компилятору и функциям, что значение можно передавать между потоками.
Синтаксис
pub unsafe auto trait Send { }
// as a bound
fn foo<T: Send>(value: T) { }
Пример
Давайте передадим значение типа i32 в
другой поток. Такой тип реализует Send
автоматически, поэтому код компилируется:
use std::thread;
fn main()
{
let value = 12345;
let handle = thread::spawn(move || {
println!("{}", value);
});
handle.join().unwrap();
}
Результат выполнения кода:
12345
Пример
Давайте попробуем передать в поток значение типа
Rc<i32>. Тип Rc не реализует
Send, поэтому такой код не скомпилируется:
use std::rc::Rc;
use std::thread;
fn main()
{
let value = Rc::new(12345);
let handle = thread::spawn(move || {
println!("{}", value);
});
handle.join().unwrap();
}
Компилятор выдаст ошибку:
error[E0277]: `Rc<i32>` cannot be sent between threads safely
Пример
Давайте напишем дженерик-функцию с ограничением
T: Send и вызовем её для типа i32
и для типа String. Оба типа реализуют
Send:
fn check_send<T: Send>(value: T) -> T
{
value
}
fn main()
{
let a = check_send(12345);
let b = check_send(String::from("abcde"));
println!("{}", a);
println!("{}", b);
}
Результат выполнения кода:
12345
"abcde"
Пример
Давайте реализуем Send вручную через
unsafe impl для собственной обёртки. Такой
код снимает автоматическую проверку компилятора
и требует уверенности в безопасности:
struct MyBox<T>(T);
unsafe impl<T: Send> Send for MyBox<T> { }
use std::thread;
fn main()
{
let value = MyBox(12345);
let handle = thread::spawn(move || {
println!("{}", value.0);
});
handle.join().unwrap();
}
Результат выполнения кода:
12345
Смотрите также
-
трейт
Sync,
который разрешает доступ к значению из нескольких потоков -
трейт
Sized,
который указывает на известный размер типа на этапе компиляции -
трейт
Trait Bound,
который задаёт ограничения на дженерик-параметры -
трейт
impl Trait,
который позволяет указывать трейт в возвращаемом типе