getting vector from an Arc Mutex

Viewed 339

So I have this code:

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

fn main() {
    
    let array = vec!("test", "work", "please");
    let test = Arc::new(Mutex::new(array));
    
    let getter = test.lock().unwrap();
    println!("{:?}", getter);
    
    for item in getter {
        println!("{}", item);
    }
}

it throws an error saying:

error[E0277]: `MutexGuard<'_, Vec<&str>>` is not an iterator
  --> src/main.rs:11:17
   |
11 |     for item in getter {
   |                 ^^^^^^ `MutexGuard<'_, Vec<&str>>` is not an iterator
   |
   = help: the trait `Iterator` is not implemented for `MutexGuard<'_, Vec<&str>>`
   = note: required because of the requirements on the impl of `IntoIterator` for `MutexGuard<'_, Vec<&str>>`

Which, okay fine. But I am able to do let getter = test.lock().unwrap().len(); and that gets the length correctly. So why does it know its an array in the second case but not the first?

2 Answers

getter is a MutexGuard which implements Deref<Target = Vec<&str>>. When you call a method on it like .len(), it's automatically dereferenced into the Vec because there's no .len() method on MutexGuard. The same is not done automatically by a for loop. You can either force a manual dereference:

for item in &*getter {

or you can call .iter() on it which automatically dereferences it:

for item in getter.iter() {

Code:

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

fn main() {
    let array = vec!["test", "work", "please"];
    let test = Arc::new(Mutex::new(array));

    let getter = test.lock().unwrap();
    println!("{:?}", getter);

    for item in &*getter {
        println!("{}", item);
    }

    for item in getter.iter() {
        println!("{}", item);
    }
}

Playground

The .len() access works because of deref coercion (as the MutexGuard implements Deref), but this does not apply when checking if a value implements Iterator or IntoIterator.

You can manually deref-and-reborrow to make that work:

    for item in &*getter {
        println!("{}", item);
    }
Related