特征对象的 Rust 向量的类型推断不正确

Incorrect type inference for Rust vector of trait object

我无法理解以下错误:

// test.rs

struct A {
    a: u32
}

trait B { }

impl B for A { }

struct C {
    c: Vec<Box<dyn B>>,
}

fn test() {
    let a = A {a: 1};
    let a_vec = vec![Box::new(a)];
    let c = C {
        c: a_vec,
        // c: vec![Box::new(a)],
    };
}

编译错误:

mismatched types

expected trait object `dyn test::B`, found struct `test::A`

错误发生在我尝试创建 C 的那一行。有趣的是,如果我按以下方式创建 C,那么它可以正常编译。

let c = C {
        c: vec![Box::new(a)],
    };

另一种可行的方法是

let a_vec: Vec<Box<dyn B>> = vec![Box::new(a)];
let c = C {
        c: a_vec,
    };

我做的另一个实验是将 C.c 的类型更改为 Box 而不是 Vec,然后无论我如何启动它它都会编译。

在我看来,这可能是 Rust 关于特征对象向量的类型推断的一些缺失 feature/bug?我对 Rust 还是很陌生,所以非常感谢任何关于此的想法!

这都是预期的行为。 Box<A> 可以强制转换为 Box<dyn B>——这称为 unsized coercion,只要编译器知道目标类型是 Box<dyn B>,它就会隐式发生。然而,当刚写

let a_vec = vec![Box::new(a)];

编译器不知道向量的项目类型,因此它从右侧的表达式推断出它,这意味着 a_vecVec<Box<A>> 类型结束。

Vec<Box<A>>Vec<Box<dyn B>> 没有未定大小的强制转换。将 Box<A> 转换为 Box<dyn B> 只是将指针转换为堆栈上的胖指针,这是一种廉价操作。转换这些元素的向量是非常不同的——它需要重新分配整个向量并调整每个元素的大小,这是一个相当昂贵的操作,所以它不应该隐式地发生。

在所有实际编译的版本中,向量从一开始就被创建为 Vec<Box<dyn B>>,因为您告诉编译器这是您想要的类型。