强制将值转换为特质对象的规则是什么?

4
考虑下面的Rust代码:
#[derive(Debug, Clone, Copy)]
struct Struct;
trait Trait {}
impl Trait for Struct {}

fn f() {
    // Why does this coerce to the target type (Result<Box<dyn Trait>, ()>)
    let rbdt: Result<Box<dyn Trait>, ()> = Ok(Box::new(Struct));

    // And this coerces to the target type...
    let a = Box::new(Struct);
    let rbdt: Result<Box<dyn Trait>, ()> = Ok(a);

    // But this does not:
    let a = Ok(Box::new(Struct));
    let rbdt: Result<Box<dyn Trait>, ()> = a; // Error: mismatched types
}

为什么前两个对`rbdt`的赋值能正确地将值强制转换为目标类型(`Result, ()>`),但第三个却不行呢?在我看来,这三种情况下赋值右侧的类型都是`Result, ()>`,所以令人困惑的是为什么有些形式能正常工作,而其他形式会导致类型不匹配的错误。
关于包含特质对象的类型何时可以进行赋值,有哪些规则?这些规则是否有文档记录?
2个回答

4
这里的基本原则是编译器会愉快地将一个 Box<Struct> 强制转换为一个 Box<dyn Trait>,在需要的地方悄悄地插入一个 as。但它需要一个实际的位置来将代码重写为 boxed_struct as BoxedTrait
在第一个例子中,这是可能的:
let rbdt: Result<Box<dyn Trait>, ()> = Ok(Box::new(Struct) as Box<dyn Trait>);

而在第二个:
let a = Box::new(Struct);
let rbdt: Result<Box<dyn Trait>, ()> = Ok(a as Box<dyn Trait>);

但在第三个例子中,没有地方可以进行Box<Struct>Box<Trait>的强制转换。当你尝试给rbdt赋值时,a的类型已经确定为Result<Box<Struct>, ()>,此时再试图重新推断类型为更一般的Result<Box<Trait>, ()>已经太晚了。以下内容不是一个盒子到盒子的强制转换,因此是不允许的。
let rbdt: Result<Box<dyn Trait>, ()> = a as Result<Box<dyn Trait>, ()>;

Box<Struct>-as-Box<Trait>是可以的;对于任何Type来说,Type<Box<Struct>>-as-Type<Box<Trait>>是不可以的。


这个答案可能在技术上更正确,但我觉得关于推理的推理更符合我的直觉,而不是以AST重写的方式思考。 - undefined
@IvanC 我认为我们两个答案结合起来就是一个很好的答案。 - undefined

1
我认为这更多是关于推断,而不是强制。
在前两种情况下,可以立即推断出Result<Box<T>>中的T是与Struct不同的东西,而在第三种情况下,Box<Struct>已经是一个具体的类型,与T = dyn Trait的类型注释在rdbt上引入的要求发生冲突。
此外,我想指出,通常不可能将已经存在的值强制转换为不同类型,尤其是更大的类型,这是因为Box<Struct>Box<dyn Trait>都是由于后者是一个胖指针。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接