Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can &Some(_) in vec.iter() { .. } compile?

Tags:

rust

I tried to run the following code snippet:

let a = &[Some(1), Some(2), Some(3), None, Some(4)];

let mut sum = 0;
for &Some(x) in a.iter() {
    sum += x;
}

assert_eq!(sum, 1+2+3+4);

The compiler replied with:

about_loops.rs:39:9: 43:18 error: non-exhaustive patterns: None not covered
about_loops.rs:39         for &Some(x) in a.iter() {
about_loops.rs:40             sum += x;
about_loops.rs:41         } 
about_loops.rs:42 
about_loops.rs:43         assert_eq!(sum, 1+2+3+4);
error: aborting due to previous error
make: *** [all] Error 101

Can I make such a construct compile for a for loop without using a match expression as suggested by luke and hobbs? Or is this error message misleading? It does not seem so given the grammar definition of for.

for_expr : "for" pat "in" expr '{' block '}' ;

I'm on:

rustc 0.11.0-pre-nightly (6291955 2014-05-19 23:41:20 -0700)
host: x86_64-apple-darwin

To clarify: How expressive is the 'pat' portion of for_expr? This is not specified under http://doc.rust-lang.org/rust.html#for-expressions in contrast to the definition under http://doc.rust-lang.org/rust.html#match-expressions.

like image 901
havardh Avatar asked Mar 19 '23 12:03

havardh


1 Answers

The pattern of a for loop essentially has the same restrictions as a let: it has to be irrefutable, that is, it can't ever fail to match.

Examples of irrefutable patterns are &, tuples, structs and single-variant enums. Other patterns (like multivariant enums or literals) aren't guaranteed to always match, since the type allows for values that aren't covered by the pattern.

The for construct is essentially a macro that desugars as follows (it desugars in the same pass as macros are expanded, you can see it manually running rustc with --pretty expanded):

for <pattern> in <iter_expression> {
    <code>
}

// becomes

match &mut <iter_expression> { // match to guarantee data lives long enough
    it => {
        loop {
            match it.next() {
                None => break,
                Some(<pattern>) => { <code> }
            }
        }
    }
}

That is a normal match, i.e. the arms have to be exhaustive (cover every possibility), and so if <pattern> is just &Some(_), then the Some(&None) possibility isn't covered.

(The Some arm is essentially equivalent to Some(value) => { let <pattern> = value; .... Thinking about it now, this might actually be a desugaring that gives better error messages: I filed #14390.)

like image 157
huon Avatar answered Mar 28 '23 11:03

huon