Reputation: 3509
Acessing a field of a struct for reading rust playpen:
use std::sync::Mutex;
#[deriving(Show)]
struct Test{
a: uint,
}
impl Test{
fn new() -> Test{
Test { a: 0}
}
fn get(&self) -> uint {
self.a
}
}
fn main() {
let t = Test{a: 42};
let m = Mutex::new(Test::new());
println!("Getting t: {} where t.a = {}", t.get(), t.a);
{
let m2 = m.lock();
println!("m2.a = {}", m2.a); // works
//println!("m2.get() = {}", m2.get()); // error: cannot borrow immutable local variable `m2` as mutable
}
}
So in this case accessing the field m2.a
works, but calling m2.get()
requires m2
to be mutable although get does not mutate anything and is not declared to be mutating anything especially not &self
.
To make this code work I could just declare m2
with let mut m2 = m.lock();
and everything works fine, but why do I need that mut here and is there a better way to call m2.get()
without declaring m2
mutable in a similar way as it works for t
that I declare as non mutable and which still permits me to call t.get()
.
Upvotes: 3
Views: 1591
Reputation: 7246
This is due to a slight limitation of the Deref
family of traits right now - namely implementing both Deref
and DerefMut
for the same type right now is slightly broken due to the behavior of autoderef for methods, namely, deref_mut
is always called, even to get &
references.
As a result, MutexGuard
needs to be mutable for you to call methods which require &self
. Usually, immutable uses of Mutex
are rare, and RWLock
, which supports both read and write locks separately, is better suited to this use case as it allows concurrent read locks.
Upvotes: 3
Reputation: 28117
Yeah, the compiler tends to prefer to call deref_mut
over deref
in case both are available. In your case, deref
would suffice and work, but the implicit dereferencing machinery picks deref_mut
instead and then complains about m2
not being mutable.
To add to what reem said, the lock object does implement both, Deref
and DerefMut
and if you don't need a mutable borrow, you can get the immutable one by explicitly reborrowing it immutably:
println!("m2.get() = {}", (&*m2).get());
and if this kind of access is all you need you can also write
let m2 = m.lock();
let m2 = &*m2;
which then allows
println!("m2.get() = {}", m2.get());
Upvotes: 4