为什么 Send on trait implementations 的 trait bounds 被忽略?
Why are trait bounds for Send on trait implementations ignored?
为什么特征实现上自动特征 Send
的特征边界被忽略? (Playground(1))
trait IsSend {
fn is_send(&self);
}
impl<T: Send> IsSend for T {
fn is_send(&self) {}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let i = std::rc::Rc::new(43);
i.is_send(); // (!!) no compiler error although Rc<...> is not Send
Ok(())
}
例如,为自定义特征 (X) 使用特征绑定它有效:
(Playground(2))
trait X {}
trait IsSend {
fn is_send(&self);
}
impl<T: X> IsSend for T {
fn is_send(&self) {}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let i = std::rc::Rc::new(43);
i.is_send(); // (ok) compiler error as Rc<...> does not implement X
Ok(())
}
更令人困惑的是,在函数上使用特征绑定它按预期工作:(Playground(3))
fn is_send<T: Send>(_s: &T) {}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let i = std::rc::Rc::new(43);
is_send(&i); // (ok) compiler as Rc<...> is not Send
Ok(())
}
看起来自动特征 Send
(或一般的自动特征)被特殊对待。但是,我还没有找到任何关于此的文档。这是一个错误还是我不理解 :-)?
看看this slightly modified version of your playground
use std::any::TypeId;
trait IsSend {
fn is_send(&self);
}
impl<T: Send + 'static> IsSend for T {
fn is_send(&self){
println!("TypeId of T: {:?}", TypeId::of::<T>());
}
}
fn main() -> Result<(),Box<dyn std::error::Error>> {
println!("TypeId of i32: {:?}", TypeId::of::<i32>());
println!("TypeId of Rc<i32>: {:?}", TypeId::of::<std::rc::Rc<i32>>());
let i = std::rc::Rc::new(43);
i.is_send(); // (!!) no compiler error although Rc is not Send
Ok(())
}
我们得到了结果:
TypeId of i32: TypeId { t: 13431306602944299956 }
TypeId of Rc<i32>: TypeId { t: 1918842018359854094 }
TypeId of T: TypeId { t: 13431306602944299956 }
我改了:
- 添加了一些
println!
调用以便我们可以看到类型的 TypeId
- 由于
TypeId
限制,添加了一项要求 T: 'static
。这不应该影响我们的答案,因为 Rc<i32>
和 i32
都是 'static
.
可以看出T
解析为i32
而不是Rc<i32>
。也就是说,is_send
是用 T = i32
调用的,而不是 T = Rc<i32>
.
这是因为Rc<T>
implements Deref<Target = T>
。当你调用i.is_send()
时,它实际上相当于(*i).is_send()
,而*i
是一个i32
,是一个Send
。当您使用点运算符对值调用方法时,编译器会尝试执行取消引用,直到满足类型界限。
为了展示这一点,让我们 try changing Rc
to Arc
,其中 Arc
实现 Send
。您可以看到 T
现在具有与 Arc<i32>
相同的 TypeId 而不是 i32
。这是因为 Arc
已经满足 T: Send
界限,不需要进一步取消引用。
use std::any::TypeId;
use std::sync::Arc;
trait IsSend {
fn is_send(&self);
}
impl<T: Send + 'static> IsSend for T {
fn is_send(&self){
println!("TypeId of T: {:?}", TypeId::of::<T>());
}
}
fn main() -> Result<(),Box<dyn std::error::Error>> {
println!("TypeId of i32: {:?}", TypeId::of::<i32>());
println!("TypeId of Arc<i32>: {:?}", TypeId::of::<Arc<i32>>());
let i = Arc::new(43);
i.is_send(); // (!!) no compiler error although Rc is not Send
Ok(())
}
TypeId of i32: TypeId { t: 13431306602944299956 }
TypeId of Arc<i32>: TypeId { t: 3504454246784010795 }
TypeId of T: TypeId { t: 3504454246784010795 }
为什么特征实现上自动特征 Send
的特征边界被忽略? (Playground(1))
trait IsSend {
fn is_send(&self);
}
impl<T: Send> IsSend for T {
fn is_send(&self) {}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let i = std::rc::Rc::new(43);
i.is_send(); // (!!) no compiler error although Rc<...> is not Send
Ok(())
}
例如,为自定义特征 (X) 使用特征绑定它有效: (Playground(2))
trait X {}
trait IsSend {
fn is_send(&self);
}
impl<T: X> IsSend for T {
fn is_send(&self) {}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let i = std::rc::Rc::new(43);
i.is_send(); // (ok) compiler error as Rc<...> does not implement X
Ok(())
}
更令人困惑的是,在函数上使用特征绑定它按预期工作:(Playground(3))
fn is_send<T: Send>(_s: &T) {}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let i = std::rc::Rc::new(43);
is_send(&i); // (ok) compiler as Rc<...> is not Send
Ok(())
}
看起来自动特征 Send
(或一般的自动特征)被特殊对待。但是,我还没有找到任何关于此的文档。这是一个错误还是我不理解 :-)?
看看this slightly modified version of your playground
use std::any::TypeId;
trait IsSend {
fn is_send(&self);
}
impl<T: Send + 'static> IsSend for T {
fn is_send(&self){
println!("TypeId of T: {:?}", TypeId::of::<T>());
}
}
fn main() -> Result<(),Box<dyn std::error::Error>> {
println!("TypeId of i32: {:?}", TypeId::of::<i32>());
println!("TypeId of Rc<i32>: {:?}", TypeId::of::<std::rc::Rc<i32>>());
let i = std::rc::Rc::new(43);
i.is_send(); // (!!) no compiler error although Rc is not Send
Ok(())
}
我们得到了结果:
TypeId of i32: TypeId { t: 13431306602944299956 }
TypeId of Rc<i32>: TypeId { t: 1918842018359854094 }
TypeId of T: TypeId { t: 13431306602944299956 }
我改了:
- 添加了一些
println!
调用以便我们可以看到类型的 TypeId - 由于
TypeId
限制,添加了一项要求T: 'static
。这不应该影响我们的答案,因为Rc<i32>
和i32
都是'static
.
可以看出T
解析为i32
而不是Rc<i32>
。也就是说,is_send
是用 T = i32
调用的,而不是 T = Rc<i32>
.
这是因为Rc<T>
implements Deref<Target = T>
。当你调用i.is_send()
时,它实际上相当于(*i).is_send()
,而*i
是一个i32
,是一个Send
。当您使用点运算符对值调用方法时,编译器会尝试执行取消引用,直到满足类型界限。
为了展示这一点,让我们 try changing Rc
to Arc
,其中 Arc
实现 Send
。您可以看到 T
现在具有与 Arc<i32>
相同的 TypeId 而不是 i32
。这是因为 Arc
已经满足 T: Send
界限,不需要进一步取消引用。
use std::any::TypeId;
use std::sync::Arc;
trait IsSend {
fn is_send(&self);
}
impl<T: Send + 'static> IsSend for T {
fn is_send(&self){
println!("TypeId of T: {:?}", TypeId::of::<T>());
}
}
fn main() -> Result<(),Box<dyn std::error::Error>> {
println!("TypeId of i32: {:?}", TypeId::of::<i32>());
println!("TypeId of Arc<i32>: {:?}", TypeId::of::<Arc<i32>>());
let i = Arc::new(43);
i.is_send(); // (!!) no compiler error although Rc is not Send
Ok(())
}
TypeId of i32: TypeId { t: 13431306602944299956 }
TypeId of Arc<i32>: TypeId { t: 3504454246784010795 }
TypeId of T: TypeId { t: 3504454246784010795 }