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

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.

Related

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();

Rust borrow checker multiple mutable reference in modifying element in linked list in a loop

I'm trying to build some sort of linked list, each node has a keyword and vectors of the same node. In that for loop, i will traverse the linked list to get the vector, either already exist if keyword is the same, or create a new vector. I find it impossible to *not * violate the double mut reference error since I'll need to do iter_mut(), push() on the same path. Anyone has general idea on how to approach this?
pub struct Knowledge {
pub title: String,
}
pub struct Entry {
pub keyword: String,
pub next: Vec<Box<KnowledgeEntry>>
}
pub enum KnowledgeEntry {
Normal(Knowledge),
Entry(Entry)
}
impl KnowledgeEntry {
pub fn get_entry_mut (&mut self) -> Option<&mut Vec<Box<KnowledgeEntry>>> {
match self {
KnowledgeEntry::Entry(e) => {
Some(&mut e.next)
}
KnowledgeEntry::Normal(k) => {None}
}
}
}
fn main () {
let mut entry = Entry{keyword: "".to_owned(), next: vec![]};
let mut current_container = &mut entry.next;
let new_knowledge = Knowledge{title: "title1".to_owned()};
// new knowledge to be insert in these hierarchy.
let remaining_comp: Vec<_> = vec!["hier1", "hier2", "hier3"];
// each loop will set current_container, either created from new, or found in the vector.
for comp in remaining_comp.iter() {
// true will be replace with body checking with keyword.
let mut _result = current_container.iter_mut().find(|en| {true});
if let Some(mut _res) = _result {
// found the container. Set the current container
if let KnowledgeEntry::Entry(ref mut entry) = &mut **_res {
current_container = &mut entry.next;
} else {
break;
}
} else {
// can't find the resulting container. Create a new vector, and move the container.
let new_container: Vec<Box<KnowledgeEntry>> = vec![];
let mut _temp = KnowledgeEntry::Entry(Entry {
keyword: (*comp).to_string(),
next: new_container
});
current_container.push(Box::new(_temp));
let last_var = current_container.last_mut().unwrap();
// get_entry_mut() to retrieve `_temp` that we have just moved.
current_container = (**last_var).get_entry_mut().unwrap();
}
}
// found the container correspond to "hier1" -> "hier2" -> "hier3", add the entry.
current_container.push(Box::new(KnowledgeEntry::Normal(new_knowledge)));
}
Playground
Produces the following errors:
error[E0499]: cannot borrow `*current_container` as mutable more than once at a time
--> src/main.rs:50:13
|
35 | let mut _result = current_container.iter_mut().find(|en| {true});
| ----------------- first mutable borrow occurs here
...
50 | current_container.push(Box::new(_temp));
| ^^^^^^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
error[E0499]: cannot borrow `*current_container` as mutable more than once at a time
--> src/main.rs:51:28
|
35 | let mut _result = current_container.iter_mut().find(|en| {true});
| ----------------- first mutable borrow occurs here
...
51 | let last_var = current_container.last_mut().unwrap();
| ^^^^^^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
error[E0499]: cannot borrow `*current_container` as mutable more than once at a time
--> src/main.rs:57:1
|
35 | let mut _result = current_container.iter_mut().find(|en| {true});
| ----------------- first mutable borrow occurs here
...
57 | current_container.push(Box::new(KnowledgeEntry::Normal(new_knowledge)));
| ^^^^^^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here

Error on Future generator closure: Captured variable cannot escape `FnMut` closure body

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?

Borrowed and captured variable in RUST

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.

How to reduce lifetime conflicts?

