How to write a Rust function that takes an iterator?

后端 未结 3 2012
遇见更好的自我
遇见更好的自我 2020-11-27 20:57

I\'d like to write a function that accepts an iterator and returns the results of some operations on it. Specifically, I\'m trying to iterate over the values of a Has

相关标签:
3条回答
  • 2020-11-27 21:10

    Easiest is using an impl Trait, impl Iterator:

    use std::collections::HashMap;
    
    fn find_min<'a>(vals: impl Iterator<Item = &'a u32>) -> Option<&'a u32> {
        vals.min()
    }
    
    fn main() {
        let mut map = HashMap::new();
        map.insert("zero", 0u32);
        map.insert("one", 1u32);
        println!("Min value {:?}", find_min(map.values()));
    }
    

    playground

    0 讨论(0)
  • 2020-11-27 21:12

    You want to use generics here:

    fn find_min<'a, I>(vals: I) -> Option<&'a u32>
    where
        I: Iterator<Item = &'a u32>,
    {
        vals.min()
    }
    

    Traits can be used in two ways: as bounds on type parameters and as trait objects. The book The Rust Programming Language has a chapter on traits and a chapter on trait objects that explain these two use cases.

    Additionally, you often want to take something that implements IntoIterator as this can make the code calling your function nicer:

    fn find_min<'a, I>(vals: I) -> Option<&'a u32>
    where
        I: IntoIterator<Item = &'a u32>,
    {
        vals.into_iter().min()
    }
    
    0 讨论(0)
  • 2020-11-27 21:22

    This behaviour is a little unintuitive from those with a Python background rather than, say, a C++ background, so let me clarify a little.

    In Rust, values are conceptually stored inside the name that binds them. Thus, if you write

    let mut x = Foo { t: 10 };
    let mut y = x;
    x.t = 999;
    

    y.t will still be 10.

    So when you write

    let x: Iterator<Item=&'a u32>;
    

    (or the same in the function parameter list), Rust needs to allocate enough space for any value of type Iterator<Item=&'a u32>. Even if this was possible, it wouldn't be efficient.

    So what Rust does instead is offer you the option to

    • Put the value on the heap, eg. with Box, which gives Python-style semantics. Then you can take generically with &mut Iterator<Item=&'a u32>.

    • Specialize each function invocation for each possible type to satisfy the bound. This is more flexible, since a trait reference is a possible specialization, and gives the compiler more opportunities for specialization, but means you can't have dynamic dispatch (where the type can vary dependent on runtime parameters).

    0 讨论(0)
提交回复
热议问题