Issues with borrow checker and loop

Hi, I am quite new to rust and I'm running into some issues with the borrow checker.
Namely, I want to have a value that is uninitialized outside of a loop, to then initialize it inside, and use it in said loop as well.

This is a simplified version of the script I'm attempting to write:

let mut port: &serial::windows::COMPort;
let mut success: bool = false;

loop
{
    if !success
    {
        if let Ok(fetched_port) = serial::open("COM3")
        { 
            port = fetched_port;
            success = true;
        }
        else
        {
            // Execute failsafe
        }
    }
    else
    {
        // Execute actual code
        port.read(); // The port variable is used here after being properly populated
    }
}

The issue seems to be in the "fetched_port" section(on the line: port = fetched_port).
As shown now it gives the following error:

expected &serial::serial_windows::COMPort, found struct serial::serial_windows::COMPort
help: consider borrowing here: &fetched_port

However, when I borrow the "fetched_port" it shows the following error:

fetched_port does not live long enough

borrowed value does not live long enoughrustc(E0597)
main.rs(222, 24): borrowed value does not live long enough
main.rs(228, 13): fetched_port dropped here while still borrowed
main.rs(237, 13): borrow later used here

It feels like I'm missing something obvious.
Any thoughts? Thank you!

Your borrowed fetched_port will be dropped at the end of the loop and thus your reference will point to an already freed object. And rust is preventing that error.

You need an "owned" instance instead of a reference. And because you might have or not have one, you should use the Option type:

// None means not initialized yet
let mut port = None;

loop{
    if let Some(port) = &port{
        port.read();
        // do stuff
        
        // do not forget to "continue" in order to avoid reopening the port
        continue;    
    }

    match serial::open("COM3"){
        Ok(p) => port = Some(p),
        Err(e) => { /* handle error */ }
    }
}

Hi Zarev,

Thank you for your reply.
I tried out the snippet you suggested and it already looks much nicer!
Sadly the borrow issue still persists, the snippet below still complains about borrowed values
on the "p" variable.

let mut port: Option<&serial::windows::COMPort>;

loop
{
    if let Some(port) = &port
    {
        port.read()
        continue;
    }

    // As suggested
    match serial::open("COM3") {
        Ok(p) => port = Some(p),
        Err(e) => ()
    }

    // Slightly adjusted
    if let Ok(mut p) = serial::open("COM3")
    {
        p.configure(&SETTINGS);
        p.set_timeout(Duration::from_millis(1000));

        port = Some(p);
    }
}

The error is the same as I posted before:

expected &serial::serial_windows::COMPort, found struct serial::serial_windows::COMPort
help: consider borrowing here: &p

This is not correct - you are telling the compiler that port must be a reference, but it cannot be a reference - it must be an "owned" value. Instead use:

let mut port = None;

Ah I misunderstood then! I adjusted it below.
Though now it gives this error (on this line: if let Some(port) = &port):

type annotations needed for std::option::Option<T>
cannot infer type for type parameter T declared on the enum Option

Full snippet:

let mut port = None;

loop
{
    if let Some(port) = &port
    {
        port.read()
        continue;
    }

    // As suggested
    match serial::open("COM3") {
        Ok(p) => port = Some(p),
        Err(e) => ()
    }

    // Slightly adjusted
    if let Ok(mut p) = serial::open("COM3")
    {
        p.configure(&SETTINGS);
        p.set_timeout(Duration::from_millis(1000));

        port = Some(p);
    }
}

Ah, it cannot infer the type, so you have to type it:

    let mut port: Option<serial::windows::COMPort> = None;

Note that I've removed the ampersand & because I still want an owned value

PS: there is a missing semicolon ; after port.read()

That fixed another issue!
Thank you for the catch on the semicolon, it hadn't errored out there, but it now was!
Somehow the issue is now back to why I added the "&" to the declaration of "port" as the port.read is complaining about not being.

Actually no, the error is slightly different, it's concerned about the read function:
(I've shortened the snippet for readability)

if let Some(port) = &port
{
    let mut signal: Vec<u8> = (0..255).collect();
    port.read(&mut signal[..]);
    continue;
}

throws error:

cannot borrow *port as mutable, as it is behind a & reference
port is a & reference, so the data it refers to cannot be borrowed as mutablerustc(E0596)
main.rs(220, 13): port is a & reference, so the data it refers to cannot be borrowed as mutable

just borrow it mutably (&mut port):

if let Some(port) = &mut port
{
    let mut signal: Vec<u8> = (0..255).collect();
    port.read(&mut signal[..]);
    continue;
}

That did the trick, thank you for all the help!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.