I'm new to rust, and I'm trying to code a program that opens a websocket for 10 seconds, receive the data from it and then stops. The piece of code is the following.
let now = Instant::now();
while let n=now.elapsed().as_secs() < 10 {
let msg = socket.read_message().expect("Error reading message");
let msg = match msg {
tungstenite::Message::Text(s) => { s }
_ => { panic!() }
};
let parsed: serde_json::Value = serde_json::from_str(&msg).expect("Can't parse to JSON");
let price_str=parsed["p"].as_str().unwrap();
let price: f32 = price_str.parse().unwrap();
write!(f,"1 \t").expect("unable to write");
write!(f, "\t\t {} \n", price).expect("unable to write");
println!("{}",n);
}
n becomes false after 10 seconds, but the loop never ends. What I'm doing wrong?
Thanks for your help.
while let n
binds the result of the expression now.elapsed().as_secs() < 10
to n
. This binding can never fail, thus your loop never exits.
The compiler emits a lint to prevent such mistakes:
warning: irrefutable `while let` pattern
--> src/lib.rs:24:11
|
24 | while let n = now.elapsed().as_secs() < 10 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(irrefutable_let_patterns)]` on by default
= note: this pattern will always match, so the loop will never exit
= help: consider instead using a `loop { ... }` with a `let` inside it
To fix your snippet, you'll need to remove the let n
part. Or in a more unusual and rather unidiomatic manner, you can pattern match on the value returned by now.elapsed().as_secs() < 10
through:
while let true = now.elapsed().as_secs() < 10 {
// do your thing
}
If you want access to the loop control variable, you can still bind it to a variable through:
let now = std::time::Instant::now();
while let n @ true = now.elapsed().as_secs() < 10 {
println!("loop_control={}", n)
}
As @Jmb mentions in a comment, there is another issue that's not a compiler error: The loop body may block indefinitely, thus rendering the timeout ineffective.