Iter::any without mutable reference


#1

What’s a good iter alternative to

use std::str;

pub struct NamedPoint {
	pub metric_name: String
}

impl NamedPoint {
    fn parse_datagram_line(line: &str) -> Result< NamedPoint, String > {
        let parts : Vec<&str> = line.split(" ").collect();
        if parts.len() != 3 {
            return Err( format!("Datagram `{}` does not have 3 parts", line) );
        }
        
        let metric_name = parts[0].to_string();
        Ok(NamedPoint{ metric_name: metric_name })
    }
}

fn main() {
    let datagram = "collectd.xle.xle-forwarder-01.disk-vda.disk_octets.read nan 1442949342\r\ncollectd.xle.xle-forwarder-01.disk-vda.disk_octets.write nan 1442949342\r\n";
  
    let parsed_lines_iter = datagram.lines_any().map(|x| NamedPoint::parse_datagram_line(x) );
    if parsed_lines_iter.any(|x| x.is_err() ) {
        println!("oh no! bad parse!");
    } else {
        println!("yay parses worked");
    }
}

Fails with:

<anon>:23:8: 23:25 error: cannot borrow immutable local variable `parsed_lines_iter` as mutable
<anon>:23     if parsed_lines_iter.any(|x| x.is_err() ) {
                 ^~~~~~~~~~~~~~~~~
error: aborting due to previous error
playpen: application terminated with error code 101

Play: http://is.gd/SNeEPu

where parsed_lines_iter is not required to be mut? I don’t need the state of the iterator or to access the passing iter item. Should I use a simple gated value with a for loop?

let mut has_it = false;
for entry in collection {
  if entry.is_err() {
    has_it = true;
    break;
  }
}

#2

collection.iter().any(|x| cond(x)) works whether or not collection is mutable.

A better example of how to use collect() for an operation which might fail:

fn main() {
    let strings = vec!["1", "2", "3"];
    let parsed_strings : Result<Vec<i32>, _> =
        strings.iter().map(|x| x.parse()).collect();
    println!("{:?}", parsed_strings);
}

#3

There was a bug in my example, I didn’t mean to call collect() on the first line. collection should be an iter until the end of the function.

By the way, the signature for any: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.any

fn any<F>(&mut self, f: F) -> bool 
   where F: FnMut(Self::Item) -> bool

I updated the top post with play-runnable code example. Sorry for the confusion!


#4

let mut parsed_lines_iter = compiles.

You could also write if { let mut p = parsed_lines_iter; p.any(|x| x.is_err()) } {, but I’m not sure that’s really an improvement.


#5

I guess I’m looking for something which shortcircuits to true when an entry matches the predicate. I don’t need the mutable variable since I’ll never check what the value of the iterator was, I just need the true/false. Oh well!


#6

To check if any value matches, you need to produce at least one value from the iterator. To do that, the iterator needs to be mutable, since it changes its internal state.

When you write something like

vec.iter().map(f).any(|x| x.is_err())

there is also a mutable iterator returned from iter(), you just don’t bind it to a variable, so there is no let mut.