Получите последний элемент вектора и поместите его в тот же вектор

Что я пытаюсь сделать:

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

Я понимаю, что когда я звоню last(), он вернется Option<&Test>Так что это будет заимствовать test_vec до конца блока if-let.

Я попробовал следующее безуспешно:

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

2 ответа

Решение

При попытке выяснить, почему контролер заимствований жалуется, может оказаться полезным определить типы, которые в нем участвуют.

Если вы печатаете:

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

Вы получаете сообщение об ошибке, что () а также core::option::Option<&Test> не того же типа.

В чем дело? Проще говоря, если вы клонируете &Test Вы получаете &Test таким образом вызывая .map(|v| v.clone()) на Option<&Test> дает Option<&Test>, Очевидно, это все еще занимает.

Та же проблема возникает при следующей попытке, если вы наберете:

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

Вы получаете сообщение об ошибке, что () а также &Test не того же типа.

По телефону unwrap на Option<&Test> Вы получаете &Test который затем клонируется в &Test,


Таким образом, проблема заключается в отсутствии разыменования. Вы должны разыменовать раньше, чтобы избежать заимствования test_vec в Some(last):

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

конечно, это не работает, потому что Test не реализует clone, Как только это исправлено (#[derive(Clone)]), он компилируется.

Поскольку клонирование из ссылок является такой распространенной потребностью, существует специальный метод Option (а также Iterator) называется cloned:

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

Для решения проблемы заимствования вы можете позвонить Option::cloned, который производит Option<T> из Option<&T>, Сделать это, Test должен реализовать Clone, Вы можете реализовать Clone за Test с помощью 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);
}
Другие вопросы по тегам