gpt4 book ai didi

generics - 为什么 Send on trait implementations 的 trait bounds 被忽略?

转载 作者:行者123 更新时间:2023-11-29 07:45:44 24 4
gpt4 key购买 nike

为什么自动特征 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) 使用特征绑定(bind)它有效:( 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(())
}

更令人困惑的是,在它按预期工作的函数上使用特征绑定(bind):( 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(())
}

看起来 auto trait Send(或一般的 auto traits)被特殊对待。但是,我还没有找到任何关于此的文档。这是错误还是只是我不理解 :-)?

最佳答案

看看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
  • 添加了一个要求 T: 'static , 由于 TypeId约束。这不应该影响我们的答案,因为 Rc<i32>i32'static .

可以看出T解析为 i32而不是 Rc<i32> .即 is_sendT = 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绑定(bind),并且不需要进一步取消引用。

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 }

关于generics - 为什么 Send on trait implementations 的 trait bounds 被忽略?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57442126/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com