Why does Rust not automatically move when necessary? - rust

The following program compiles without issue:
#[tokio::main]
async fn main() {
async fn g(x: String) {}
let f = || {
let y: String = String::from("a").clone();
return async {
println!("{}", &y);
return g(y).await;
}};
}
However, if the line "return g(y).await;" is removed, it will fail with the following:
error[E0373]: async block may outlive the current function, but it borrows `y`, which is owned by the current function
--> src/main.rs:35:22
|
35 | return async {
| ______________________^
36 | | println!("{}", &y);
| | - `y` is borrowed here
37 | | // return g(y).await;
38 | | }};
| |_____^ may outlive borrowed value `y`
|
note: async block is returned here
--> src/main.rs:35:16
|
35 | return async {
| ________________^
36 | | println!("{}", &y);
37 | | // return g(y).await;
38 | | }};
| |_____^
help: to force the async block to take ownership of `y` (and any other referenced variables), use the `move` keyword
|
35 | return async move {
| ++++
Why does the same error not appear in the original code?

Rust does the minimum amount of work necessary to get your closure to work.
let f = || {
let y: String = String::from("a").clone();
return async {
println!("{}", &y);
}
};
Here, the inner closure requires y by reference. So Rust is going to turn it into, essentially, a struct with a &String. Removing the async stuff for simplicity, it would turn this
let f = || {
let y: String = String::from("a").clone();
|| {
println!("{}", &y);
}
};
into, effectively, this
struct MyCustomClosure<'a> { y: &'a String };
impl<'a> FnOnce for MyCustomClosure<'a> {
fn call_once(self) {
println!("{}", self.y)
}
}
// (Same impl for FnMut and Fn ...)
let f = || {
let y: String = String::from("a").clone();
return MyCustomClosure { y: &y }
};
Now, sometime way later on in the compilation process, Rust realizes that the lifetime 'a for MyCustomClosure doesn't line up with the lifetime for the enclosing function, and it complains. But by this point it's already committed to using a reference here and it's not smart enough to go back and try a different closure type. It's two different stages of compilation that don't talk to each other directly.
This on the other hand
let f = || {
let y: String = String::from("a").clone();
|| { y }
};
This, on the other hand, very clearly requires a move. We're passing ownership inside the closure, so we get a closure that only implements FnOnce and that takes the y by value. Essentially we get
struct MyCustomClosure2 { y: String };
impl FnOnce for MyCustomClosure2 {
fn call_once(self) -> String {
self.y
}
}
// No FnMut or Fn this time, since we need to pass ownership of a value.
Now there's no lifetime argument 'a to cause conflicts down the road. There's just a simple struct and it all works out.
As the error message indicates, if your intent is to get an FnOnce which returns the string by moving, you can prefix your closure with the move keyword.
let f = || {
let y: String = String::from("a").clone();
return async move {
println!("{}", &y);
}
};

Related

Cryptic message when dealing with Rust Option type

