The problem is that msg
is a variable you get from the iteration, and therefore is only valid during one iteration step. It ceases to exist at the end of the iteration step, hence the comiler message - msg dropped here while still borrowed
at the end of the loop.
The reason why this is a problem is because you move the reference msg_str
into the closure via move ||
, and the rust compiler cannot infer that spawn_blocking
drops it before the end of the loop. (it can't infer it because it would be incorrect; join_handle.await
could get cancelled, which would NOT cancel the spawned task and would cause &msg_str
to be a dangling reference)
But it doesn't tell me how to do a static
borrow of msg
in this case.
You can't borrow statically from a temporal variable. That is the definition of a 'static
borrow, that it does not cease to exist after a while.
Sadly without knowing the types of the variables / function parameters I can't give you any advice how you could solve this. You probably want to introduce a clone somewhere, but hard to tell where exactly without knowing types.
Guess of a solution
I tried to infer a minimal reproducible example from your question.
I assume that the types are as followed:
use tokio::task::spawn_blocking;
fn parse_trade(_msg: &str) -> Result<Vec<u32>, String> {
Ok(vec![1, 2, 3])
}
#[tokio::main]
async fn main() {
let rx = vec!["a".to_string(), "b".to_string()];
for msg in rx {
let msg_str = msg.as_str();
println!("{}", &msg_str);
let join_handle = spawn_blocking(move || parse_trade(&msg_str));
match join_handle.await {
Ok(trade) => {
let t = &trade.unwrap()[0];
}
Err(error) => panic!("Problem joining: {:?}", error),
}
}
}
Which does show the following error message:
error[E0597]: `msg` does not live long enough
--> src/main.rs:12:23
|
12 | let msg_str = msg.as_str();
| ^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `msg` is borrowed for `'static`
...
23 | }
| - `msg` dropped here while still borrowed
This is a possible solution:
use tokio::task::spawn_blocking;
fn parse_trade(_msg: &str) -> Result<Vec<u32>, String> {
Ok(vec![1, 2, 3])
}
#[tokio::main]
async fn main() {
let rx = vec!["a".to_string(), "b".to_string()];
for msg in rx {
let msg_str = msg.as_str();
let msg_clone = msg.clone();
println!("{}", &msg_str);
let join_handle = spawn_blocking(move || parse_trade(msg_clone.as_str()));
match join_handle.await {
Ok(trade) => {
let t = &trade.unwrap()[0];
}
Err(error) => panic!("Problem joining: {:?}", error),
}
}
}
You create a .clone()
of msg
and move this one into the closure instead. It carries ownership of the cloned string into the closure, and it therefore does no longer depend on the msg
variable.