Получите последний элемент вектора и поместите его в тот же вектор
Что я пытаюсь сделать:
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);
}