I have a simple structure with a questions variable defined as follows:
struct Store {
questions: Arc<RwLock<HashMap<QuestionId, Question>>>,
}
HashMap<QuestionId, Question>
- The hashmap itself containing id and data.RwLock<>
- Preventing multiple writes to data.Arc<>
- Allows multiple pointers to same complex data structure.Sorry if this is a primitive question but:
How can I get the length of the HashMap<>
that is wrapped in RwLock<>
and Arc<>
?
I could not seem to find anything in the Arc documentation either (even though I know it is not responsible for tasks like this).
For some context, this is a store intended to be used by a Rest API Web Server implemented with the Tokio framework.
Although previous answers explain how to get HashMap
's length, they do not explain why it works. I'll try to explain the latter, so you will understand this mechanism in the future.
Calling methods of "inner" objects on the "outer" objects is possible thanks to the Deref
trait and deref coercion.
Deref
trait defines semantics of the dereferencing operator *
. For example when you dereference String
you get str
and when you dereference Vec<T>
you get [T]
. Similarly smart pointers like Box<T>
or Arc<T>
give you T
when you dereference them.
You could do this dereferencing manually:
let map = Arc::new(RwLock::new(HashMap::from([("a", "b"), ("c", "d")])));
let len = (&*(&*map).read().await).len();
However this quickly gets very messy. Luckily to help comes deref coercion and auto-magically performs this series of dereferencing. The details of how it works are described in the linked documentation, but the gist of it is that when you call method foo
on object bar: Bar
the compiler will do the following:
Bar
has method foo
, if not thenBar
implements Deref<Target=Baz>
and if it does thenBaz
has method foo
, if not thenDeref
Target
until it finds type that implements method foo
So when you write
let len = map.read().await.len();
the compiler does the following:
read
on Arc<RwLock<_>>
and doesn't find it.read
on RwLock<_>
.await
ing result you have a RwLockReadGuard<'_, HashMap<_, _>>
.len
on RwLockReadGuard<_>
and doesn't find it.HashMap<_>
.len
method so it calls it.