Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the return type of the indexing operation?

Tags:

rust

I am trying, quite unsuccessfully, to play around with slices.

I have reduced my first issue to:

fn at<'a, T>(slice: &'a [T], index: usize) -> &'a T {
    let item = slice[index];
    item
}

It is my expectation that the return type of slice[index] be a reference, given the documentation:

pub trait Index<Index> {
    type Output;
    fn index(&'a self, index: &Index) -> &'a <Self as Index<Index>>::Output;
//                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}

However, the compiler gives me an error:

error[E0308]: mismatched types
 --> src/main.rs:3:5
  |
3 |     item
  |     ^^^^ expected reference, found type parameter
  |
  = note: expected type `&'a T`
             found type `T`

Which I interpret as meaning that the type of item does not match the return type of the function (I introduced item solely for debugging purpose, to split expression evaluation from return).

If I switch the return type to T, which is the type of item, I get another error message:

error[E0508]: cannot move out of type `[T]`, a non-copy slice
 --> src/main.rs:2:16
  |
2 |     let item = slice[index];
  |                ^^^^^^^^^^^^
  |                |
  |                cannot move out of here
  |                help: consider using a reference instead: `&slice[index]`

After tinkering a bit, I found two work-arounds:

fn at<'a, T>(slice: &'a [T], index: usize) -> &'a T {
    &slice[index]
//  ^
}

fn at<'a, T>(slice: &'a [T], index: usize) -> &'a T {
    let ref item = slice[index];
//      ^~~
    item
}

forcing the type to be a reference does the trick.

Why are these shenanigans necessary in the first place? Am I doing something wrong?

like image 261
Matthieu M. Avatar asked Jan 10 '15 17:01

Matthieu M.


People also ask

What is the return type of index?

The INDEX function returns a value or the reference to a value from within a table or range. There are two ways to use the INDEX function: If you want to return the value of a specified cell or array of cells, see Array form. If you want to return a reference to specified cells, see Reference form.

What is the purpose of indexed?

You can use an index to help Access find and sort records faster. An index stores the location of records based on the field or fields that you choose to index. After Access obtains the location from the index, it can then retrieve the data by moving directly to the correct location.


2 Answers

This is a bit of helpful ergonomics that the compiler does for you in order to make the code look a bit nicer.

The return value of the Index trait is a reference, but the compiler automatically inserts a dereference for you when you use the sugared syntax []. Most other languages would just return the item from the array (copying it or returning another reference to the object, whatever is appropriate).

Due to Rust's importance of move / copy semantics, you can't always make a copy a value, so in those cases, you will usually use a &:

let items = &[1u8, 2, 3, 4];

let a: u8 = items[0];
let a: u8 = *items.index(&0); // Equivalent of above

let b: &u8 = &items[0];
let b: &u8 = &*items.index(&0); // Equivalent of above

Note that the indexing value is also automatically taken by reference, similar to the automatic dereference.

like image 153
Shepmaster Avatar answered Oct 21 '22 08:10

Shepmaster


No, you're doing everything correctly. While index() method does return a reference, when it is invoked in an indexing operation its result is dereferenced automatically. This is done so the indexing is more natural: in every language where some kind of indexing operator exists (mainly C and C++), it returns values themselves, not the references into containers.

In order to obtain a reference into the collection you have to either apply a reference operator explicitly (like in your first "workaround") or to use reference pattern (like in the second one).

like image 25
Vladimir Matveev Avatar answered Oct 21 '22 09:10

Vladimir Matveev