I don't understand basic reference

I am picking up rust again, but I am really confused about basic things.
For instance:

let v = vec![String::from("hello"), String::from("world")];
let s = &v[0]; // 1

How does rust (compiler) evaluate &v[0] ? Where does the borrow checker comes in and say "Ok, you're good" or "nope" ?
I mean v[0] would not pass the borrow checker as you cannot move a String out of a vector right ? But for evaluating &v[0] don't you have to first evaluate the operator of the reference operator ?

Is v[0] still a place expression when v is a vector ?
Sorry, I am not sure my question makes sense..

1 Like

Yes. collection[index] is sugar for *Index::index(&collection, index) (note the implicitly added dereference).


From the Index trait docs:

container[index] is actually syntactic sugar for *container.index(index)

You can also see from the trait docs that the method index always returns a reference. Thus, by using & in here, you effectively write the following code:

let v = vec![String::from("hello"), String::from("world")];
let s = &*v.index(0); // 1

This constitutes a reborrow, but you can essentially imagine that the & and * cancel each other out, making this equivalent to just calling index. The important thing to notice is that * (at least for the borrow checker) does not eagerly take ownership of the value being referred to (sometimes that wouldn't even be possible) - this is also why you can turn a String s into a &str via &*s.


Ooh, indeed, dereference expressions are place expression.
And in let s = v[0] it is evaluated in a value expression context, hence denotes the value held in the memory location represented by the place expression; while in let r = &v[0] v[0] is evaluated in a place expression context hence only reference the memory location, correct ?


1 Like

this is also why you can turn a String s into a &str via &*s.

Huh ??!

Is it because *s is equivalent to *Deref::deref(&s) which would be of type str ?

Is &*s actually useful in some situation ? Or would you rather simply use &s ?

fn main() {
    let s = String::new();
    match &s { // &*s works here
        "" => (),
        _ => (),

error[E0308]: mismatched types
 --> src/main.rs:4:9
3 |     match &s {
  |           -- this expression has type `&String`
4 |         "" => (),
  |         ^^ expected `&String`, found `&str`
  = note: expected reference `&String`
             found reference `&'static str`
1 Like

That sounds correct.


Yes, mainly for invoking Deref.