Get the last element of a vector and push it to th

2019-06-25 08:53发布

问题:

What I am trying to do:

enum Test {
    Value1,
    Value2,
    Value3
}

fn main() {
    let mut test_vec: Vec<Test> = Vec::new();
    test_vec.push(Test::Value2);

    if let Some(last) = test_vec.last() {
        test_vec.push(*last);
    }
    //Wanted output: vector with [Test::Value2, Test::Value2]
}

I understand that when I call last(), it will return Option<&Test> So it will borrow the test_vec till the end of the if-let block.

I tried the following without success:

if let Some(last) = test_vec.last().map(|v| v.clone()) {
    test_vec.push(*last);
}

//and

let last = test_vec.last().unwrap().clone();
test_vec.push(*last);

回答1:

When trying to figure out why the borrow checker complains it can be useful to identify the types involved.

If you type out:

let _: () = test_vec.last().map(|v| v.clone());

you get an error complaining that () and core::option::Option<&Test> are not the same type.

What's going on? Very simply put, if you clone an &Test you get an &Test, thus calling .map(|v| v.clone()) on a Option<&Test> gives an Option<&Test>. Obviously, it still borrows.

The same problem occurs with your next attempt, if you type out:

let _: () = test_vec.last().unwrap().clone();

you get an error complaining that () and &Test are not the same type.

By calling unwrap on an Option<&Test> you get an &Test which is then cloned into an &Test.


So, the problem is a lack of dereferencing. You need to dereference earlier, to avoid borrowing test_vec in Some(last):

if let Some(last) = test_vec.last().map(|v| (*v).clone()) {
    test_vec.push(last);
}

of course, this does not work because Test does not implement clone. Once that is fixed (by #[derive(Clone)]), it compiles.

Since cloning from references is such a common need, there is a dedicated method on Option (and Iterator) called cloned:

if let Some(last) = test_vec.last().cloned() {
    test_vec.push(last);
}


回答2:

To solve the borrow problem you can call Option::cloned, that produces a Option<T> from a Option<&T>. To do this, Test must implement Clone. You can implement Clone for Test using derive:

// To allow assert_eq, we also derive Debug and PartialEq
#[derive(Debug, PartialEq, Clone)]
enum Test {
    Value1,
    Value2,
    Value3
}

fn main() {
    let mut test_vec = Vec::new();
    test_vec.push(Test::Value2);

    if let Some(last) = test_vec.last().cloned() {
        test_vec.push(last);
    }

    assert_eq!(vec![Test::Value2, Test::Value2], test_vec);
}


标签: vector rust