I'm writing a chat server over TCP as a learning project. I've been tinkering with the ws crate today, but I've come across an issue. This is the code I wrote, modifying their server example.
extern crate ws;
extern crate env_logger;
use ws::listen;
fn main() {
// Setup logging
env_logger::init().unwrap();
// Listen on an address and call the closure for each connection
if let Err(error) = listen("127.0.0.1:3012", |out| {
let mut message: String;
// The handler needs to take ownership of out, so we use move
move |message| {
message = message.trim();
// Handle messages received on this connection
println!("Server got message '{}'. ", message);
// Use the out channel to send messages back
out.send(message)
}
}) {
// Inform the user of failure
println!("Failed to create WebSocket due to {:?}", error);
}
}
When I try compiling it I get an error:
error: the type of this value must be known in this context
--> src/main.rs:15:23
|
15 | message = message.trim();
| ^^^^^^^^^^^^^^
Why is this happening? How may I fix this?
move |message|
shadows the message
variable you've declared outside the closure. So within the closure.. message
is said to be a ws::Message
... except you've done this:
message = message.trim();
The compiler goes "oh no! trim()
? That doesn't exist for ws::Message
".. and so now it doesn't quite know what to do.
The first fix involves delegating the trim()
call to the client who sends the message.
The fix is to not make any assumptions about what the message is inside this closure. If you keep this:
move |message|
..but remove the trim()
call, the compiler happily infers its type as ws::Message
and will build:
if let Err(error) = listen("127.0.0.1:3012", |out| {
// The handler needs to take ownership of out, so we use move
move |message| {
// --- REMOVED trim() call ---
// Handle messages received on this connection
println!("Server got message '{}'. ", message);
// Use the out channel to send messages back
out.send(message)
}
}
This gives you the option of delegating the trim()
call to the client instead.
Option 2 involves inspecting the type of message you've received, and making sure you trim it only if it is text:
// The handler needs to take ownership of out, so we use move
move |mut message: ws::Message| {
// Only do it if the Message is text
if message.is_text() {
message = ws::Message::Text(message.as_text().unwrap().trim().into());
}
// Handle messages received on this connection
println!("Server got message '{}'. ", message);
// Use the out channel to send messages back
out.send(message)
}
This is perhaps a little more verbose than it needs to be.. but hopefully it shows you what the actual issue is with your original snippet of code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With