No method named `incoming` found for unit type `()` in the current scope

[1]

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);
    }
}

Thanks.

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.

3 Likes

Just to make sure I understand this correctly: it has something to do with the borrowing mechanism of Rust; correct?

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.

5 Likes

I see what you mean:

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?

.unwrap() it.

1 Like

Heh, Ok, but in that case I could have done this from the get going. :grin:

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 ... !?

You can use match for control flow like this:

fn main() {
    match std::net::TcpListener::bind("127.0.0.1:7878") {
        Ok(listener) => {
            println!("Server initiated");
            for stream in listener.incoming() {
                let stream = stream.unwrap();
                println!("[Client connected]: {:?}", stream.peer_addr());
                handle_connection(stream);
            }
        }
        Err(e) => {
            println!("Error: {e}")
        }
    };
}

Each match arm evaluates to the unit type (), and that value is ignored by not assigning the match expression to a variable.

2 Likes

You can return in the Err match arm, which "returns" a ! to the match and makes it work.

2 Likes

This is kind of mind-boggling to me; could you please elaborate on why return - in this case - returns a !(not)?

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.
2 Likes

! 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` -----+

The Err arm acts like my example above.


If you see something like this:

pub fn exit(code: i32) -> ! { /* ... */ }

That means the function never returns.

If you saw something like

fn try_me() -> Result<Happiness, !> { /* ... */ }

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.)


  1. in terms of control flow â†Šī¸Ž

2 Likes

Thank you very much for your detailed explanations. It's going to take me some time to wrap my head around this "never" / "bottom" type concept.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.