fn main() {
let listener = match TcpListener::bind("127.0.0.1:7878") {
Ok(v) => {
println!("Server initiated")
}
Err(e) => {
println!("Error: {}", e.to_string())
}
};
//println!("Your server is running on: {}", listener.);
for stream in listener.incoming() { // why is this "incoming() method unavailable?
let stream = stream.unwrap();
// show client connection
println!("[Client connected]: {:?}", stream.peer_addr());
// handle each connection
handle_connection(stream);
}
}
Why does match() prevent listener from being able to access its incoming() method?
As opposed to this version:
[2]
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
println!("Your server is running on: {:?}", listener);
for stream in listener.incoming() { //"listener" can now access "incoming()"
let stream = stream.unwrap();
// show client connection
println!("[Client connected]: {:?}", stream.peer_addr());
// handle each connection
handle_connection(stream);
}
}
The listener is passed into the match, and you're throwing it away by not using the v variable in your Ok arm. You could change it to this:
Ok(v) => {
println!(...);
v
}
which would return the listener when there was no error, however you will then run into the issue because the types of the match arms do not agree. The original code panics on error, so the exact solution depends on what you want to happen when there is an error.
No, it has to do with the fact that both of your match cases, and thus the entire match expression, returns the unit type () because that's what println returns. Thus the value of listener will be (). In Ok(v) you unwrap the listener and assign it to v, but then you don't do anything with v, just let it go away when the match expression is done.
let listener = match TcpListener::bind("127.0.0.1:7878") {
Ok(v) => {
println!("Server initiated");
v
}
Err(e) => {
println!("Error: {}", e.to_string());
e // this is a problem now because e is not the same type as v
}
};
If I only wanted to output the error message in case of an error, what would be the way to do it?
Heh, Ok, but in that case I could have done this from the get going.
I guess what I'm trying to do instead is use a match control flow that lets me call different functions in the case of each match arm. I assume that isn't possible ... !?
It's not a "not", that's the "never" or "bottom" type, ie. the type of values that aren't. An expression that results in control flow leaving the scope or looping infinitely (together these are called "diverging" expressions) doesn't actually end up producing a value, so it has a type that can coerce to any other type, because it doesn't really need to be type checked.
To clarify, the type of the return expression itself is bottom, independent of what the type of the value being returned is. For this reason, I don't like the terminology whereby an expression "returns" a value; it's confusing. An expression yields a value â or, if it diverges, it doesn't yield any value, so it's got the never type.
Other diverging expressions with which this logically works are:
let never_reached: ! = loop {
// infinite
};
while condition {
let never_reached: ! = break;
}
while condition {
let never_reached: ! = continue;
}
let never_reached: ! = panic!(); // todo!(), etc.
! here is the "never type" -- it's a type which can never be instantiated. It can coerce to any other type. It's used for expressions where control flow diverges from the "normal" path, and the code after it [1] cannot be reached. For example:
let s: String = String::new();
// | ^^^^^^^^^^^^^ expression with type `String` ...
// |
// |________ ...gets assigned to new binding `s`
Versus
let s: String = return Whatever;
// | ^^^^^^^^^^^^^^^ expression with type `!` ...
// |
// |________ ...control flow has diverged so we can never actually
// assign to `s`. But the code still compiles because
// the `!` type coerces to `String`, so there's not
// a type check error between the left and right side
Or in the context of a match:
let s: String = match some_result { // --- the match as a whole ---+
Ok(_) => { String::new() }, // must be a `String`, so |
Err(_) => { return "dang it!" }, // every match arm must |
}; // --- also be a `String` -----+
That would mean the return value will always be the Ok variant; it is never the Err variant. (However you won't see this much until the ! type stabilizes more; in the mean time, an empty enum such as Infallible can be used instead, as empty enums are another type which can never be instantiated.)