About Index on String

    let x = String::from("hello world");
    let y = x[..];
    println!("{}", y);

Here I thought x[..] should return &str,

impl ops::Index<ops::RangeFull> for String {
    type Output = str;

    fn index(&self, _index: ops::RangeFull) -> &str {
        unsafe { str::from_utf8_unchecked(&self.vec) }

but here the compiler throws error:

23 |     let y = x[..];
   |         ^ doesn't have a size known at compile-time
   = help: the trait `Sized` is not implemented for `str`

It actually returns str, so if I add &, it's ok then:

let y = &x[..];

Why we need to add &?

foo[i] is desugared to *Index::index(foo, i). I.e., there's an implicit dereference, so you don't have to write that out. Having to write *some_slice[i] += 1 would be way more annoying.

It's to differentiate between Index and IndexMut - &x[y] uses Index but &mut x[y] uses IndexMut, and Rust needs to know which one to call. There is one exception to this rule, and that is when the type implements Copy, and you can write x[y] which is equivalent to *&x[y] (it uses Index).

This is for consistency with other kinds of indexing. For example, if you have a Vec<i32>, you wouldn't want the_vector[5] to give you a reference, instead you want it to give you an integer. So just like the_vector[5] results in a i32 without the reference, x[..] will give you a str.