Rust gloo_events : Nested eventlisteners - rust

So, few months ago, i went on the journey of Rust and WASM.
The goal is to build a new generation free software WASM CMS to build websites implementing crypto and decentralized networking.
(See Fermyon Bartholomew, Locutus (rust version of Freenet), Holochain).
I want to build a business around that, so i will never drop this project. For those who are interested, help is welcome.
Anyway, i'm stuck on this problems since weeks, and i'm literally going crazy about it. Here is the problem:
For now i'm trying to make a rectangle selection tool, to simply draw empty rectangles on my canvas.
The mechanic is as follow, just three nested event listeners:
The first one is the onmousedown, registering the x/y position of the mouse click, and then adding the 2nd eventlistener
The second one is the onmousemove, adding the 3rd eventlistener if not already added, and then drawing/redrawing the rectangle
The third one is the oumouseup, setting the Point to None, and then removing itself and the onmousemove listeners
You can get the project at https://github.com/MojoMotion/canvas_rectangle_drawing_example (push requests are welcome).
Here is the main.rs:
use wasm_bindgen::JsCast;
use wasm_bindgen::UnwrapThrowExt;
//use gloo_console::log;
use gloo::events::EventListener;
use gloo_utils::document;
use web_sys::CanvasRenderingContext2d;
use web_sys::MouseEvent;
use std::cell::RefCell;
use std::rc::Rc;
struct Point {
x: f32,
y: f32,
}
fn main() {
let canvas = Rc::new(RefCell::new(document()
.get_element_by_id("canvas")
.unwrap()
.dyn_into::<web_sys::HtmlCanvasElement>()
.map_err(|_| ())
.unwrap()));
let context: CanvasRenderingContext2d = canvas
.borrow()
.get_context("2d")
.unwrap()
.unwrap()
.dyn_into::<CanvasRenderingContext2d>()
.unwrap();
let p1 = Rc::new(RefCell::new(None));
let p2 = Rc::new(RefCell::new(None));
let mouse_down = EventListener::new(&*canvas.borrow_mut(), "mousedown", |event| {
let event = event.dyn_ref::<MouseEvent>().unwrap_throw();
*p1.borrow_mut() = Some(Point { x: event.x() as f32, y: event.y() as f32 });
let mouse_move = EventListener::new(&*canvas.borrow_mut(), "mousemove", |event| {
let event = event.dyn_ref::<MouseEvent>().unwrap_throw();
*p2.borrow_mut() = Some(Point { x: event.x() as f32, y: event.y() as f32 });
let mouse_up = EventListener::new(&*canvas.borrow_mut(), "mouseup", |_event| {
*p1.borrow_mut() = None;
*p2.borrow_mut() = None;
//context.begin_path();
//context.move_to(125., 125.);
//context.line_to(125., 45.);
//context.line_to(45., 125.);
//context.close_path();
//context.stroke();
});
mouse_up.forget();
});
mouse_move.forget();
});
mouse_down.forget();
}
Here is the errors :
error[E0597]: `p1` does not live long enough
--> src/main.rs:40:10
|
38 | let mouse_down = EventListener::new(&*canvas.borrow_mut(), "mousedown", |event| {
| ------- value captured here
39 | let event = event.dyn_ref::<MouseEvent>().unwrap_throw();
40 | *p1.borrow_mut() = Some(Point { x: event.x() as f32, y: event.y() as f32 });
| ^^ borrowed value does not live long enough
...
46 | let mouse_up = EventListener::new(&*canvas.borrow_mut(), "mouseup", |_event| {
| ____________________________-
47 | | *p1.borrow_mut() = None;
48 | | *p2.borrow_mut() = None;
49 | |
... |
56 | |
57 | | });
| |______________- argument requires that `p1` is borrowed for `'static`
...
64 | }
| - `p1` dropped here while still borrowed
error[E0597]: `canvas` does not live long enough
--> src/main.rs:42:47
|
38 | let mouse_down = EventListener::new(&*canvas.borrow_mut(), "mousedown", |event| {
| ------- value captured here
...
42 | let mouse_move = EventListener::new(&*canvas.borrow_mut(), "mousemove", |event| {
| - ^^^^^^ borrowed value does not live long enough
| __________________________|
| |
43 | | let event = event.dyn_ref::<MouseEvent>().unwrap_throw();
44 | | *p2.borrow_mut() = Some(Point { x: event.x() as f32, y: event.y() as f32 });
45 | |
... |
58 | | mouse_up.forget();
59 | | });
| |__________- argument requires that `canvas` is borrowed for `'static`
...
64 | }
| - `canvas` dropped here while still borrowed
error[E0597]: `p2` does not live long enough
--> src/main.rs:44:14
|
38 | let mouse_down = EventListener::new(&*canvas.borrow_mut(), "mousedown", |event| {
| ------- value captured here
...
44 | *p2.borrow_mut() = Some(Point { x: event.x() as f32, y: event.y() as f32 });
| ^^ borrowed value does not live long enough
45 |
46 | let mouse_up = EventListener::new(&*canvas.borrow_mut(), "mouseup", |_event| {
| ____________________________-
47 | | *p1.borrow_mut() = None;
48 | | *p2.borrow_mut() = None;
49 | |
... |
56 | |
57 | | });
| |______________- argument requires that `p2` is borrowed for `'static`
...
64 | }
| - `p2` dropped here while still borrowed
I guess the problem comes from the eventlistener.forget() method call that throws the borrowed variables out of scope (i guess by using Futures stuff).
I tried to get around the problem by understanding lifetimes and use the 'static lifetime, Rc and RefCell, which apparently does not lives long enough for eventlisteners.
My guess is that i should use eventlistener.callback() with Futures stuff (futures::stream::Stream, futures::channel::mpsc, std::pin::Pin, std::task::{Context, Poll}) following the official doc at https://docs.rs/gloo-events/latest/gloo_events/struct.EventListener.html, but because i'm not very experienced with javascript, i'm really lost trying connecting rust and javascript...
Right now i'm trying to make the code bit in javascript to have better understanding of js behavior and callback stuff... I will never surrender but in the meantime i would love to have some help... Also i think this is a really cool project so i if we can share the solution for free i think that's nice. Help me out!

You're passing around references to reference counted values, if this sentence seems a bit redundant it's because it is.
Or in other words Rc<T> is already a reference to T.
Just .clone() the Rc<T> if you need multiple and pass the cloned values.
let p1: Rc<RefCell<Option<Point>>> = Rc::new(RefCell::new(None));
let mouse_down = {
let p1 = p1.clone();
EventListener::new(canvas.borrow(), "mousedown", move |event| {
let event = event.dyn_ref::<MouseEvent>().unwrap_throw();
*p1.borrow_mut() = Some(Point { x: event.x() as f32, y: event.y() as f32 });
// ...
})
};
// further uses of p1

Related

How do I change the structure in the thread?

Please help me, I'm completely confused.
How do I make this code work?
I need to change the structure members in the thread...
#[derive(Debug)]
struct S {
str: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
str: "a".to_string(),
b: false,
i: 0,
});
let mut threads = vec![];
for s in vec_s {
{
let mut _s = &s;
threads.push(std::thread::spawn(move || {
_s.b = true;
_s.str = "b".to_string();
_s.i = 1;
}));
}
}
for thread in threads {
let _ = thread.join();
}
dbg!(&vec_s);
}
The compiler outputs a lot of errors:
error[E0594]: cannot assign to `_s.b`, which is behind a `&` reference
--> src/main.rs:23:17
|
23 | _s.b = true;
| ^^^^^^^^^^^ cannot assign
error[E0594]: cannot assign to `_s.str`, which is behind a `&` reference
--> src/main.rs:24:17
|
24 | _s.str = "b".to_string();
| ^^^^^^ cannot assign
error[E0594]: cannot assign to `_s.i`, which is behind a `&` reference
--> src/main.rs:25:17
|
25 | _s.i = 1;
| ^^^^^^^^ cannot assign
error[E0597]: `s` does not live long enough
--> src/main.rs:21:26
|
21 | let mut _s = &s;
| ^^ borrowed value does not live long enough
22 | threads.push(std::thread::spawn(move || {
| __________________________-
23 | | _s.b = true;
24 | | _s.str = "b".to_string();
25 | | _s.i = 1;
26 | | }));
| |______________- argument requires that `s` is borrowed for `'static`
27 | }
28 | }
| - `s` dropped here while still borrowed
error[E0382]: borrow of moved value: `vec_s`
--> src/main.rs:34:10
|
9 | let mut vec_s = vec![];
| --------- move occurs because `vec_s` has type `Vec<S>`, which does not implement the `Copy` trait
...
19 | for s in vec_s {
| ----- `vec_s` moved due to this implicit call to `.into_iter()`
...
34 | dbg!(&vec_s);
| ^^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `vec_s`
--> /home/martin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:261:18
|
261 | fn into_iter(self) -> Self::IntoIter;
| ^^^^
help: consider iterating over a slice of the `Vec<S>`'s content to avoid moving into the `for` loop
|
19 | for s in &vec_s {
| +
You are attempting to do multithreading. Everything accessed by multiple threads has to be thread-safe. Further, with Rust being very strict (zero undefined behaviour tolerance), the compiler has to understand that your code is thread-safe.
The biggest problem here is that Rust's borrow checker doesn't understand that your threads get joined at some point. Therefore it doesn't allow you to create references to your S objects, because it cannot prove how long those references exist. Rust must be able to prove that they are destroyed before your S object is dropped; that's part of Rust's borrow checker safety guarantees.
For your specific usecase, Rust introduced thread scopes. With them, the compiler can finally understand thread lifetimes.
With some minor ownership issues fixed (use &mut vec_s for your loop, otherwise the vec_s object gets consumed by the loop), this now works:
#[derive(Debug)]
struct S {
s: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
s: "a".to_string(),
b: false,
i: 0,
});
std::thread::scope(|scope| {
let mut threads = vec![];
for s in &mut vec_s {
threads.push(scope.spawn(move || {
s.b = true;
s.s = "b".to_string();
s.i = 1;
}));
}
for thread in threads {
let _ = thread.join();
}
});
dbg!(&vec_s);
}
[src/main.rs:31] &vec_s = [
S {
s: "b",
b: true,
i: 1,
},
]
Another optimization:
If you don't actually use the JoinHandles for error propagation or similar, you don't need them at all in this example. The scope already automatically joins all threads it spawned at the end of the scope:
#[derive(Debug)]
struct S {
s: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
s: "a".to_string(),
b: false,
i: 0,
});
std::thread::scope(|scope| {
for s in &mut vec_s {
scope.spawn(move || {
s.b = true;
s.s = "b".to_string();
s.i = 1;
});
}
});
dbg!(&vec_s);
}
[src/main.rs:27] &vec_s = [
S {
s: "b",
b: true,
i: 1,
},
]

