如何使用数组填充特征对象向量?

fra*_*low 10 rust

为什么下面的代码会出错?[T; N]into有一个全面的实现Vec<T>,那么为什么在这种情况下dyn Foo不匹配呢?Fooable是否有不涉及克隆的解决方法Fooable

trait Foo {}

struct Fooable {}

impl Foo for Fooable {}

pub fn main() {
    let bar: Vec<Box<dyn Foo>> = [
        Box::new(Fooable {}),
    ].into();
}
Run Code Online (Sandbox Code Playgroud)

错误:

error[E0277]: the trait bound `Vec<Box<dyn Foo>>: From<[Box<Fooable>; 1]>` is not satisfied
  --> src/main.rs:10:7
   |
10 |     ].into();
   |       ^^^^ the trait `From<[Box<Fooable>; 1]>` is not implemented for `Vec<Box<dyn Foo>>`
   |
   = help: the following other types implement trait `From<T>`:
             <Vec<T, A> as From<Box<[T], A>>>
             <Vec<T, A> as From<VecDeque<T, A>>>
             <Vec<T> as From<&[T]>>
             <Vec<T> as From<&mut [T]>>
             <Vec<T> as From<BinaryHeap<T>>>
             <Vec<T> as From<Cow<'a, [T]>>>
             <Vec<T> as From<[T; N]>>
             <Vec<u8> as From<&str>>
           and 2 others
   = note: required because of the requirements on the impl of `Into<Vec<Box<dyn Foo>>>` for `[Box<Fooable>; 1]`
Run Code Online (Sandbox Code Playgroud)

操场

Sil*_*olo 11

你说得对。From<[T; n]>on有一个全面的实现Vec<T>。这意味着您可以使用或转换[T; n]为。Vec<T>From::fromInto::into

更具体地说,这意味着您可以将 a 转换[Box<Fooable>; 1]为 a Vec<Box<Fooable>>,或将 a[Box<dyn Foo>; 1]转换为 a Vec<Box<dyn Foo>>。然而,您有一个[Box<Fooable>; 1]并且想要一个Vec<Box<dyn Foo>>,并且由于T不同,所以毯子impl不适用。

使用显式强制转换来获得您想要的行为。你只需要让 Rust 相信数组的类型是[Box<dyn Foo>; 1],而不是[Box<Fooable>; 1]它最初推断的那样。

let bar: Vec<Box<dyn Foo>> = [
    Box::new(Fooable {}) as Box<dyn Foo>,
].into();
Run Code Online (Sandbox Code Playgroud)


mou*_*ail 9

您可以通过手动转换框来修复错误,如下所示:

trait Foo {}

struct Fooable {}

impl Foo for Fooable {}

pub fn main() {
    let bar: Vec<Box<dyn Foo>> = [
        // Turn a Box<Fooable> into a Box<dyn Foo>
        Box::new(Fooable {}) as Box<dyn Foo>,
    ].into();
}
Run Code Online (Sandbox Code Playgroud)

请记住,默认情况下,Rust 构建会将特征方法调用直接替换为对实现的调用(如果存在)。对象的“类型”仅在编译时存在,在运行时不存在类型。dyn类型不同。它们存储一些额外的数据,以便找到要在运行时调用的方法的实际变体。

为什么直接分配给数组就可以了?

当您像这样定义整数数组时:

// this works
let k:[i8;3] = [1,2,3]
Run Code Online (Sandbox Code Playgroud)

这里没有发生转换。即使默认情况下是数字,i32数组中的数字也将被解释为i8值。

在这种情况下也是一样的:

// this works
let k:[i8;3] = [1,2,3]
Run Code Online (Sandbox Code Playgroud)

从 a 转换V{}为 a需要进行转换,但编译器可以通过从一开始Box<dyn T>就将右侧解释为 a 来避免转换。Box<dyn T>

这也适用于数组,但如果存在一定程度的间接寻址则不行:

// works
let k:[Box<dyn T>;1] = [Box::new(V{})]
// does not work
let b = [Box::new(Fooable {})];
let e:[Box<dyn Foo>;1] = b;
Run Code Online (Sandbox Code Playgroud)

这也是这有效的原因:

let k:Box<dyn T> = Box::new(V{});
Run Code Online (Sandbox Code Playgroud)

即使我们只有as Box<dyn Foo>第一个元素,这也会改变整个数组的解释方式。

  • @frankplow @mousetail 这可能是因为通过 `From` 特征的间接性,它不能隐式地进行强制转换。这就是为什么 `let baz: Box&lt;dyn Foo&gt; = Box::new(Fooable {}).into();` 也不起作用,但 `let bar: [Box&lt;dyn Foo&gt;; 1] = [Box::new(Fooable {})];` 确实如此。 (3认同)