Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dereferencing Rc<Vec<T>> confusion in Rust

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.

like image 757
soupybionics Avatar asked Feb 28 '18 10:02

soupybionics


People also ask

What does Dereferencing do in Rust?

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.

What is VEC in Rust?

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.

What is RC Rust?

'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 .

How do you initialize VEC in Rust?

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();


2 Answers

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.

like image 200
Tim Diekmann Avatar answered Nov 15 '22 10:11

Tim Diekmann


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.

like image 41
E_net4 stands with Ukraine Avatar answered Nov 15 '22 11:11

E_net4 stands with Ukraine