我试着把我的问题提炼成一个最小的例子。在下面的函数中,如果我有if语句的任何一个分支,程序就会编译得很好。
fn foo(bar: bool) -> impl Iterator<Item = u32> {
if bar {
vec![].into_iter()
} else {
vec![].into_iter().map(|o| o)
}
}但是,正如我前面所写的,将两个分支放在一起会导致以下错误:
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:5:9
|
2 | / if bar {
3 | | vec![].into_iter()
| | ------------------ expected because of this
4 | | } else {
5 | | vec![].into_iter().map(|o| o)
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::vec::IntoIter`, found struct `Map`
6 | | }
| |_____- `if` and `else` have incompatible types
|
= note: expected struct `std::vec::IntoIter<_>`
found struct `Map<std::vec::IntoIter<_>, [closure@src/main.rs:5:32: 5:37]>`
For more information about this error, try `rustc --explain E0308`.根据我的理解,问题是,即使声明的返回类型是impl Iterator,编译器也必须选择要使用的具体类型。虽然if语句的两个分支都生成一个类型为impl Iterator的值,但它们是不同的具体类型。但是,我不知道我能用什么具体的类型来解决这个问题。
发布于 2022-08-11 15:48:01
你是对的。impl不是一种可以永久隐藏实现的万能解决方案。这只是一个方便的语法,这样程序员就不必考虑返回类型了。但是仍然必须存在一种唯一的返回类型。
现在,您可以(我不建议这样)编写一个enum,它可以是两种迭代器类型之一。
// Pseudocode, I'm not looking up the actual types because they're complicated
enum MyIterator {
IsVectorIterator(Vec::Iter<u32>),
IsMapIterator(iter::Map<Vec::Iter<u32>, u32, ...>),
}然后,您可以为这种类型编写一个Iterator实现,它将委托给内部的任何东西。这是大量的工作和大量的样板,特征对象将为我们做这件事。
我建议您从函数返回Box<dyn Iterator<Item=u32>>。
fn foo(bar: bool) -> Box<dyn Iterator<Item = u32>> {
if bar {
Box::new(vec![].into_iter())
} else {
Box::new(vec![].into_iter().map(|o| o))
}
}这是一个动态特性对象,所以我们在运行时才知道具体类型是完全可以接受的。它确实需要动态分派(因为属性对象必须记住如何迭代),但这是一个非常便宜的成本,以换取不必显式地处理类型。
注意,根据谁拥有输入向量(在您的示例中,它是一个临时的vec![],但我在实际代码中设想它是一个具有终生的参数),您的dyn可能必须有一个终身参数,如
Box<dyn Iterator<Item = u32> + 'a>其中'a是输入向量的生存期。
https://stackoverflow.com/questions/73323490
复制相似问题