I am new to Rust and am trying to learn the idiomatic way to work with the borrow checker.
I'm trying to write a simple function that takes in a slice (generic over the data type) and returns the last element, in such a way that I can mutate the slice afterward. The naive implementation gives me an error:
fn last_element<T>(list: &[T]) -> T {
list[list.len() - 1]
}
fn main() {
let mut slice = [1, 2, 3, 4, 5];
let x = last_element(&slice);
println!("{}", x);
// I want to be able to mutate slice after extracting last element
slice[2] = 17;
}
The error is cannot move out of type
[T], a non-copy slice
. I see that one workaround is to have the function return a reference:
fn last_element<T>(list: &[T]) -> &T {
&list[list.len() - 1]
}
fn main() {
let mut slice = [1, 2, 3, 4, 5];
let x = last_element(&slice);
println!("{}", x);
// I want to be able to mutate slice after extracting last element
slice[2] = 17;
}
But then I get an error for slice[2] = 17
because the slice was borrowed when x
was assigned. I do want to be able to mutate after calling last_element
. The one workaround I found was to dereference x
, which I believe consumes the borrow:
fn last_element<T>(list: &[T]) -> &T {
&list[list.len() - 1]
}
fn main() {
let mut slice = [1, 2, 3, 4, 5];
let x = *last_element(&slice);
println!("{}", x);
// I want to be able to mutate slice after extracting last element
slice[2] = 17;
}
Is this the most idiomatic way to accomplish the aim of being able to get the last element of a slice and still mutate the slice afterward? Or should I never even be doing the mutation afterward if I am writing good code?