I am working with paho_mqtt, and I want to send messages on topics according to those received. I divided my code into nested functions, and I use the variable cli (cf code below). I think I need to use references to have a working code, but I still don't figure how. Thank you for your help.
Code:
fn publish_fail_msg(cli: mqtt::AsyncClient, topic: String){
let msg = mqtt::Message::new(topic, "Fail", QOS[0]);
cli.publish(msg);
}
fn manage_msgs(cli: mqtt::AsyncClient, msg: mqtt::Message){
let topic = msg.topic();
let payload_str = msg.payload_str();
match topic {
"main" => publish_new_topic(cli, payload_str.to_string()),
_ => publish_fail_msg(cli, topic.to_string()),
}
}
fn main() -> mqtt::AsyncClient {
// Create the client connection
let mut cli = mqtt::AsyncClient::new(create_opts).unwrap_or_else(|e| {
println!("Error creating the client: {:?}", e);
process::exit(1);
});
// Attach a closure to the client to receive callback on incoming messages.
cli.set_message_callback(|_cli, msg| {
if let Some(msg) = msg {
manage_msgs(cli, msg);
}
});
cli
}
Error:
error[E0507]: cannot move out of captured variable in an `FnMut` closure
--> src/main.rs:230:25
|
212 | let mut cli = mqtt::AsyncClient::new(create_opts).unwrap_or_else(|e| {
| ------- captured outer variable
...
230 | manage_msgs(cli, msg);
| ^^^ cannot move out of captured variable in an `FnMut` closure
error[E0505]: cannot move out of `cli` because it is borrowed
--> src/main.rs:228:30
|
228 | cli.set_message_callback(|_cli, msg| {
| --- -------------------- ^^^^^^^^^^^ move out of `cli` occurs here
| | |
| | borrow later used by call
| borrow of `cli` occurs here
229 | if let Some(msg) = msg {
230 | manage_msgs(cli, msg);
| --- move occurs due to use in closure
error[E0382]: borrow of moved value: `cli`
--> src/main.rs:248:5
|
212 | let mut cli = mqtt::AsyncClient::new(create_opts).unwrap_or_else(|e| {
| ------- move occurs because `cli` has type `mqtt::AsyncClient`, which does not implement the `Copy` trait
...
228 | cli.set_message_callback(|_cli, msg| {
| ----------- value moved into closure here
229 | if let Some(msg) = msg {
230 | manage_msgs(cli, msg);
| --- variable moved due to use in closure
...
248 | cli.connect_with_callbacks(conn_opts, on_connect_success, on_connect_failure);
| ^^^ value borrowed here after move
The devil is in the details: I found the issue, which is the _cli. I replaced it with cli: &mqtt::AsyncClient and I could send the reference to my nested functions. Maybe there are better solutions for this, and it would be a pleasure to see them.
Related
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();
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.
I want to create a simple websocket server. I want to process the incoming messages and send a response, but I get an error:
error: captured variable cannot escape `FnMut` closure body
--> src\main.rs:32:27
|
32 | incoming.for_each(|m| async {
| _________________________-_^
| | |
| | inferred to be a `FnMut` closure
33 | | match m {
34 | | // Error here...
35 | | Ok(message) => do_something(message, db, &mut outgoing).await,
36 | | Err(e) => panic!(e)
37 | | }
38 | | }).await;
| |_____^ returns a reference to a captured variable which escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
This gives a few hits on Stack Overflow but I don't see anywhere in my code where a variable is escaping. The async block won't run concurrently, so I don't see any problem. Furthermore, I feel like I am doing something very simple: I get a type which allows me to send data back to the client, but when using a reference to it in the async block, it gives a compile error. The error only occurs when I use the outgoing or db variable in the async code.
This is my code (error is in the handle_connection function):
main.rs
use tokio::net::{TcpListener, TcpStream};
use std::net::SocketAddr;
use std::sync::Arc;
use futures::{StreamExt, SinkExt};
use tungstenite::Message;
use tokio_tungstenite::WebSocketStream;
struct DatabaseConnection;
#[tokio::main]
async fn main() -> Result<(), ()> {
listen("127.0.0.1:3012", Arc::new(DatabaseConnection)).await
}
async fn listen(address: &str, db: Arc<DatabaseConnection>) -> Result<(), ()> {
let try_socket = TcpListener::bind(address).await;
let mut listener = try_socket.expect("Failed to bind on address");
while let Ok((stream, addr)) = listener.accept().await {
tokio::spawn(handle_connection(stream, addr, db.clone()));
}
Ok(())
}
async fn handle_connection(raw_stream: TcpStream, addr: SocketAddr, db: Arc<DatabaseConnection>) {
let db = &*db;
let ws_stream = tokio_tungstenite::accept_async(raw_stream).await.unwrap();
let (mut outgoing, incoming) = ws_stream.split();
// Adding 'move' does also not work
incoming.for_each(|m| async {
match m {
// Error here...
Ok(message) => do_something(message, db, &mut outgoing).await,
Err(e) => panic!(e)
}
}).await;
}
async fn do_something(message: Message, db: &DatabaseConnection, outgoing: &mut futures_util::stream::SplitSink<WebSocketStream<TcpStream>, Message>) {
// Do something...
// Send some message
let _ = outgoing.send(Message::Text("yay".to_string())).await;
}
Cargo.toml
[dependencies]
futures = "0.3.*"
futures-channel = "0.3.*"
futures-util = "0.3.*"
tokio = { version = "0.2.*", features = [ "full" ] }
tokio-tungstenite = "0.10.*"
tungstenite = "0.10.*"
When using async move, I get the following error:
code
incoming.for_each(|m| async move {
let x = &mut outgoing;
let b = db;
}).await;
error
error[E0507]: cannot move out of `outgoing`, a captured variable in an `FnMut` closure
--> src\main.rs:33:38
|
31 | let (mut outgoing, incoming) = ws_stream.split();
| ------------ captured outer variable
32 |
33 | incoming.for_each(|m| async move {
| ______________________________________^
34 | | let x = &mut outgoing;
| | --------
| | |
| | move occurs because `outgoing` has type `futures_util::stream::stream::split::SplitSink<tokio_tungstenite::WebSocketStream<tokio::net::tcp::stream::TcpStream>, tungstenite::protocol::message::Message>`, which does not implement the `Copy` trait
| | move occurs due to use in generator
35 | | let b = db;
36 | | }).await;
| |_____^ move out of `outgoing` occurs here
FnMut is an anonymous struct, since FnMutcaptured the &mut outgoing, it becomes a field inside of this anonymous struct and this field will be used on each call of FnMut , it can be called multiple times. If you lose it somehow (by returning or moving into another scope etc...) your program will not able to use that field for further calls, due to safety Rust Compiler doesn't let you do this(for your both case).
In your case instead of capturing the &mut outgoing we can use it as argument for each call, with this we'll keep the ownership of outgoing. You can do this by using fold from futures-rs:
incoming
.fold(outgoing, |mut outgoing, m| async move {
match m {
// Error here...
Ok(message) => do_something(message, db, &mut outgoing).await,
Err(e) => panic!(e),
}
outgoing
})
.await;
This may seem a bit tricky but it does the job, we are using constant accumulator(outgoing) which will be used as an argument for our FnMut.
Playground (Thanks #Solomon Ucko for creating reproducible example)
See also :
How to return the captured variable from `FnMut` closure, which is a captor at the same time
How can I move a captured variable into a closure within a closure?
This question already has answers here:
How to update-or-insert on a Vec?
(2 answers)
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
(1 answer)
Closed 5 years ago.
I'm trying to implement a trie but the borrow checker is really giving me a hard time:
struct Node {
// a trie node
value: char,
children: Vec<Node>,
}
impl Node {
fn add_child(&mut self, value: char) -> &mut Node {
// adds a child to given node
let vec: Vec<Node> = Vec::new();
let node = Node {
value,
children: vec,
};
self.children.push(node);
self.children.last_mut().unwrap()
}
fn get_child(&mut self, value: char) -> Option<&mut Node> {
// checks if given node has a child with given value, returns the child if it exists
for child in self.children.iter_mut() {
if child.value == value {
return Some(child);
}
}
None
}
fn has_child(&self, value: char) -> bool {
for child in self.children.iter() {
if child.value == value {
return true;
}
}
false
}
fn add_word(&mut self, word: String) {
let mut cursor = self;
for c in word.chars() {
match cursor.get_child(c) {
Some(node) => cursor = node,
None => cursor = cursor.add_child(c),
}
}
cursor.add_child('~');
}
}
The add_word method gives these 5 errors:
error[E0499]: cannot borrow `*cursor` as mutable more than once at a time
--> src/main.rs:41:19
|
41 | match cursor.get_child(c) {
| ^^^^^^ mutable borrow starts here in previous iteration of loop
...
47 | }
| - mutable borrow ends here
error[E0506]: cannot assign to `cursor` because it is borrowed
--> src/main.rs:42:31
|
41 | match cursor.get_child(c) {
| ------ borrow of `cursor` occurs here
42 | Some(node) => cursor = node,
| ^^^^^^^^^^^^^ assignment to borrowed `cursor` occurs here
error[E0506]: cannot assign to `cursor` because it is borrowed
--> src/main.rs:43:25
|
41 | match cursor.get_child(c) {
| ------ borrow of `cursor` occurs here
42 | Some(node) => cursor = node,
43 | None => cursor = cursor.add_child(c),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `cursor` occurs here
error[E0499]: cannot borrow `*cursor` as mutable more than once at a time
--> src/main.rs:43:34
|
41 | match cursor.get_child(c) {
| ------ first mutable borrow occurs here
42 | Some(node) => cursor = node,
43 | None => cursor = cursor.add_child(c),
| ^^^^^^ second mutable borrow occurs here
...
47 | }
| - first borrow ends here
error[E0499]: cannot borrow `*cursor` as mutable more than once at a time
--> src/main.rs:46:9
|
41 | match cursor.get_child(c) {
| ------ first mutable borrow occurs here
...
46 | cursor.add_child('~');
| ^^^^^^ second mutable borrow occurs here
47 | }
| - first borrow ends here
This is the Go code that I was trying to translate:
func (n *trieNode) AddWord(word string) {
cursor := n
for i := 0; i < len(word); i++ {
if cursor.HasChild(byte(word[i])) == nil {
cursor = cursor.AddChild(byte(word[i]))
} else {
cursor = cursor.HasChild(byte(word[i]))
}
}
// tilde indicates the end of the word
cursor.AddChild(byte('~'))
}
This code:
//let seen_cell = std::cell::RefCell::new(window_0);
window_0.connect_delete_event(|_, _| {
//window_0.destroy();
window.hide();
Inhibit(true)
});
button_0.connect_clicked(|_|{
window.show_all();
}
);
Produces the errors:
error[E0373]: closure may outlive the current function, but it borrows `window`, which is owned by the current function
--> src/main.rs:192:36
|
192 | window_0.connect_delete_event( |_, _| {
| ^^^^^^ may outlive borrowed value `window`
...
195 | window.hide();
| ------ `window` is borrowed here
|
help: to force the closure to take ownership of `window` (and any other referenced variables), use the `move` keyword, as shown:
| window_0.connect_delete_event( move |_, _| {
error[E0373]: closure may outlive the current function, but it borrows `window`, which is owned by the current function
--> src/main.rs:199:30
|
199 | button_0.connect_clicked(|_|{
| ^^^ may outlive borrowed value `window`
200 | window.show_all();
| ------ `window` is borrowed here
|
help: to force the closure to take ownership of `window` (and any other referenced variables), use the `move` keyword, as shown:
| button_0.connect_clicked(move |_|{
If I try this:
//let seen_cell = std::cell::RefCell::new(window_0);
window_0.connect_delete_event(move |_, _| {
//window_0.destroy();
window.hide();
Inhibit(true)
});
button_0.connect_clicked(|_|{
window.show_all();
}
);
I get the errors:
error[E0373]: closure may outlive the current function, but it borrows `window`, which is owned by the current function
--> src/main.rs:199:30
|
199 | button_0.connect_clicked(|_|{
| ^^^ may outlive borrowed value `window`
200 | window.show_all();
| ------ `window` is borrowed here
|
help: to force the closure to take ownership of `window` (and any other referenced variables), use the `move` keyword, as shown:
| button_0.connect_clicked(move |_|{
error[E0382]: capture of moved value: `window`
--> src/main.rs:199:30
|
192 | window_0.connect_delete_event(move |_, _| {
| ----------- value moved (into closure) here
...
199 | button_0.connect_clicked(|_|{
| ^^^ value captured here after move
|
= note: move occurs because `window` has type `gtk::Window`, which does not implement the `Copy` trait
If I try this:
//let seen_cell = std::cell::RefCell::new(window_0);
window_0.connect_delete_event(move |_, _| {
//window_0.destroy();
window.hide();
Inhibit(true)
});
button_0.connect_clicked(move|_|{
window.show_all();
}
);
I get the errors:
error[E0382]: capture of moved value: `window`
--> src/main.rs:200:9
|
192 | window_0.connect_delete_event(move |_, _| {
| ----------- value moved (into closure) here
...
200 | window.show_all();
| ^^^^^^ value captured here after move
|
= note: move occurs because `window` has type `gtk::Window`, which does not implement the `Copy` trait
I have read similar questions but I have not been able to solve this case. How can I solve this in the best way, perhaps by using Arc or similar?
I have solved the above using a macro that I have drawn from some sample projects of gtk-rs
macro_rules! clone {
(#param _) => ( _ );
(#param $x:ident) => ( $x );
($($n:ident),+ => move || $body:expr) => (
{
$( let $n = $n.clone(); )+
move || $body
}
);
($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
{
$( let $n = $n.clone(); )+
move |$(clone!(#param $p),)+| $body
}
);
}
Taking the case described I have used it this way:
window_0.connect_delete_event(clone!(window => move |_, _| {
//window_0.destroy();
window.hide();
Inhibit(true)
}));
button_0.connect_clicked(clone!(window => move |_|{
window.show_all();
}));
This is the relevant part window_0.connect_delete_event(clone!(window => move. In my case it also applies to button_0.connect_clicked because window Is used later in a similar place