I am completely new to Rust. When attempting to create a client/ server over tcp listener, I first create a function that listen on a specific address port. The code looks like
let listener = TcpListener
::bind(format!("{address}:{port}"))
.unwrap();
listener.set_nonblocking(true);
for stream in listener.incoming() { ... }
But it looks like the method unwrap() is discouraged. But many examples I found online, including official doc, employ unwrap(). If it's not recommended, what's a better way to accomplish such task?
I tried something like following, but I do not know how to iterate over the stream.
let result: Result<Result<(), Error>, Error> = TcpListener
::bind(format!("{address}:{port}"))
.map(|listener| listener.set_nonblocking(true))
// here how to iterate over the stream like the official doc example? => for stream in listener.incoming() { ... }
TcpListener
::bind(format!("{address}:{port}"))
.and_then(|listener| listener.set_nonblocking(true)) // this returns only one layer of Result
.map(|listener| {
for stream in listener.incoming() { ... }
})
Note that you still need to handle the Result, usually by changing your function to return it.
Another approach is to use the ? operator, which unwraps the result or returns early with the error:
fn handle_connections(address: &str, port: u16) -> std::io::Result<()> {
let listener = TcpListener
::bind(format!("{address}:{port}"))?;
listener.set_nonblocking(true)?; // this also returns a result
for stream in listener.incoming() { ... }
}
If you need your function to return a different error type you can use Result::map_err().
There's no one-size-fits-all solution. As the programmer, you need to decide what should happen when the program can't bind to the port that it requested. unwrap() does this by terminating the program immediately with a panic message that's useful for developers but pretty inscrutable to ordinary users. This is the simplest approach, which is why it's used in documentation, but usually isn't the best choice. If you're just writing something quick-and-dirty, though, it may be sufficient.
Other options include panicing with a nicer message (expect), returning a Result to the caller (who will then face the same problem), trying a different port/interface, giving up on networking altogether but otherwise continue running, etc.