简体   繁体   English

为什么忽略“按特征发送”实现的特征范围?

[英]Why are trait bounds for Send on trait implementations ignored?

Why are trait bounds for auto trait Send on trait implementations ignored? 为什么忽略自动特征Send到特征实现的特征边界? ( Playground(1) ) 游乐场(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(())
}

For example using a trait bound for a self defined trait (X) it works: ( Playground(2) ) 例如,使用绑定到自定义特征(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(())
}

Even more confusing, using a trait bound on a function it works as expected: ( Playground(3) ) 更令人困惑的是,使用绑定到函数上的特征按预期工作:( 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(())
}

It looks like the auto trait Send (or auto traits in general) is treated specially. 看起来自动特征Send (或通常是自动特征)已得到特别处理。 However, I have not found any documentation about this. 但是,我没有找到任何有关此的文档。 Is this a bug or just my lack of understanding :-)? 这是一个错误还是仅仅是我缺乏理解:-)?

Have a look at 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(())
}

And we have the result: 结果是:

TypeId of i32: TypeId { t: 13431306602944299956 }
TypeId of Rc<i32>: TypeId { t: 1918842018359854094 }
TypeId of T: TypeId { t: 13431306602944299956 }

I changed: 我变了:

  • Added a few println! 增加了一些println! calls so that we can see the TypeId of the types 调用,以便我们可以看到类型的TypeId
  • Added a requirement T: 'static , due to TypeId constraints. 由于TypeId限制,添加了一个要求T: 'static This should not affect our answer, since both Rc<i32> and i32 are 'static . 这不会影响我们的答案,因为Rc<i32>i32均为'static

It can be seen that T is resolved as i32 instead of Rc<i32> . 可以看出, T被解析为i32而不是Rc<i32> That is, is_send is called with T = i32 rather than T = Rc<i32> . 也就是说, is_send调用与T = i32 ,而不是T = Rc<i32>

This is because Rc<T> implements Deref<Target = T> . 这是因为Rc<T>实现Deref<Target = T> When you call i.is_send() , it is actually equivalent to (*i).is_send() , and *i is an i32 , which is a Send . 当您调用i.is_send() ,它实际上等效于(*i).is_send() ,并且*i是一个i32 ,它是一个Send The compiler attempts to perform dereferencing when you use the dot operator to call a method on a value until the type bounds are satisfied. 当您使用点运算符对值调用方法时,直到满足类型限制,编译器才会尝试执行解引用。

To show this, let's try changing Rc to Arc , where Arc implements Send . 为了说明这一点,让我们尝试将Rc更改为Arc ,其中Arc实现Send You can see that T now has the same TypeId as Arc<i32> rather than i32 . 您可以看到T现在具有与Arc<i32>相同的TypeId,而不是i32 This is because Arc already satisfies the T: Send bound, and no further dereferencing is required. 这是因为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 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM