Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does indexing need to be referenced? [duplicate]

I'm currently learning Rust coming from JavaScript.

My problem is the following:

fn main() {
    let name = String::from("Tom");
    let sliced = name[..2];
    println!("{}, {}", name, sliced);
}

This doesn't work. Saying "doesn't have a size known at compile-time".

To fix this I need to add & the referencing operator.

fn main() {
    let name = String::from("Tom");

    let sliced = &name[..2];

    println!("{}, {}", name, sliced);
}

I know I need to add & before name and & is the referencing operator. But I just don't know why I actually need to do that?

By referencing a variable the reference refers to variable name but does not own it. The original value will not get dropped if my reference gets out of scope. Does that mean that the variable gets out of scope if i do name[...] and the variable gets dropped and because of that i need to create a reference to it to prevent that?

Could somebody explain me that?

like image 549
Ifaruki Avatar asked Jan 25 '23 14:01

Ifaruki


1 Answers

I know I need to add & before name and & is the referencing operator. But I just don't know why I actually need to do that.

I understand where the confusion come from, because when you look at index() it returns &Self::Output. So it already returns a reference, what's going on?


It's because the indexing operator is syntactic sugar and uses the Index trait. However, while it uses index() which does return a reference, that is not how it is desugared.

In short x[i] is not translated into x.index(i), but actually to *x.index(i), so the reference is immediately dereferenced. That's how you end up with a str instead of a &str.

let foo = "foo bar"[..3]; // str
// same as
let foo = *"foo bar".index(..3); // str

That's why you need to add the & to get it "back" to a reference.

let foo = &"foo bar"[..3]; // &str
// same as
let foo = &*"foo bar".index(..3); // &str

Alternatively, if you call index() directly, then it isn't implicitly dereferenced of course.

use std::ops::Index;

let foo = "foo bar".index(..3); // &str

Trait std::ops::Index - Rust Documentation:

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

The same applies to IndexMut.

like image 104
vallentin Avatar answered Jan 27 '23 03:01

vallentin