#error[E0382]: borrow of moved value: `qr`

17 messages · Page 1 of 1 (latest)

rapid ocean
#

I need send the qr variable to my frontend. I get a message trough socketio but when I try save the message and show in the console. I get this error. Help me.

#[tauri::command]
fn getQR() -> String {

    let mut qr = String::new();

    let callback = move |payload: Payload, socket: RawClient| {
        match payload {
            Payload::String(str) => {
                qr.push_str(&str);
                println!("Received: {}", qr);
            },
            Payload::Binary(bin_data) => println!("Received bytes: {:#?}", bin_data),
        }
    };

   
    let mut socket = ClientBuilder::new("http://localhost:1425")
        .namespace("/")
        .on("message", callback)
        .on("error", |err, _| eprintln!("Error: {:#?}", err))
        .connect()
        .expect("Connection failed");
        
   
    println!("qr: {}", qr);

    qr.into()

}
rapid ocean
#

The error is the follow:

#

error[E0382]: borrow of moved value: qr
--> src/main.rs:71:28
|
50 | let mut qr = String::new();
| ------ move occurs because qr has type std::string::String, which does not implement the Copy trait
51 |
52 | let callback = move |payload: Payload, socket: RawClient| {
| ------------------------------------------ value moved into closure here
...
55 | qr.push_str(&str);
| -- variable moved due to use in closure
...
71 | println!("qr: {}", qr);
| ^^ value borrowed here after move
|
= note: this error originates in the macro $crate::format_args_nl which comes from the expansion of the macro println (in Nightly builds, run with -Z macro-backtrace for more info)

tight trout
#

So the main problem here is the code execution flow. The error about the moved variable is just a consequence of that. Maybe a react code example helps to show the problem. ```rs
let qr = "";

getQR.then((payload) => {
qr = payload.data;
});

console.log(qr) // This will print an empty string because it runs before the .then stuff of getQR

This is basically the same that's happening in your rust code. Meanning that you can't just return the qr code like this from the command.

The easiest solution on the rust side would be to use a tauri event to give back the qr code. Should look something like this ```rs
#[tauri::command]
async fn getQR(app_handle: tauri::AppHandle) { // make sure to make it async so that it doesn't block the main thread
    let callback = move |payload: Payload, socket: RawClient| {
        match payload {
            Payload::String(data) => {
                app_handle.emit_all("qr_code_str", data).unwrap();
                println!("Received: {}", qr);
            },
            Payload::Binary(bin_data) => {
              app_handle.emit_all("qr_code_bin", data).unwrap();
              println!("Received bytes: {:#?}", bin_data);
            }
        }
    };

   
    let mut socket = ClientBuilder::new("http://localhost:1425")
        .namespace("/")
        .on("message", callback)
        .on("error", |err, _| eprintln!("Error: {:#?}", err))
        .connect()
        .expect("Connection failed");
}

The drawback of this is how you have to handle that on the javascript side:

listen("qr_code_str", (payload) => { console.log(payload) })
invoke("getQR", () => { /* There won't be a payload here */ })
#

alternatively you can use a channel to make the rust command work like you excepted:

#[tauri::command]
async fn getQR() -> String { // make sure to make it async so that it doesn't block the main thread

    let (sender, receiver) = std::sync::mpsc::channel();

    let callback = move |payload: Payload, socket: RawClient| {
        sender.send(payload).unwrap();
    };
   
    let mut socket = ClientBuilder::new("http://localhost:1425")
        .namespace("/")
        .on("message", callback)
        .on("error", |err, _| eprintln!("Error: {:#?}", err))
        .connect()
        .expect("Connection failed");
        
    let qr = receiver.recv().unwrap();
   
    println!("qr: {}", qr);

    qr.into()
}
``` (didn't check if this actually compiles)
rapid ocean
#

I actually try to save the str variable in the qr variable. But I cant. Do you help me with this, forgett that I try to send to the frontend.

tight trout
#

i understood what you were trying to do. If you want a qr variable on the rust side then my last example is the solution (or at least a step in the right direction)

rapid ocean
#

println!("qr: {}", qr);
| ^^ Payload cannot be formatted with the default formatter

#

I get this error

tight trout
tight trout
# rapid ocean println!("qr: {}", qr); | ^^ `Payload` cannot be forma...

whoops, i forgot to add your match again. i guess it would look something like this then.


#[tauri::command]
async fn getQR() -> String { // make sure to make it async so that it doesn't block the main thread

    let (sender, receiver) = std::sync::mpsc::channel();

    let callback = move |payload: Payload, socket: RawClient| {
        sender.send(payload).unwrap();
    };
   
    let mut socket = ClientBuilder::new("http://localhost:1425")
        .namespace("/")
        .on("message", callback)
        .on("error", |err, _| eprintln!("Error: {:#?}", err))
        .connect()
        .expect("Connection failed");
        
    let message = receiver.recv().unwrap();
    let mut qr = String::new();
    match message {
            Payload::String(data) => {
                qr = data;
            },
            Payload::Binary(bin_data) => {
              println!("Received bytes: {:#?}", bin_data);
            }
    }

    println!("Received: {}", qr);

    qr.into()
}
rapid ocean
#

I cant understand. Its so difficult for only save a variable

tight trout
#

did you see my javascript example? I tried to show there why it is so difficult.

rapid ocean
#

Yes, but I get the message in the pay load. Its means that I will can use or modify. I cant undenstrand why rust dont equals to variables

tight trout
#

well that part works fine, and is basically what i did in my last snippet. I just initialized qr with an empty string because Payload can be Binary and i didn't know how to handle that here.

Maybe i misunderstood your message here tho

#

but again, this is not a rust thing either. It's how callbacks work. You'll have similar problems in all languages when callbacks are used (or something inbetween like javascript's Promise.then() which is basically a callback too)

rapid ocean
#

Hey! I used a global variable. Yes I understand your explication. Thanks for it. Really it was useful.