I'm fear about lifetime question. I searched and got so many relative results. I feel so different between of them, and I think it is difficult to get the spirit from them. so I decide to ask.
The error occurred when invoking dao's method inside a Hyper service's call, and I can't fix it!
extern crate futures;
extern crate hyper;
use futures::future::Future;
use futures::Stream;
use hyper::server::{Http, Request, Response, Service};
use hyper::StatusCode;
use std::net::SocketAddr;
trait Dao {
fn input_data(&self, data: &str) -> bool;
}
struct MysqlDao;
impl Dao for MysqlDao {
fn input_data(&self, data: &str) -> bool {
unimplemented!()
}
}
struct HelloWorld<'a> {
dao: &'a Dao,
}
impl<'a> Service for HelloWorld<'a> {
type Request = Request;
type Response = Response;
type Error = hyper::Error;
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
fn call(&self, req: Request) -> Self::Future {
Box::new(req.body().concat2().map(|b| {
let rtn = self.dao.input_data(std::str::from_utf8(b.as_ref()).unwrap());
let rtn = true; // line 35 this is ok
match rtn {
true => {
return Response::new()
.with_status(StatusCode::Ok)
.with_body(String::from("ok"));
}
false => {
return Response::new()
.with_status(StatusCode::UnprocessableEntity)
.with_body(String::from("error"));
}
}
}))
}
}
fn main() {
let addr = "127.0.0.1:3000".parse().unwrap();
static DAO: MysqlDao = MysqlDao;
web_startup(&addr, &DAO);
}
fn web_startup<T: Dao>(addr: &SocketAddr, dao: &'static T) {
let server = Http::new()
.bind(addr, move || Ok(HelloWorld { dao }))
.unwrap();
server.run().unwrap();
}
playground
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:33:9
|
33 | / Box::new(req.body().concat2().map(|b| {
34 | | let rtn = self.dao.input_data(std::str::from_utf8(b.as_ref()).unwrap());
35 | | let rtn = true; // line 35 this is ok
36 | | match rtn {
... |
47 | | }
48 | | }))
| |___________^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 26:1...
--> src/main.rs:26:1
|
26 | / impl<'a> Service for HelloWorld<'a> {
27 | | type Request = Request;
28 | | type Response = Response;
29 | | type Error = hyper::Error;
... |
49 | | }
50 | | }
| |_^
note: ...so that the type `futures::Map<futures::stream::Concat2<hyper::Body>, [closure#src/main.rs:33:43: 48:10 self:&&HelloWorld<'a>]>` will meet its required lifetime bounds
--> src/main.rs:33:9
|
33 | / Box::new(req.body().concat2().map(|b| {
34 | | let rtn = self.dao.input_data(std::str::from_utf8(b.as_ref()).unwrap());
35 | | let rtn = true; // line 35 this is ok
36 | | match rtn {
... |
47 | | }
48 | | }))
| |___________^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<futures::Future<Error=hyper::Error, Item=hyper::Response> + 'static>, found std::boxed::Box<futures::Future<Error=hyper::Error, Item=hyper::Response>>)
--> src/main.rs:33:9
|
33 | / Box::new(req.body().concat2().map(|b| {
34 | | let rtn = self.dao.input_data(std::str::from_utf8(b.as_ref()).unwrap());
35 | | let rtn = true; // line 35 this is ok
36 | | match rtn {
... |
47 | | }
48 | | }))
| |___________^
The problem line is 34. When I replace line 34 with line 35, it works.
There's a couple of things going on with lifetimes in this code, and the error message is not that great.
The first thing is that your call function returns a trait object; that is, Box<T> where T is a trait instead of a concrete type. The default lifetime for a trait object is 'static, so Box<Future> is equivalent to Box<Future + 'static>. That explains where this line of the message comes from:
note: ...so that expression is assignable (expected std::boxed::Box<futures::Future<Error=hyper::Error, Item=hyper::Response> + 'static>, found std::boxed::Box<futures::Future<Error=hyper::Error, Item=hyper::Response>>)
In this case, you don't need your returned Future to have the 'static lifetime. Instead, you want it to have the same lifetime as self.dao, so change your type alias as follows:
type Future = Box<'a + Future<Item = Self::Response, Error = Self::Error>>;
The second thing is what variables your closure captures. Your closure refers to self, so it needs to save away that reference. This means the closure can't live past the end of the method - but you've already specified it will live as long as 'a; that is, it will live at least as long as self.dao.
Note that self in this method does not have the lifetime 'a. The instance of HelloWorld might have a shorter lifetime than the dao it has a reference to.
To fix this half of the problem, you need to allow the closure to capture only self.dao without capturing self. So you have to add
let dao = self.dao;
before the closure, and then refer to dao instead of self.dao inside the closure, so that it won't capture self. You also need to make the closure a move closure, otherwise it ends up capturing a reference to the reference, which still ties the lifetime to the scope of the function.
User red75prime, who originally posted this suggestion in a comment, made a playground with these changes. Lines 30, 33, and 34 are the important ones.
I found a way, but I think it's ugly.
Remove dao property from HelloWorld; add Sync to trait Dao; move out DAO to upper scope; invoke DAO directly from fn call.
Code : playground

Resources