复制 std::thread::spawn 和 Send 行为,但具有不同的特征和功能
Copying std::thread::spawn and Send behavior, but with a different trait and function
我正在学习 Rust 并 运行 解决了以下问题,这对我来说并不明显。
我在库中看到 std::thread::spawn,查看了实现,发现某些类型需要 Send 特性的实现才能将某些内容发送到另一个线程。
我试图用我自己的函数和我自己的特征复制行为,但编译器成功编译了代码,而没有抱怨没有为我的类型实现特征。
我错过了什么?
pub trait SomeTrait {
fn bar(&self);
}
#[derive(Debug)]
struct StructWithoutTrait {
_data: Box<i32>
}
#[derive(Debug)]
struct StructWithTrait {
_data: Box<i32>
}
impl SomeTrait for StructWithTrait {
fn bar(&self) {}
}
fn foo<F, T>(f: F) -> T
where
F: FnOnce() -> T,
F: SomeTrait + 'static,
T: SomeTrait + 'static
{
f.bar();
f()
}
impl<F, T> SomeTrait for F
where
F: FnOnce() -> T,
T: SomeTrait
{
fn bar(&self) {}
}
fn main() {
let without_trait = StructWithoutTrait { _data: Box::new(1) };
let with_trait = StructWithTrait { _data: Box::new(2) };
let x = std::rc::Rc::new(1);
foo(move || {
println!("{:?}", without_trait);
println!("{:?}", x);
with_trait
});
}
我很确定这是编译器行为:
A closure is Send if all variables captured by non-unique immutable reference are Sync, and all values captured by unique immutable or mutable reference, copy, or move are Send.
~https://doc.rust-lang.org/reference/types/closure.html
因此,由于闭包类型是完全不透明的,因此您现在无法真正实现它
目前Send
由编译器专门处理。引用自 the documentation:
This trait is automatically implemented when the compiler determines it’s appropriate.
有plans to move the implementation fully into the standard library (tracking issue),这应该使得具有相似的用户定义标记特征成为可能。有可能当此功能稳定后您可以编写:
auto trait SomeTrait {}
struct StructWithTrait {}
struct StructWithoutTrait {}
impl !SomeTrait for StructWithoutTrait {}
并获得类似于 Send
的行为。
Send
是 an auto
trait。 Auto-traits 有点像编译器实现的;确定类型 T
是否实现自动特征 AutoTrait
的步骤如下:
- 如果有明确的
impl AutoTrait for T
,那么T
总是impls AutoTrait
(注意因为Send
is an unsafe trait
你需要unsafe impl Send for T
,但是总的原则保持不变)。
- 否则,如果有负面影响
impl !AutoTrait for T
,则T
不会实现AutoTrait
。请注意,对于同一类型的同一特征同时具有正面和负面影响是错误的。
- 否则,如果
T
的任何字段没有实现AutoTrait
,T
也不会实现它。例如,如果T
定义为struct T(U);
,并且有impl !AutoTrait for U
,那么T
并没有实现AutoTrait
。
- 否则,
T
实施 AutoTrait
。
auto traits 和 negative impls 都是高度不稳定的特性,目前不打算在标准库之外使用。如果你真的想要,你可以,尽管因为编译器必须能够自动实现特征,它不能包含任何关联项(方法、关联类型、关联常量)。如果您删除 bar()
方法,您的代码将如下所示:
#![feature(auto_traits, negative_impls)]
pub auto trait SomeTrait {}
#[derive(Debug)]
struct StructWithoutTrait {
_data: Box<i32>
}
impl !SomeTrait for StructWithoutTrait {}
#[derive(Debug)]
struct StructWithTrait {
_data: Box<i32>
}
fn foo<F, T>(f: F) -> T
where
F: FnOnce() -> T,
F: SomeTrait + 'static,
T: SomeTrait + 'static
{
f()
}
fn main() {
let without_trait = StructWithoutTrait { _data: Box::new(1) };
let with_trait = StructWithTrait { _data: Box::new(2) };
let x = std::rc::Rc::new(1);
foo(move || {
println!("{:?}", without_trait);
println!("{:?}", x);
with_trait
});
}
我正在学习 Rust 并 运行 解决了以下问题,这对我来说并不明显。 我在库中看到 std::thread::spawn,查看了实现,发现某些类型需要 Send 特性的实现才能将某些内容发送到另一个线程。 我试图用我自己的函数和我自己的特征复制行为,但编译器成功编译了代码,而没有抱怨没有为我的类型实现特征。 我错过了什么?
pub trait SomeTrait {
fn bar(&self);
}
#[derive(Debug)]
struct StructWithoutTrait {
_data: Box<i32>
}
#[derive(Debug)]
struct StructWithTrait {
_data: Box<i32>
}
impl SomeTrait for StructWithTrait {
fn bar(&self) {}
}
fn foo<F, T>(f: F) -> T
where
F: FnOnce() -> T,
F: SomeTrait + 'static,
T: SomeTrait + 'static
{
f.bar();
f()
}
impl<F, T> SomeTrait for F
where
F: FnOnce() -> T,
T: SomeTrait
{
fn bar(&self) {}
}
fn main() {
let without_trait = StructWithoutTrait { _data: Box::new(1) };
let with_trait = StructWithTrait { _data: Box::new(2) };
let x = std::rc::Rc::new(1);
foo(move || {
println!("{:?}", without_trait);
println!("{:?}", x);
with_trait
});
}
我很确定这是编译器行为:
A closure is Send if all variables captured by non-unique immutable reference are Sync, and all values captured by unique immutable or mutable reference, copy, or move are Send.
~https://doc.rust-lang.org/reference/types/closure.html
因此,由于闭包类型是完全不透明的,因此您现在无法真正实现它
目前Send
由编译器专门处理。引用自 the documentation:
This trait is automatically implemented when the compiler determines it’s appropriate.
有plans to move the implementation fully into the standard library (tracking issue),这应该使得具有相似的用户定义标记特征成为可能。有可能当此功能稳定后您可以编写:
auto trait SomeTrait {}
struct StructWithTrait {}
struct StructWithoutTrait {}
impl !SomeTrait for StructWithoutTrait {}
并获得类似于 Send
的行为。
Send
是 an auto
trait。 Auto-traits 有点像编译器实现的;确定类型 T
是否实现自动特征 AutoTrait
的步骤如下:
- 如果有明确的
impl AutoTrait for T
,那么T
总是implsAutoTrait
(注意因为Send
is anunsafe trait
你需要unsafe impl Send for T
,但是总的原则保持不变)。 - 否则,如果有负面影响
impl !AutoTrait for T
,则T
不会实现AutoTrait
。请注意,对于同一类型的同一特征同时具有正面和负面影响是错误的。 - 否则,如果
T
的任何字段没有实现AutoTrait
,T
也不会实现它。例如,如果T
定义为struct T(U);
,并且有impl !AutoTrait for U
,那么T
并没有实现AutoTrait
。 - 否则,
T
实施AutoTrait
。
auto traits 和 negative impls 都是高度不稳定的特性,目前不打算在标准库之外使用。如果你真的想要,你可以,尽管因为编译器必须能够自动实现特征,它不能包含任何关联项(方法、关联类型、关联常量)。如果您删除 bar()
方法,您的代码将如下所示:
#![feature(auto_traits, negative_impls)]
pub auto trait SomeTrait {}
#[derive(Debug)]
struct StructWithoutTrait {
_data: Box<i32>
}
impl !SomeTrait for StructWithoutTrait {}
#[derive(Debug)]
struct StructWithTrait {
_data: Box<i32>
}
fn foo<F, T>(f: F) -> T
where
F: FnOnce() -> T,
F: SomeTrait + 'static,
T: SomeTrait + 'static
{
f()
}
fn main() {
let without_trait = StructWithoutTrait { _data: Box::new(1) };
let with_trait = StructWithTrait { _data: Box::new(2) };
let x = std::rc::Rc::new(1);
foo(move || {
println!("{:?}", without_trait);
println!("{:?}", x);
with_trait
});
}