2

I'm trying to play about with multithreading in Rust and I've come across something I'd consider rather trivial. Here's the code snippet:

use std::thread;
use std::sync::{Arc, Mutex};

fn main() {
    let vec: Vec<i32> = vec!(1, 2, 3);
    let shared = Arc::new(Mutex::new(vec));

    let clone = shared.clone();

    let join_handle = thread::spawn(move || {
        let mut data = clone.lock().unwrap();
        data.push(5);
    });

    join_handle.join().unwrap();

    let clone = shared.clone();
    let vec = try!(clone.lock());

    println!("{:?}", *vec);
}

So, my issue is on the line let vec = try!(clone.lock()). This causes the following compiler error:

error: mismatched types [E0308]
return $ crate :: result :: Result :: Err (
       ^
note: in this expansion of try! (defined in <std macros>)
help: run `rustc --explain E0308` to see a detailed explanation
note: expected type `()`
note:    found type `std::result::Result<_, _>`

To me, this doesn't make a lot of sense. clone.lock() returns TryLockResult<MutexGuard<T>>, which essentially translates to Result<MutexGuard<T>, PoisonedError<MutexGuard<T>>, which means try!(clone.lock()) should resolve to either a throw or MutexGuard<T>.

Am I fundamentally misunderstanding something here?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Dan
  • 10,282
  • 2
  • 37
  • 64

1 Answers1

2

Running the 'explain' on rustc will explain this error - I thought I already had, but I guess not.

This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.

For example:

```
let x: i32 = "I am not a number!";
//     ~~~   ~~~~~~~~~~~~~~~~~~~~
//      |             |
//      |    initializing expression;
//      |    compiler infers type `&str`
//      |
//    type `i32` assigned to variable `x`
```

Another situation in which this occurs is when you attempt to use the `try!`
macro inside a function that does not return a `Result<T, E>`:

```
use std::fs::File;

fn main() {
    let mut f = try!(File::create("foo.txt"));
}
```

This code gives an error like this:

```
<std macros>:5:8: 6:42 error: mismatched types:
 expected `()`,
     found `core::result::Result<_, _>`
 (expected (),
     found enum `core::result::Result`) [E0308]
```

`try!` returns a `Result<T, E>`, and so the function must. But `main()` has
`()` as its return type, hence the error.

In other words, the error is not with the type of Mutex; it's because I'm using try! within the main function; try! enforces the enclosing function return a Result<_, _>, but the main function must return ().

If we look at the expanded code:

let vec =
    match clone.lock() {
        ::std::result::Result::Ok(val) => val,
        ::std::result::Result::Err(err) => {
            return ::std::result::Result::Err(::std::convert::From::from(err))
        }
    };

The reason why try! yells at you is because the return statement doesn't apply to the block in match, it applies to the enclosing method.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Dan
  • 10,282
  • 2
  • 37
  • 64