如何从切片复制最后一个元素

时间:2018-08-27 17:19:36

标签: rust copy slice

我对Rust还是陌生的,正在尝试学习使用借位检查器的惯用方式。

我正在尝试编写一个简单的函数,该函数接受一个slice(对数据类型通用)并返回最后一个元素,以使我以后可以对该slice进行更改。天真的实现方式给我一个错误:

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;
}

错误是cannot move out of type [T] , a non-copy slice。我看到一种解决方法是让函数返回引用:

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;
}

但是随后我得到slice[2] = 17的错误,因为在分配x时借用了切片。我确实希望能够在致电last_element之后进行变异。我发现的一种解决方法是取消引用x,我认为这会消耗借用:

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;
}

这是否是最惯用的方法,可以实现获得切片的最后一个元素并随后仍然使切片变异的目的?或者如果我编写好的代码,我以后甚至应该永远不要做这种变异吗?

1 个答案:

答案 0 :(得分:4)

如果使用简单类型,例如i32和其他固定大小的小型结构,则这些类型通常实现Copy。此特征是一个标记,它告诉编译器在可能会移动值的情况下将其复制到内存中。实际上,这是错误消息在引用non-copy slice时的含义:如果元素未实现Copy,则必须移动它们,这将使切片处于无效状态,这是不允许的。

如果您将函数限制为仅期望Copy类型,那么它将很乐意为您复制这些值:

fn last_element<T: Copy>(list: &[T]) -> T {
    list[list.len() - 1]
}

如果元素的类型可能更复杂且未实现Copy,则可以将函数约束更广泛,以实现任何实现Clone的类型,然后调用{{1 }}在元素返回之前:

clone()

与复制相比,克隆操作通常要重得多,因为克隆操作通常是在Rust代码的每个字段中实现的,而fn last_element<T: Clone>(list: &[T]) -> T { list[list.len() - 1].clone() } 是对原始内存进行的较低级别的操作。

最后一个选择是只返回对最后一个元素的引用。然后,函数的调用者可以决定如何处理它。如果它是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