I have a function like the following:
pub fn process_options<T>(in_refs:& mut Vec<T>,ivals:Vec<Option<T>>) -> i32 {
let mut nones = 0;
for int in 0..ivals.len() {
if let None = ivals[int] {
nones += 1;
} else {
in_refs.push(ivals[int].unwrap());
}
}
return nones;
}
What this function does is that it:
It pushes all the some(T) from one vector to another as T. And it also records the number of none values in the first vector. As written above the code fails to compile and gives me:
error[E0507]: cannot move out of index of `Vec<Option<T>>`
--> src/functions.rs:40:26
|
40 | in_refs.push(ivals[int].unwrap());
| ^^^^^^^^^^ -------- value moved due to this method call
| |
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
| move occurs because value has type `Option<T>`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves value
--> /Users/yunfeichen/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:772:25
|
772 | pub const fn unwrap(self) -> T {
Which I frankly do not understand can you explain this to me?
Edit:
This question has been solved:
It turns out I just need to use a different style of for loop, Not sure why this for loop works but it does:
pub fn process_options<T>(in_refs:& mut Vec<T>,ivals:Vec<Option<T>>) -> i32 {
let mut nones = 0;
for element in ivals{
if let None = element {
nones += 1;
} else {
in_refs.push(element.unwrap());
}
}
return nones;
}

Can I specify a closure which captures nothing?

While closures are powerful, they can lead to bugs if used carelessly. An example is a closure that modifies its captured variables when this is not wanted. Sometimes we only need an anonymous function that has no free variables. That is, it captures nothing. Can I specify a closure as capturing nothing and get this checked by the compiler? Something like none |...| {...} looks ideal. I know I can define a function in current scope but it's not as elegant as a variable containing an anonymous function.
Only non capturing closures can coerce to function pointers. You can use this fact to check that the closure is non-capturing by attempting to coerce it to a function pointer:
let closure = || {};
let _: fn() = closure;
You can wrap it in a macro to make this convenient:
macro_rules! enforce_non_capturing {
// This macro does not allow specifying the return type (`|| -> Ret {}`),
// but it can be adjusted to allow that.
// It also does not allow patterns as parameter names, but allowing that
// is harder.
(
| $( $param:ident $( : $param_ty:ty )? ),* $(,)? | $body:expr
) => {{
let closure = | $( $param $( : $param_ty )?, )* | $body;
// We want to generate `fn(_, _, ...) -> _` with underscores as the number of parameters.
// We use a dummy repetition to achieve that.
let _: fn( $( enforce_non_capturing!(#replace_with_underscore $param ), )* ) -> _ = closure;
closure
}};
// `||` is recognized as one token instead of two, so we need another arm.
( || $body:expr ) => { enforce_non_capturing!(| | $body) };
(#replace_with_underscore $param:ident) => { _ };
}
fn main() {
// Compiles.
let closure = enforce_non_capturing!(|| {});
closure();
let a = 0;
// Doesn't compile.
// let closure = enforce_non_capturing!(|| a);
// closure();
}
Playground.
Maybe the constraint could not be expressed where the closure/function is provided, but where it is expected.
In this example, fnct2() cannot receive a closure.
fn fnct1(mut f: impl FnMut(i32) -> i32) {
println!("{}", f(10));
}
fn fnct2(f: fn(i32) -> i32) {
println!("{}", f(20));
}
fn main() {
let mut x = 0;
fnct1(|n| {
x += 1;
n + x
});
fnct2(|n| {
// x += 2; // ERROR: expected fn pointer, found closure
// n + x
n + 2
});
println!("x={}", x);
}
/*
11
22
x=1
*/
While this is most certainly not a 'best practice', you can store the closure in a function pointer. Function pointers can only hold non-capturing closures.
This works:
fn main() {
let c: fn() = || {
println!("Hello world!");
};
c();
}
Hello world!
While this doesn't:
fn main() {
let mut a = 10;
let c: fn() = || {
a += 1;
};
}
error[E0308]: mismatched types
--> src/main.rs:3:19
|
3 | let c: fn() = || {
| ____________----___^
| | |
| | expected due to this
4 | | a += 1;
5 | | };
| |_____^ expected fn pointer, found closure
|
= note: expected fn pointer `fn()`
found closure `[closure#src/main.rs:3:19: 3:21]`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> src/main.rs:4:9
|
4 | a += 1;
| ^ `a` captured here

Why does i got lifetime error in rust closure

I'm testing some rust wasm features, and have some problem with closures.
I'm implemented this function, which setup callback on button click event.
pub fn setup_click(&mut self) {
let mut clicks = 0;
let ws_cloned = self.websocket.clone();
let num_clicks_cloned = self.num_clicks.clone();
let notifications = Rc::new(RefCell::new(Notificator::new(
NotificationConfig::new_default(),
)));
let cb = move |_: Event| {
clicks += 1;
num_clicks_cloned
.borrow_mut()
.set_inner_html(clicks.to_string());
let mut map: Map<String, Value> = serde_json::Map::new();
map.insert("key".to_string(), Value::String(clicks.to_string()));
if let Ok(ws) = ws_cloned.clone().try_borrow_mut() {
ws.send_rpc(
String::from("click"),
Params::Map(map),
Box::new(|payload: String| {
notifications.clone().borrow_mut().display(
payload,
"Click success".to_string(),
"success".to_string(),
)
}),
);
}
};
self.click_button.add_event_listener("click", cb);
}
where third param of the ws.send rpc is
pub type RPCHandler = Box<dyn Fn(String) + 'static>;
and add_event_listener has this sugnature
pub fn add_event_listener<T>(&mut self, event_name: &str, handler: T)
where
T: 'static + FnMut(web_sys::Event),
{
let cb = Closure::wrap(Box::new(handler) as Box<dyn FnMut(_)>);
if let Some(el) = self.el.take() {
let el_et: EventTarget = el.into();
el_et
.add_event_listener_with_callback(event_name, cb.as_ref().unchecked_ref())
.unwrap();
cb.forget();
if let Ok(el) = el_et.dyn_into::<web_sys::Element>() {
self.el = Some(el);
}
}
}
When i try to compile the code i got life time error
--> src/test_click_btn.rs:46:21
|
35 | let cb = move |_: Event| {
| --------------- lifetime `'1` represents this closure's body
...
46 | / Box::new(|payload: String| {
47 | | notifications.clone().borrow_mut().display(
48 | | payload,
49 | | "Click success".to_string(),
50 | | "success".to_string(),
51 | | )
52 | | }),
| |______________________^ cast requires that `'1` must outlive `'static`
|
= note: closure implements `FnMut`, so references to captured variables can't escape the closure```
I see that notifications not live long enough, but can't understand how to fix this error)
There's no guarantee in this code that the closure passed to send_rpc will last no longer than the event callback closure. Therefore, it needs to be made a move closure too, so that it can live independently rather than borrowing from the event handler closure.
Conveniently, you already have notifications wrapped in Rc, which is just what you need, but you've performed the clone in the wrong place. This line
notifications.clone().borrow_mut().display(
performs a clone and dereferences it immediately, so it's redundant. Instead, you need to clone it before creating the closure so that the closure (now move) can own it:
let notifications = notifications.clone(); // create a clone that will be moved into the closure
ws.send_rpc(
String::from("click"),
Params::Map(map),
Box::new(move |payload: String| { // now a move closure
notifications.borrow_mut().display( // no clone here
...

Two closures that use references to parent scope

Im trying to create a struct that stores 2 closures, each with read references to an parent scope variable where they were created.
After I have closed over the references in the parent scope, how do I make sure they live for the same amount of time as the closures?
For example:
struct S {
x: bool,
}
type Closure = Box<dyn Fn()>;
struct Env {
fn_a: Closure,
fn_b: Closure,
}
fn get_env() -> Env {
let s = S { x: true };
let fn_a = || {
&s.x;
};
let fn_b = || {
&s.x;
};
Env {
fn_a: Box::new(fn_a),
fn_b: Box::new(fn_b),
}
}
fn main() {
let env = get_env();
}
playground
Results in:
error[E0597]: `s` does not live long enough
--> src/main.rs:16:10
|
15 | let fn_a = || {
| -- value captured here
16 | &s.x;
| ^ borrowed value does not live long enough
...
23 | fn_a: Box::new(fn_a),
| -------------- cast requires that `s` is borrowed for `'static`
...
26 | }
| - `s` dropped here while still borrowed```
It depends on your scenario. How long would the returned closures live?
If it lives as long as the Env value, what about moving s into the Env value and accessing s from the Env value?
If you don't know (or don't want to spend the trouble to figure out) the lifetime for the closures, a convenient (although slightly less efficient) way is to use Rc, then move a clone of the Rc from the results:
Playground
use std::rc::Rc;
pub struct S {
x: bool,
}
pub type Closure = Box<dyn Fn()>;
#[allow(unused)]
pub struct Env {
fn_a: Closure,
fn_b: Closure,
}
fn get_env() -> Env {
let s = Rc::new(S { x: true });
let cloned = Rc::clone(&s);
let fn_a = move || {
s.x;
};
let fn_b = move || {
cloned.x;
};
Env {
fn_a: Box::new(fn_a),
fn_b: Box::new(fn_b),
}
}
fn main() {
let _env = get_env();
}

Borrow checker issue in `zip`-like function with a callback

I'm trying to implement a function that steps though two iterators at the same time, calling a function for each pair. This callback can control which of the iterators is advanced in each step by returning a (bool, bool) tuple. Since the iterators take a reference to a buffer in my use case, they can't implement the Iterator trait from the stdlib, but instead are used though a next_ref function, which is identical to Iterator::next, but takes an additional lifetime parameter.
// An iterator-like type, that returns references to itself
// in next_ref
struct RefIter {
value: u64
}
impl RefIter {
fn next_ref<'a>(&'a mut self) -> Option<&'a u64> {
self.value += 1;
Some(&self.value)
}
}
// Iterate over two RefIter simultaneously and call a callback
// for each pair. The callback returns a tuple of bools
// that indicate which iterators should be advanced.
fn each_zipped<F>(mut iter1: RefIter, mut iter2: RefIter, callback: F)
where F: Fn(&Option<&u64>, &Option<&u64>) -> (bool, bool)
{
let mut current1 = iter1.next_ref();
let mut current2 = iter2.next_ref();
loop {
let advance_flags = callback(&current1, &current2);
match advance_flags {
(true, true) => {
current1 = iter1.next_ref();
current2 = iter2.next_ref();
},
(true, false) => {
current1 = iter1.next_ref();
},
(false, true) => {
current2 = iter1.next_ref();
},
(false, false) => {
return
}
}
}
}
fn main() {
let mut iter1 = RefIter { value: 3 };
let mut iter2 = RefIter { value: 4 };
each_zipped(iter1, iter2, |val1, val2| {
let val1 = *val1.unwrap();
let val2 = *val2.unwrap();
println!("{}, {}", val1, val2);
(val1 < 10, val2 < 10)
});
}
error[E0499]: cannot borrow `iter1` as mutable more than once at a time
--> src/main.rs:28:28
|
22 | let mut current1 = iter1.next_ref();
| ----- first mutable borrow occurs here
...
28 | current1 = iter1.next_ref();
| ^^^^^ second mutable borrow occurs here
...
42 | }
| - first borrow ends here
error[E0499]: cannot borrow `iter2` as mutable more than once at a time
--> src/main.rs:29:28
|
23 | let mut current2 = iter2.next_ref();
| ----- first mutable borrow occurs here
...
29 | current2 = iter2.next_ref();
| ^^^^^ second mutable borrow occurs here
...
42 | }
| - first borrow ends here
error[E0499]: cannot borrow `iter1` as mutable more than once at a time
--> src/main.rs:32:28
|
22 | let mut current1 = iter1.next_ref();
| ----- first mutable borrow occurs here
...
32 | current1 = iter1.next_ref();
| ^^^^^ second mutable borrow occurs here
...
42 | }
| - first borrow ends here
error[E0499]: cannot borrow `iter1` as mutable more than once at a time
--> src/main.rs:35:28
|
22 | let mut current1 = iter1.next_ref();
| ----- first mutable borrow occurs here
...
35 | current2 = iter1.next_ref();
| ^^^^^ second mutable borrow occurs here
...
42 | }
| - first borrow ends here
I understand why it complains, but can't find a way around it. I'd appreciate any help on the subject.
Link to this snippet in the playground.
Since the iterators take a reference to a buffer in my use case, they can't implement the Iterator trait from the stdlib, but instead are used though a next_ref function, which is identical to Iterator::next, but takes an additional lifetime parameter.
You are describing a streaming iterator. There is a crate for this, aptly called streaming_iterator. The documentation describes your problem (emphasis mine):
While the standard Iterator trait's functionality is based off of
the next method, StreamingIterator's functionality is based off of
a pair of methods: advance and get. This essentially splits the
logic of next in half (in fact, StreamingIterator's next method
does nothing but call advance followed by get).
This is required because of Rust's lexical handling of borrows (more
specifically a lack of single entry, multiple exit borrows). If
StreamingIterator was defined like Iterator with just a required
next method, operations like filter would be impossible to define.
The crate does not currently have a zip function, and certainly not the variant you have described. However, it's easy enough to implement:
extern crate streaming_iterator;
use streaming_iterator::StreamingIterator;
fn each_zipped<A, B, F>(mut iter1: A, mut iter2: B, callback: F)
where
A: StreamingIterator,
B: StreamingIterator,
F: for<'a> Fn(Option<&'a A::Item>, Option<&'a B::Item>) -> (bool, bool),
{
iter1.advance();
iter2.advance();
loop {
let advance_flags = callback(iter1.get(), iter2.get());
match advance_flags {
(true, true) => {
iter1.advance();
iter2.advance();
}
(true, false) => {
iter1.advance();
}
(false, true) => {
iter1.advance();
}
(false, false) => return,
}
}
}
struct RefIter {
value: u64
}
impl StreamingIterator for RefIter {
type Item = u64;
fn advance(&mut self) {
self.value += 1;
}
fn get(&self) -> Option<&Self::Item> {
Some(&self.value)
}
}
fn main() {
let iter1 = RefIter { value: 3 };
let iter2 = RefIter { value: 4 };
each_zipped(iter1, iter2, |val1, val2| {
let val1 = *val1.unwrap();
let val2 = *val2.unwrap();
println!("{}, {}", val1, val2);
(val1 < 10, val2 < 10)
});
}
The issue with this code is that RefIter is being used in two ways, which are fundamentally at odds with one another:
Callers of next_ref recieve a reference to the stored value, which is tied to the lifetime of RefIter
RefIter's value needs to be mutable, so that it can be incremented on each call
This perfectly describes mutable aliasing (you're trying to modify 'value' while a reference to it is being held) - something which Rust is explicitly designed to prevent.
In order to make each_zipped work, you'll need to modify RefIter to avoid handing out references to data that you wish to mutate.
I've implemented one possibility below using a combination of RefCell and Rc:
use std::cell::RefCell;
use std::rc::Rc;
// An iterator-like type, that returns references to itself
// in next_ref
struct RefIter {
value: RefCell<Rc<u64>>
}
impl RefIter {
fn next_ref(&self) -> Option<Rc<u64>> {
let new_val = Rc::new(**self.value.borrow() + 1);
*self.value.borrow_mut() = new_val;
Some(Rc::clone(&*self.value.borrow()))
}
}
// Iterate over two RefIter simultaniously and call a callback
// for each pair. The callback returns a tuple of bools
// that indicate which iterators should be advanced.
fn each_zipped<F>(iter1: RefIter, iter2: RefIter, callback: F)
where F: Fn(&Option<Rc<u64>>, &Option<Rc<u64>>) -> (bool, bool)
{
let mut current1 = iter1.next_ref();
let mut current2 = iter2.next_ref();
loop {
let advance_flags = callback(&current1, &current2);
match advance_flags {
(true, true) => {
current1 = iter1.next_ref();
current2 = iter2.next_ref();
},
(true, false) => {
current1 = iter1.next_ref();
},
(false, true) => {
current2 = iter1.next_ref();
},
(false, false) => {
return
}
}
}
}
fn main() {
let iter1 = RefIter { value: RefCell::new(Rc::new(3)) };
let iter2 = RefIter { value: RefCell::new(Rc::new(4)) };
each_zipped(iter1, iter2, |val1, val2| {
// We can't use unwrap() directly, since we're only passed a reference to an Option
let val1 = **val1.iter().next().unwrap();
let val2 = **val2.iter().next().unwrap();
println!("{}, {}", val1, val2);
(val1 < 10, val2 < 10)
});
}
This version of RefIter hands out Rcs to consumers, instead of references. This avoids the issue of mutable aliasing - updating value is done by placing
a new Rc into the outer RefCell. A side effect of this is that consumers are able to hold onto an 'old' reference to the buffer (through the returned Rc), even after RefIter has advanced.

Resources