Если вы работаете с простыми типами, такими как i32
и другими небольшими структурами фиксированного размера, эти типы обычно реализуют Copy
. Эта черта является маркером, который указывает компилятору копировать значения в памяти в ситуациях, когда они иначе были бы перемещены. Фактически, это то, что означает сообщение об ошибке, когда оно ссылается на non-copy slice
: если элементы не реализуют Copy
, тогда ему придется их перемещать, и это оставит срез в недопустимом состоянии, что не является допускается.
Если вы ограничите свою функцию ожиданием только Copy
типов, тогда она с радостью скопирует для вас эти значения:
fn last_element<T: Copy>(list: &[T]) -> T {
list[list.len() - 1]
}
Если тип ваших элементов может быть более сложным и не реализует Copy
, тогда вы можете ограничить функцию шире, любым типом, который реализует Clone
, а затем вызвать clone()
для элемента перед возвращается:
fn last_element<T: Clone>(list: &[T]) -> T {
list[list.len() - 1].clone()
}
Клонирование, как правило, более сложная операция, чем копирование, так как оно обычно реализуется для каждого поля в коде Rust, тогда как Copy
- это операция более низкого уровня в необработанной памяти.
Последний вариант - просто вернуть ссылку на последний элемент в первую очередь. Затем вызывающая функция может решить, что с ней делать. Если это тип Copy
(например, числа), то разыменование скопирует его:
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);
}
Если бы элементы были Clone
, но не Copy
, тогда вместо разыменования вы можете явно clone
это вместо этого:
let x = last_element(&slice).clone();