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 */ }
}
}
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:
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);
}
}
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