-1

I get this unhelpful error message:

error[E0597]: `msg` does not live long enough
  --> src/main.rs:25:23
   |
25 |         let msg_str = msg.as_str();
   |                       ^^^^^^^^^^^^
   |                       |
   |                       borrowed value does not live long enough
   |                       argument requires that `msg` is borrowed for `'static`
...
51 |     }
   |     - `msg` dropped here while still borrowed

From the following Rust code:

    for msg in rx {
        let msg_str = msg.as_str();
        let msg_type = get_msg_type(exchange, &msg_str);

        println!("{}", &msg_str);

        let join_handle = spawn_blocking(move || { parse_trade(exchange, market_type, &msg_str) });
        match join_handle.await {
            Ok(trade) => {
                let t = &trade.unwrap()[0];
            },
            Err(error) => panic!("Problem joining: {:?}", error),
        }
    }

But it doesn't tell me how to do a static borrow of msg in this case.

What is a viable solution here?

None of the following proposed duplicate questions are equivalent to this question:

  1. Spawn non-static future with Tokio
  2. Can you specify a non-static lifetime for threads?
  3. How do I use static lifetimes with threads?
  4. How can I send non-static data to a thread in Rust and is it needed in this example?
Neil
  • 24,551
  • 15
  • 60
  • 81
  • Please provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). I have a good idea on what's going on here, but I can't help you without knowing what the type of `msg`, `msg_str` and the method parameter types of `get_msg_type` and `parse_trade` are. It should be fairly straightforward to convert this into a minimal reproducible example. – Finomnis May 10 '22 at 08:00
  • @Finomnis: It's not a "minimal" example, but it should be small enough: https://github.com/nhooey/crypto-arbitrage-rs/blob/master/src/main.rs – Neil May 10 '22 at 08:15
  • I don't think this is a minimal example. Please break down your code to the absolute minimum required to produce that error. I updated my response with a guess of a minimal example, together with a proposed solution. Please read the guide on how to create a minimal reproducible example, in most cases the process of creating such an example brings you to the solution already. – Finomnis May 10 '22 at 08:27

1 Answers1

1

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.

Finomnis
  • 18,094
  • 1
  • 20
  • 27
  • Your suggestion of creating `msg_clone` worked! – Neil May 10 '22 at 08:36
  • I'm glad :) Please try to understand how my minimal example is set up, and try to imitate that in future. That would have saved me a bunch of time :) – Finomnis May 10 '22 at 08:59