【问题标题】:How do I write the type of an iterator passed to a function?如何编写传递给函数的迭代器类型?
【发布时间】:2016-07-24 19:04:29
【问题描述】:

我正在尝试编写一个解析器,它将一个迭代器通过一个向量传递给一个函数。代码类似这样:

fn foo(itr : ???) {
    while let Some(c) = itr.next() {
        if *c != 0 {
            break;
        }
        println!("{}", *c);
    }
}

fn main() {
    let v = vec![0; 10];
    let itr = v.iter();
    while let Some(c) = itr.next() {
        foo(itr);
    }
}

我不知道如何在向量上写入迭代器的类型。我尝试输入错误的类型 u32 以查看预期的 rustc 类型:core::slice::Iter<'_, _>。当我尝试使用core::slice rustc 抱怨Use of undeclared type or module 'core::slice'

【问题讨论】:

    标签: loops parsing vector iterator rust


    【解决方案1】:

    解决方案是添加

    use std::slice::Iter;
    

    类型是

    fun foo<'a>(itr : &mut Iter<'a, i32>) {}
    

    【讨论】:

    • 请注意,这只允许您的函数与切片上的iter() 方法返回的迭代器一起使用,但不能与iter().map(|x| ...)) 一起使用,因为它有另一种类型。正如@FrancisGagné 建议的那样,您需要在这里使用泛型。
    【解决方案2】:

    有很多类型的迭代器;大多数时候,你真正想要的是一个能够使用它们中的任何一个的函数。为此,惯用的解决方案是使用泛型。

    fn foo<'a, T: Iterator<Item=&'a i32>>(mut itr: T) {
        while let Some(c) = itr.next() {
            if *c != 0 {
                break;
            }
            println!("{}", *c);
        }
    }
    
    fn main() {
        let v = vec![0; 10];
        let mut itr = v.iter();
        while let Some(c) = itr.next() {
            foo(itr);
        }
    }
    

    虽然上面的代码无法编译,因为它将itr 移动到foo,然后尝试在while let 上再次使用它。为了解决这个问题,我们需要通过引用来传递迭代器。

    fn foo<'a, T: Iterator<Item=&'a i32>>(itr: &mut T) {
        while let Some(c) = itr.next() {
            if *c != 0 {
                break;
            }
            println!("{}", *c);
        }
    }
    
    fn main() {
        let v = vec![0; 10];
        let mut itr = v.iter();
        while let Some(c) = itr.next() {
            foo(&mut itr);
        }
    }
    

    除了泛型,我们还可以使用 trait 对象:

    fn foo<'a>(itr: &mut Iterator<Item=&'a i32>) {
        while let Some(c) = itr.next() {
            if *c != 0 {
                break;
            }
            println!("{}", *c);
        }
    }
    
    fn main() {
        let v = vec![0; 10];
        let mut itr = v.iter();
        while let Some(c) = itr.next() {
            foo(&mut itr);
        }
    }
    

    Rust 书中关于 trait objects 的章节解释了这些解决方案之间的区别。

    【讨论】:

    • 太棒了!仅供参考,如果您在递归下降解析器中具有相互递归的函数,如果您使用泛型,则不会编译 rust,但如果您使用 trait 对象,它将起作用。
    猜你喜欢
    • 2021-01-03
    • 2012-07-11
    • 1970-01-01
    • 2015-04-15
    • 2016-03-21
    • 2015-09-08
    • 2012-07-23
    • 2013-06-03
    • 2019-12-10
    相关资源
    最近更新 更多