Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Rust, how can a reference be a pointer to a pointer-to-a-pointer?

Tags:

rust

Today's Rust mystery is from section 4.9 of The Rust Programming Language, First Edition. The example of references and borrowing has this example:

fn main() {
    fn sum_vec(v: &Vec<i32>) -> i32 {
        return v.iter().fold(0, |a, &b| a + b);
    }

    fn foo(v1: &Vec<i32>) -> i32 {
        sum_vec(v1);
    }

    let v1 = vec![1, 2, 3];

    let answer = foo(&v1);
    println!("{}", answer);
}

That seems reasonable. It prints "6", which is what you'd expect if the v of sum_vec is a C++ reference; it's just a name for a memory location, the vector v1 we defined in main().

Then I replaced the body of sum_vec with this:

fn sum_vec(v: &Vec<i32>) -> i32 {
    return (*v).iter().fold(0, |a, &b| a + b);
}

It compiled and worked as expected. Okay, that's not… entirely crazy. The compiler is trying to make my life easier, I get that. Confusing, something that I have to memorize as a specific tic of the language, but not entirely crazy. Then I tried:

fn sum_vec(v: &Vec<i32>) -> i32 {
    return (**v).iter().fold(0, |a, &b| a + b);
}

It still worked! What the hell?

fn sum_vec(v: &Vec<i32>) -> i32 {
    return (***v).iter().fold(0, |a, &b| a + b);
}

type [i32] cannot be dereferenced. Oh, thank god, something that makes sense. But I would have expected that almost two iterations earlier!

References in Rust aren't C++ "names for another place in memory," but what are they? They're not pointers either, and the rules about them seem to be either esoteric or highly ad-hoc. What is happening such that a reference, a pointer, and a pointer-to-a-pointer all work equally well here?

like image 612
Elf Sternberg Avatar asked Apr 05 '17 17:04

Elf Sternberg


People also ask

Is a reference a pointer to a pointer?

A pointer to reference is illegal in C++, because -unlike a pointer- a reference is just a concept that allows the programmer to make aliases of something else. A pointer is a place in memory that has the address of something else, but a reference is NOT.

Is a Rust reference a pointer?

A pointer is a general concept for a variable that contains an address in memory. This address refers to, or “points at,” some other data. The most common kind of pointer in Rust is a reference, which you learned about in Chapter 4. References are indicated by the & symbol and borrow the value they point to.

How do you get a pointer from a reference?

Once a reference is established to a variable, you cannot change the reference to reference another variable. To get the value pointed to by a pointer, you need to use the dereferencing operator * (e.g., if pNumber is a int pointer, *pNumber returns the value pointed to by pNumber .

What is a difference between reference and pointer?

References are used to refer an existing variable in another name whereas pointers are used to store address of variable. References cannot have a null value assigned but pointer can. A reference variable can be referenced by pass by value whereas a pointer can be referenced by pass by reference.


1 Answers

The rules are not ad-hoc nor really esoteric. Inspect the type of v and it's various dereferences:

fn sum_vec(v: &Vec<i32>) {
    let () = v;
}

You'll get:

  1. v -> &std::vec::Vec<i32>
  2. *v -> std::vec::Vec<i32>
  3. **v -> [i32]

The first dereference you already understand. The second dereference is thanks to the Deref trait. Vec<T> dereferences to [T].

When performing method lookup, there's a straight-forward set of rules:

  1. If the type has the method, use it and exit the lookup.
  2. If a reference to the type has the method, use it and exit the lookup.
  3. If the type can be dereferenced, do so, then return to step 1.
  4. Else the lookup fails.

References in Rust aren't C++ "names for another place in memory,"

They absolutely are names for a place in memory. In fact, they compile down to the same C / C++ pointer you know.

like image 166
Shepmaster Avatar answered Sep 20 '22 16:09

Shepmaster