this article assumes you have some basic knowledge about Rust smart pointers.
the dereference (*) operator
dereference operator *
is used for getting the actual value from a reference:
in the above example, b
is a reference to a
, *b
will return the value that b
pointing to.
the smart pointers
Box<T>
here is an example of how you can init and modify the value of a Box:
in the above example, I init a box with value 6 inside, then I changed the value to 7, and check the value inside the box with assert to ensure the change is affected.
in the first example of this post, we apply the dereference to a reference which is &i32
, but the data type of b now is Box<i32>
, how can we apply to dereference to a Box<i32>
?
the answer is the Box<T>
is implemented the trait Deref and DerefMut, so when you write *b
, the compiler implicitly translates it to *(b.deref())
if you want to get the value or *(b.deref_mut())
if you want to change the value.
if you have a Box<T>
, the deref
method returns a &T
, and deref_mut
returns a &mut T
. after calling the deref
method, you now have a reference to the actual value, therefore you can use the dereference operator on these references.
the above snippet can be explicitly rewritten as below:
firstly, we create a new box
to hold the value 6. then we call deref_mut
to get a &mut i32
, in order to change the value inside the box. finally, we get a read-only reference &i32
to the value inside the box, by calling deref
.
Rc<T>
Rc<T>
is quite similar to Box<T>
, except that you can only read data in Rc, you cannot edit it. because Rc only implements the trait Deref
, not implement DerefMut
. Therefore, you can only call the deref
method on Rc only, there is no such method deref_mut
.
RefCell<T>
if you write code like the above example, you will get this error: type RefCell<{integer}>
cannot be dereferenced. it’s because RefCell<i32>
doesn’t implement either Deref
or DerefMut
traits. you can check this out on the docs of RefCell.
the way RefCell<T>
works is a bit different from Box<T>
, to read or modify data inside RefCell
you need to explicitly call method borrow
or borrow_mut
respectively.
borrow
will return a Ref<T>
which implements trait Deref
, and borrow_mut
will return a RefMut<T>
which implements both DerefMut
and Deref
.
because Ref<T>
and RefMut<T>
implements Deref
, so we can use dereference operator on them.
so you can write code like this:
or, if you want more explicitly, I have this code:
if you run the above code, you will get this error: already mutably borrowed: BorrowError
.
it’s because, in line number 2, you call borrow_mut
, and in line number 3 you call deref_mut
to get a mutability reference.
in line number 5, you call borrow
in order to read the data inside RefCell
, which is forbidden by Rust. you can’t have a read-only reference to the value that currently has a mutability reference to prevent the race condition.
so you can rewrite it as below:
|
|
in the above code, the borrow_mut
and deref_mut
are put in the first block, so at the end of the first block, the mutability reference is dropped, there is no mutability reference to the value now. that is why in the second block, you can (read-only) borrow as much as you want from the RefCell
.