簡體   English   中英

為什么忽略“按特征發送”實現的特征范圍?

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

為什么忽略自動特征Send到特征實現的特征邊界? 游樂場(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
  • 由於TypeId限制,添加了一個要求T: 'static 這不會影響我們的答案,因為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() ,並且*i是一個i32 ,它是一個Send 當您使用點運算符對值調用方法時,直到滿足類型限制,編譯器才會嘗試執行解引用。

為了說明這一點,讓我們嘗試將Rc更改為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 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM