I've trimmed this down to the simplest version I possibly could (notably, everything goes fine when there's only one nested level of step
).
I present two different ways of extracting elements of an iterator to feed them into a struct, or returning an error if the iterator runs out of elements: the first explicitly chains .next()
and .map_or()
on an iterator; the second uses a local closure that does exactly the same, but hinds it behind a name.
#[derive(Debug)]
pub struct MyArgs {
first: String,
second: String,
}
impl MyArgs {
fn new(mut args: std::env::Args) -> Result<MyArgs, &'static str> {
args.next();
args.next().map_or(Err("missing first"), |first| {
args.next()
.map_or(Err("missing second"), |second| Ok(MyArgs { first, second }))
})
}
// fn new2(mut args: std::env::Args) -> Result<MyArgs, &'static str> {
// let step = |e, f| args.next().map_or(e, f);
// step(Err("missing 0th"), |_| {
// step(Err("missing first"), |first| {
// step(Err("missing second"), |second| Ok(MyArgs { first, second }))
// })
// })
// }
}
fn main() {
println!("{:?}", MyArgs::new(std::env::args()));
// println!("{:?}", MyArgs::new2(std::env::args()));
}
If you compile rustc args_next.rs
and run ./args_next ...
with varying arguments, you'll see the expected behavior. However, if you uncomment new2
and compile, you should get the following error:
error[E0308]: mismatched types
--> args_next.rs:19:40
|
19 | step(Err("missing first"), |first| {
| ________________________________________^
20 | | step(Err("missing second"), |second| Ok(MyArgs { first, second }))
21 | | })
| |_____________^ expected closure, found a different closure
|
= note: expected closure `[closure@args_next.rs:20:45: 20:82 first:_]`
found closure `[closure@args_next.rs:19:40: 21:14 step:_]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
error[E0308]: mismatched types
--> args_next.rs:18:34
|
18 | step(Err("missing 0th"), |_| {
| __________________________________^
19 | | step(Err("missing first"), |first| {
20 | | step(Err("missing second"), |second| Ok(MyArgs { first, second }))
21 | | })
22 | | })
| |_________^ expected closure, found a different closure
|
= note: expected closure `[closure@args_next.rs:20:45: 20:82 first:_]`
found closure `[closure@args_next.rs:18:34: 22:10 step:_]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
I can't manage to reason through the issue here, as I can eyeball this and tell they are doing exactly the same thing—I suspect it's an issue with the inferred types, but I can't fix it.
Note that changing the outer step
call to a simple args.next(); step(Err("missing first"), ...)
still results in the compiler error. As I said, nesting any deeper than a single call to step
gives this error.
Interestingly, changing to
fn new2(mut args: std::env::Args) -> Result<MyArgs, &'static str> {
let step = |e, f| args.next().map_or(e, f);
step(Err("missing 0th"), |_| {
args.next().map_or(Err("missing first"), |first| {
args.next()
.map_or(Err("missing second"), |second| Ok(MyArgs { first, second }))
})
})
}
gives a different, perhaps more revelatory, message?
error[E0596]: cannot borrow `step` as mutable, as it is not declared as mutable
--> args_next.rs:18:9
|
17 | let step = |e, f| args.next().map_or(e, f);
| ---- help: consider changing this to be mutable: `mut step`
18 | step(Err("missing 0th"), |_| {
| ^^^^ cannot borrow as mutable
error[E0499]: cannot borrow `args` as mutable more than once at a time
--> args_next.rs:18:34
|
17 | let step = |e, f| args.next().map_or(e, f);
| ------ ---- first borrow occurs due to use of `args` in closure
| |
| first mutable borrow occurs here
18 | step(Err("missing 0th"), |_| {
| ---- ^^^ second mutable borrow occurs here
| |
| first borrow later used by call
19 | args.next().map_or(Err("missing first"), |first| {
| ---- second borrow occurs due to use of `args` in closure
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0499, E0596.
For more information about an error, try `rustc --explain E0499`.