Why does the following code work?
use std::rc::Rc;
fn main () {
let c = vec![1, 2, 3, 4, 5];
let r = Rc::new(c);
println!("{:?}", (**r)[0]);
}
I can understand it working with single deference (println!("{:?}", (*r)[0]);
). But not able to understand it working with double-dereference too.
The dereference operator is also known as the indirection operator. Simply put, the dereferencing operator allows us to get the value stored in the memory address of a pointer. In Rust, we use the Deref trait to customize the behaviour of the dereferencing operator.
Vector is a module in Rust that provides the container space to store values. It is a contiguous resizable array type, with heap-allocated contents. It is denoted by Vec<T>. Vectors in Rust have O(1) indexing and push and pop operations in vector also take O(1) complexity.
'Rc' stands for 'Reference Counted'. See the module-level documentation for more details. The inherent methods of Rc are all associated functions, which means that you have to call them as e.g., Rc::get_mut(&mut value) instead of value. get_mut() . This avoids conflicts with methods of the inner type T .
In Rust, there are several ways to initialize a vector. In order to initialize a vector via the new() method call, we use the double colon operator: let mut vec = Vec::new();
Both, Rc and Vec implements Deref, whichs deref
-method is called with the *
.
let c = vec![1, 2, 3, 4, 5];
creates a Vec with the given elements with the vec!
-macro.
let r = Rc::new(c);
creates a Reference counted Object from the Vector. The Vector is moved into the RC.
println!("{:?}", (**r)[0]);
This one is a bit more tricky: *r
dereferences the Rc, so we get the underlying Vector. *rc
dereferences the Vector as a slice. slice[0]
indexes the first element of the slice, which results in the first element 1
. println!
finally prints the result.
It might be easier to understand what happens once we build a function prototype around the expression (**r)[0]
:
fn foo<T, U>(r: T) -> i32
where
T: Deref<Target=U>,
U: Deref<Target=[i32]>,
{
(**r)[0]
}
Playground
Rc<T>
, as is typical for most smart containers in Rust, implements Deref
so that it can be used as an ordinary reference to the underlying value. In turn, Vec<T>
implements Deref
so that it can be used as a slice (Target = [T]
). The explicit dereferencing *
, when performed twice, applies the two conversions in sequence.
Of course, usually you wouldn't need to do this, because Vec
also implements the Index
operator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With