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?
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.
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.
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With