generics - 为什么在特征实现上发送的特征边界被忽略?
问题描述
Send
为什么忽略 trait 实现上的 auto trait的 trait bound?(游乐场(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
(或一般的自动特征)被特殊处理。但是,我还没有找到任何关于此的文档。这是一个错误还是只是我缺乏理解:-)?
解决方案
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 T: 'static
由于TypeId
限制,添加了一个要求。这不应该影响我们的回答,因为Rc<i32>
和i32
都是'static
。
可以看出,T
被解析为,i32
而不是Rc<i32>
。也就是说,用而不是is_send
调用。T = i32
T = Rc<i32>
这是因为Rc<T>
实现Deref<Target = T>
. 调用i.is_send()
的时候,其实就等价于(*i).is_send()
, and*i
是 an i32
,也就是 a Send
。当您使用点运算符调用值的方法时,编译器会尝试执行取消引用,直到满足类型边界。
为了展示这一点,让我们尝试更改Rc
为Arc
, where Arc
implements Send
。您可以看到现在具有与而不是T
相同的 TypeId 。这是因为已经满足了界限,不需要进一步的解除引用。Arc<i32>
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 }
推荐阅读
- reactjs - 如何使用 onClick 转到另一个页面?
- android - 如何从 recyclerView 的 onClickListener 的活动中打开片段
- javascript - sum += hand[i] 有效, sum += handNew[i] 无效 - 为什么?
- sublimetext3 - 如何使用 SublimeText2 或 SublimeText3 在新行的字符串中自动添加增加的数字?
- node.js - 谷歌“一键式”,tokeninfo 端点 404
- c - 条件跳转或移动 - Valgrind
- classcastexception - Opendaylight netconf get-config 在 opendaylight 自定义功能上返回 ClassCastException
- java - 如何在 Java 的 Eclipse 控制台上使用 system.out 以粗体打印消息?
- python - Bokeh - 单击点时创建固定标签
- php - 命名空间无法正确解析