Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

TcpStream::connect – match arms have incompatible type

I’m trying to write basic networking code in Rust, but running into an error I don’t understand. I have been using match statements to error check everything in Rust so far, but when I try to error check TcpStream::connect(), I get an unexpected error:

My code:

use std::net::TcpStream;

fn main() {
    let mut server = match TcpStream::connect("127.0.0.1:23456"){
        Ok(x) => x,
        Err(x) => println!("Could not connect to server: {x}"),
    };
}

The compiler error:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

error[E0308]: `match` arms have incompatible types
 --> src/main.rs:8:19
  |
6 |       let mut server = match TcpStream::connect("127.0.0.1:23456"){
  |  ______________________-
7 | |         Ok(x) => x,
  | |                  - this is found to be of type `TcpStream`
8 | |         Err(x) => println!("Could not connect to server: {x}"),
  | |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
                        expected struct `TcpStream`, found `()`
9 | |     };
  | |_____- `match` arms have incompatible types
  |

Every other time I use a match statement it allows me to destructure the Result type into a return value in the OK case (as above), or an error string in the error case.

It is the case that TcpStream::connect() returns a TcpStream, but why is the compiler insisting that the error case also needs to return a TcpStream?

>Solution :

The value of the match statement gets assigned to server.

However, both branches of your match statement return a different type.

  • Ok(x) returns x, which is of type TcpStream.
  • Err(x) returns the result of println!(), which has the return value ().

TcpStream and () are incompatible.

Just think about the code after the match statement. What should the server variable be? You don’t stop the execution when the error happens, you simply println!() and continue. So something has to be written to the server variable.

If you panic!() instead of println!(), meaning print and abort, then it compiles because it knows that the Err case won’t continue afterwards:

use std::net::TcpStream;

fn main() {
    let mut server = match TcpStream::connect("127.0.0.1:23456") {
        Ok(x) => x,
        Err(x) => panic!("Could not connect to server: {x}"),
    };
}
thread 'main' panicked at 'Could not connect to server: Connection refused (os error 111)', src/main.rs:6:19

That said, if this is your desired behavior, there is a short form for it:

use std::net::TcpStream;

fn main() {
    let mut server = TcpStream::connect("127.0.0.1:23456").expect("Could not connect to server");
}
thread 'main' panicked at 'Could not connect to server: Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }', src/main.rs:4:60

I recommend handling the error properly, though.

There are many ways to do that, so this part will be opinionated.

I personally like miette (an alternative would be anyhow):

use miette::{Context, IntoDiagnostic};
use std::net::TcpStream;

fn main() -> miette::Result<()> {
    let mut _server = TcpStream::connect("127.0.0.1:23456")
        .into_diagnostic()
        .wrap_err("Could not connect to server.")?;

    // Do something with server

    Ok(())
}
Error: 
  × Could not connect to server.
  ╰─▶ Connection refused (os error 111)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading