匹配返回迭代器的武器?

时间:2017-01-17 18:32:45

标签: rust matching traits trait-objects

我有一些尝试运行匹配的代码,其中每个分支都可以返回不同的类型,但所有这些类型都会实现Iterator<Item=usize>

let found: Iterator<Item = usize> = match requirements {
    Requirements::A => MatchingAs { ainternals: [] },
    Requirements::B => MatchingBs { binternals: [] },
    Requirements::C => MatchingCs { cinternals: [] },
};

return found.any(|m| m == 1)

...其中MatchingAsMatchingBsMatchingCs所有impl std::iter::Iterator<Item = usize>

我因为Iterator不是大小而撞墙:

    | the trait `std::marker::Sized` is not implemented for `std::iter::Iterator<Item=usize>`

是否有一种很好的方法让匹配臂返回具有共享特征的对象,然后在处理结果时依赖(仅)特征?

1 个答案:

答案 0 :(得分:4)

当你想要返回非Sized的东西时,第一个反射就是Box它(也就是说,把它放在堆上,返回一个指针):

let found: Box<Iterator<Item = usize>> = match requirements {
    Requirements::A => Box::new(MatchingAs { ainternals: [] }),
    Requirements::B => Box::new(MatchingBs { binternals: [] }),
    Requirements::C => Box::new(MatchingCs { cinternals: [] }),
};

found.any(|m| m == 1)

这还不够,因为现在match会抱怨您返回了不同的类型:Box<MatchingAs>Box<MatchingBs>,...

但是,只要有Box<Concrete>Box<Trait>就可以投放到impl Trait for Concrete,所以:

let found = match requirements {
    Requirements::A => Box::new(MatchingAs { ainternals: [] }) as Box<Iterator<Item = usize>>,
    Requirements::B => Box::new(MatchingBs { binternals: [] }) as Box<Iterator<Item = usize>>,
    Requirements::C => Box::new(MatchingCs { cinternals: [] }) as Box<Iterator<Item = usize>>,
};

found.any(|m| m == 1)

但是,有一个无分配的解决方案:使用泛型。

fn search<T: Iterator<Item = usize>>(t: T) -> bool {
    t.any(|m| m == 1)
}

然后将该函数应用于match

的每个分支
match requirements {
    Requirements::A => search(MatchingAs {ainternals: []}),
    Requirements::B => search(MatchingBs {binternals: []}),
    Requirements::C => search(MatchingCs {cinternals: []}),
}

权衡的是它更接近回调 - 地狱,有点间接流动。