5 ms·
Newbie question: in the last example: fn make_tester(answer: &str) -> impl Fn(&str) -> bool + '_ { move |challenge| { challenge == answer
by akavel 6y ago
Newbie question: in the last example:
fn make_tester(answer: &str) -> impl Fn(&str) -> bool + '_ {
move |challenge| {
challenge == answer
}
}
why is there `move` needed, if both `answer`, and the arg of `Fn`, seem to be references (`&str`)? To a layman, this sounds like as if both "challenge" and "answer" should be borrowed - so why "move"? what's even to move here?
- Rotten194 6y agoIirc it’s moving the reference to answer, not the value.
- momothereal 6y agoIn this closure you are moving `answer`, that is, you are moving the reference itself into scope. The `challenge` reference is already owned by the closure since it's a parameter. The move doesn't mean the closure owns the underlying strings, but the references themselves.
- steveklabnik 6y agoI believe what happens here is that the closure tries to capture it as a &&str. This is because it defaults to trying to take the environment by reference. The "move" in this case means that it will try to take it by value instead. This feels tricky semantically because references are types too, so "taking it by value" means taking a &T rather than a &&T, just like you may think about how taking a T is by value as opposed to &T.
- ridiculous_fish 6y agoThis is confusing, and Rust's error messages make it much worse. If you try to remove the `move`, you get an error: > closure may outlive the current function, but it borrows `answer`, which is owned by the current function. To force the closure to take ownership of `answer` use the `move` keyword. But 'answer' is of course not owned by the current function, and how can you take ownership through a shared reference? The explanation is double indirection. By default, the closure captures a pointer to answer, which is itself a pointer on the stack. Without the 'move', inside the closure `answer` has type &&str and points into make_tester's stack frame. With the 'move', it copies the passed-in pointer. The error message is referring to the pointer itself, and this is not obvious. Incidentally I have never found docs for the '+' syntax there, would appreciate a pointer to any.
- steveklabnik 6y agoThe + syntax is https://doc.rust-lang.org/reference/types/trait-object.html#trait-object-lifetime-bounds https://doc.rust-lang.org/reference/types/trait-object.html#... This applies to impl Trait as well. It should probably be there too...
- ridiculous_fish 6y agoThanks!
- dbaupp 6y ago> But 'answer' is of course not owned by the current function As you imply later, ‘answer’ itself is owned by the current function, but the ‘answer’ value is a pointer that doesn’t own what it points to. This subtlety, that references are full values themselves, is definitely something to trip on, especially when double indirection starts popping up like this.