rust 我可以拥有一个特征对象的集合,在该集合中,特征对象的关联类型实现了一个共享特征吗?

w8ntj3qf  于 2022-12-19  发布在  其他
关注(0)|答案(1)|浏览(120)

我知道 * 通常 * 您不能使用Vec<dyn Iterator>>之类的类型,因为您当然需要指定关联的类型。
现在,我当然可以有Vec<Box<dyn Iterator<Item=i32>>>
但是像这样的事情呢:

trait Foo {}

#[derive(Clone)]
struct Bla;
impl Foo for Bla {}

#[derive(Clone)]
struct Bar;
impl Foo for Bar {}

fn main () {
    // this works of course
    let x: Vec<Box<dyn Iterator<Item=i32>>> = vec![];
    
    // this can be defined
    let mut y: Vec<Box<dyn Iterator<Item=Box<dyn Foo>>>> = vec![];
    
    // but how do I use it? these don't work
    let first_it = Box::new(std::iter::repeat(Box::new(Bar{})));
    let second_it = Box::new(std::iter::repeat(Box::new(Bla{})).take(10));
    
    y.push(first_it);
    y.push(second_it);
}

编译器抱怨:

expected `std::iter::Repeat<Box<Bar>>` to be an iterator that yields `Box<dyn Foo>`, but it yields `Box<Bar>`

显然,尽管Bar实现了Foo,但Box<Bar>不被认为是Box<dyn Foo>的可接受子类型。
我知道Rust没有其他语言所具有的超高阶关联类型,我所尝试做的是根本不可能的还是Rust不支持?
在我看来,使用y不应该有一个 * 固有的 * 类型问题,它包含的所有元素都将是产生某些项的迭代器,所有这些项都将实现相同的trait,Foo
或者我只是在 * 创建 * trait对象时做错了什么?

osh3o9ms

osh3o9ms1#

Iterator<Item=Box<Bar>>Iterator<Item=Box<dyn Foo>>之间存在结构不兼容性。如果您不知道,Box<Bar>的大小与Box<dyn Foo>不同(内部单指针与两个指针)。
您可以将Box<Bar>转换(或者更确切地说是强制转换)为Box<dyn Foo>,因为Bar实现了Foo,但是您不能将Iterator<Item=Box<Bar>>冒充为Iterator<Item=Box<dyn Foo>>,因为需要有一个地方来进行转换。
所以,是的,你可以拥有这样一个集合,但是你需要主动地使用正确的trait对象:

let mut y: Vec<Box<dyn Iterator<Item=Box<dyn Foo>>>> = vec![];

let first_it = Box::new(std::iter::repeat(Box::new(Bar{})).map(|b| b as Box<dyn Foo>));
let second_it = Box::new(std::iter::repeat(Box::new(Bla{})).map(|b| b as Box<dyn Foo>).take(10));

y.push(first_it);
y.push(second_it);

相关问题