How to perform actions on a variable in a foreach while being able to use it afterwards

I have the following example code (including use statements too so there's some context on types):
use actix_web::{HttpRequest, HttpResponse, Responder};
use awc::ClientRequest;
pub async fn proxy(req: HttpRequest) -> impl Responder {
let response = construct_request(req).send().await;
let body = response.unwrap().body().await.expect("");
HttpResponse::Ok().body(body)
}
fn construct_request(req: HttpRequest) -> ClientRequest {
let client = awc::Client::default();
let mut new_req = client.get("url");
req.headers().iter().for_each(|headerPair| {
new_req.append_header((headerPair.0, headerPair.1));
});
new_req.content_type("application/json")
}
Currently, the compiler complains that I'm using the new_req value after it being moved in the foreach loop to copy the headers over, which is fair enough, that is what's happening.
error[E0507]: cannot move out of `new_req`, a captured variable in an `FnMut` closure
--> src/routes/proxy.rs:18:9
|
15 | let mut new_req = client.get("http://localhost:8001/ping");
| ----------- captured outer variable
16 |
17 | req.headers().iter().for_each(|headerPair| {
| ___________________________________-
18 | | new_req.append_header((headerPair.0, headerPair.1));
| | ^^^^^^^ ------------------------------------------- `new_req` moved due to this method call
| | |
| | move occurs because `new_req` has type `ClientRequest`, which does not implement the `Copy` trait
19 | | });
| |_____- captured by this `FnMut` closure
|
note: this function takes ownership of the receiver `self`, which moves `new_req`
--> /Users/{sanitized}/awc-3.0.1/src/request.rs:186:30
|
186 | pub fn append_header(mut self, header: impl TryIntoHeaderPair) -> Self {
| ^^^^
warning: variable does not need to be mutable
--> src/routes/proxy.rs:15:9
|
15 | let mut new_req = client.get("http://localhost:8001/ping");
| ----^^^^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
error[E0382]: use of moved value: `new_req`
--> src/routes/proxy.rs:21:5
|
15 | let mut new_req = client.get("http://localhost:8001/ping");
| ----------- move occurs because `new_req` has type `ClientRequest`, which does not implement the `Copy` trait
16 |
17 | req.headers().iter().for_each(|headerPair| {
| ------------ value moved into closure here
18 | new_req.append_header((headerPair.0, headerPair.1));
| ------- variable moved due to use in closure
...
21 | new_req.append_header(("custom", req.headers().get("custom").unwrap()))
| ^^^^^^^ value used here after move
What I can't find out is how I can work around this so that I can continue to use new_req after the foreach loop - is this possible? I've tried doing some googling around preventing this movement but I haven't managed to find anything (I'm assuming this is a very simple resolution that I just don't have the right words to discover)
You'll find by looking at the signature of .append_header() and other methods that they will consume self and return Self. This is a type of builder-pattern that is designed to work like this:
let new_req = client.get("url")
.append_header(...)
.append_header(...)
.append_header(...)
.content_type("application/json");
or like this:
let mut new_req = client.get("url");
new_req = new_req.append_header(...);
new_req = new_req.append_header(...);
new_req = new_req.append_header(...);
new_req = new_req.content_type("application/json");
Unfortunately, constant ownership transfers like this don't play well with closures if you want to keep the value afterwards. You're probably better suited just using a for-loop instead:
for header_pair in req.headers() {
new_req = new_req.append_header(header_pair);
}
Or if you insist on using .for_each(), you can modify the request in-place by using .headers_mut():
req.headers().iter().for_each(|header_pair| {
new_req.headers_mut().insert(header_pair.0.clone(), header_pair.1.clone());
});
If you're in the uncomfortable situation where you must take and reassign ownership and it must be while captured in a closure, you'll have to employ a trick using Option:
// put it in an option
let mut new_req_opt = Some(new_req);
req.headers().iter().for_each(|header_pair| {
// take it out of the option
let mut new_req = new_req_opt.take().unwrap();
// do your thing
new_req = new_req.append_header(header_pair);
// put it back into the option
new_req_opt = Some(new_req);
});
// take it out again at the end
let new_req = new_req_opt.unwrap();

use an object inside a closure which is passed to a method of that object

i have a struct Screen with its implementation
pub struct Screen {
stdin: Stdin,
// types are irrelevant
stdout: MouseStdout,
}
impl Screen {
// ...
pub fn handle_keys_loop<F: FnMut(&Event) -> ()>(
&self,
mut handler: F,
) {
let stdin = stdin();
for e in stdin.events() {
let e = e.unwrap();
match e {
Event::Key(Key::Ctrl('c')) => break,
_ => {
handler(&e);
},
}
}
}
}
and usage (which is wrong and know it)
let mut screen = Screen::new();
screen.init_screen();
screen.handle_keys_loop(|event| {
match event {
Event::Key(Key::Char('a')) => {
screen.println("hello there",15, 1, true);
},
_ => {}
}
});
screen.end_screen();
the error is
error[E0502]: cannot borrow `screen` as mutable because it is also borrowed as immutable
--> src/bin/terminal.rs:74:29
|
74 | screen.handle_keys_loop(|event| {
| - ---------------- ^^^^^^^ mutable borrow occurs here
| | |
| _____| immutable borrow later used by call
| |
75 | | match event {
76 | | Event::Key(Key::Char('a')) => {
77 | | println!("{} {} {} {}", "do something with a", 15, 1, true);
78 | | // tried to borrow as mutable
79 | | screen.println("hello there",15, 1, true);
| | ------ second borrow occurs due to use of `screen` in closure
... |
82 | | }
83 | | });
| |______- immutable borrow occurs here
and if i make self mut inside handle_keys_loop to get rid of cannot borrow screen as mutable because it is also borrowed as immutable
pub fn handle_keys_loop<F: FnMut(&Event) -> ()>(
+ &mut self,
- &self
....
i get this error
error[E0499]: cannot borrow `screen` as mutable more than once at a time
--> src/bin/terminal.rs:74:29
|
74 | screen.handle_keys_loop(|event| {
| - ---------------- ^^^^^^^ second mutable borrow occurs here
| | |
| _____| first borrow later used by call
| |
75 | | match event {
76 | | Event::Key(Key::Char('a')) => {
77 | | screen.println("hello there",15, 1, true);
| | ------ second borrow occurs due to use of `screen` in closure
... |
80 | | }
81 | | });
| |______- first mutable borrow occurs here
what im trying to do: use the method handle_keys_loop of screen and pass screen inside the closure, which is passed to handle_keys_loop. basically, to use screen inside of screen.
how do i achieve that ?
some people told me to use RefCell, but that didnt work out very well, i got BorrowError.
i will use any workaround to just use screen inside the closure which is passed to screen's method.
thanks in advance.
One pattern I use to handle such a situation is to pass self: &mut Self back into the closure from handle and use that inside the closure. A simplified version of your code:
struct Screen {}
struct Event {}
impl Screen {
fn handle<F: FnMut(&mut Screen, Event)>(&mut self, mut handler: F) {
handler(self, Event {})
}
fn print(&mut self) {}
}
fn main() {
let mut screen = Screen {};
screen.handle(|screen, _event| screen.print());
screen.handle(|screen, _event| screen.print());
}
You can't do what you're trying to do because it violates Rust's rule that you can't mutate a value while something else has access to it.
However, your handle_keys_loop method doesn't even use self which means the &self parameter is redundant. There's no reason to give a function an argument it's not going to use (except when implementing a trait that requires it).
Just remove the argument:
pub fn handle_keys_loop<F: FnMut(&Event) -> ()>(
mut handler: F,
) {
And call it as Screen::handle_keys_loop(|event| { ... }).
Alternatively, make it a free function, external to Screen entirely, since it doesn't depend on Screen in any way.

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
...

How to copy instead of borrow an i64 into a closure in Rust?

I have the following minimal example of my code:
fn main()
{
let names : Vec<Vec<String>> = vec![
vec!["Foo1".to_string(), "Foo2".to_string()],
vec!["Bar1".to_string(), "Bar2".to_string()]
];
let ids : Vec<i64> = vec![10, 20];
names.iter().enumerate().flat_map(|(i,v)| {
let id : i64 = ids[i];
v.iter().map(|n|
(n.clone(), id)
)
});
}
Now, when I compile that with rustc I get the following error message:
error[E0597]: `id` does not live long enough
--> main.rs:12:16
|
11 | v.iter().map(|n|
| --- capture occurs here
12 | (n.clone(), id)
| ^^ borrowed value does not live long enough
13 | )
14 | });
| -- borrowed value needs to live until here
| |
| borrowed value only lives until here
But in my understanding, id is of type i64 and should therefore be able to be copied into the capture, with would be exactly what I need?
I've also tried to inline the id variable but to no avail:
error[E0597]: `i` does not live long enough
--> main.rs:11:21
|
10 | v.iter().map(|n|
| --- capture occurs here
11 | (n.clone(), ids[i])
| ^ borrowed value does not live long enough
12 | )
13 | });
| -- borrowed value needs to live until here
| |
| borrowed value only lives until here
So how can I copy my integer into the closure instead of borrowing it?
I tried using move, but rustc doesn't like that either:
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> main.rs:10:17
|
7 | let ids : Vec<i64> = vec![10, 20];
| --- captured outer variable
...
10 | v.iter().map(move |n|
| ^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure
So I'd somehow need to get rustc to only move/copy some but not the other variable?
When you create a closure in Rust, it captures the variables either by value or by reference. A mix of both is impossible. By default, it captures by reference, but with the move keyword, it captures by value (i.e. it moves the captured variables inside the closure).
So, in your first code, you need to move id inside the closure:
fn main() {
let names: Vec<Vec<String>> = vec![
vec!["Foo1".to_string(), "Foo2".to_string()],
vec!["Bar1".to_string(), "Bar2".to_string()],
];
let ids: Vec<i64> = vec![10, 20];
names.iter().enumerate().flat_map(|(i, v)| {
let id: i64 = ids[i];
v.iter().map(move |n| (n.clone(), id))
});
}
Then you ask if you can "inline" ids:
fn main() {
let names: Vec<Vec<String>> = vec![
vec!["Foo1".to_string(), "Foo2".to_string()],
vec!["Bar1".to_string(), "Bar2".to_string()],
];
let ids: Vec<i64> = vec![10, 20];
names.iter().enumerate().flat_map(|(i, v)| {
v.iter().map(|n| (n.clone(), ids[i]))
});
}
You cannot put ids at all in your inner closure, because you are already inside a FnMut closure (that requires exclusive access). Thus, you cannot borrow or move ids because it is already borrowed by the FnMut closure. Minimal reproduction:
fn main() {
let mut i = 0;
let mut closure = || {
i = 2;
|| {
println!("i = {}", i);
}
};
closure()();
}
You can move the variable into closure with move keyword. Here you need to change the closure like:
v.iter().map(move |n| // move is the keyword for moving variables into closure scope.
(n.clone(), id)
)
Playground

Resources