2015-06-02 2 views
4

Как принять Vec<Option<T>>, где T не может быть скопирован и разворачиваться все значения Some? Я столкнулся с ошибкой cannot move out of borrowed content, когда в шаге map. Я счастлив переместить право собственности на исходный список и «выбросить» None с.Преобразовать список опций <T> в список T, если T не может быть скопирован

#[derive(Debug)] 
struct Uncopyable { 
    val: u64 
} 

fn main(){ 
    let num_opts : Vec< Option<Uncopyable> > = vec![Some(Uncopyable{val: 1}), 
         Some(Uncopyable{val: 2}), 
         None, 
         Some(Uncopyable{val: 4})]; 

    let nums : Vec<Uncopyable> = num_opts.iter().filter(|x| x.is_some()).map(|&x| x.unwrap()).collect(); 
    println!("nums: {:?}", nums); 
} 

Что дает ошибку

<anon>:12:79: 12:81 error: cannot move out of borrowed content 
<anon>:12  let nums : Vec<Uncopyable> = num_opts.iter().filter(|x| x.is_some()).map(|&x| x.unwrap()).collect(); 

Вы можете увидеть здесь: манеж http://is.gd/HCtGZT

ответ

5

ржавчиной, когда требуется значение, обычно вы хотите двигаться элементов или клона им.

Поскольку движение является более общим, здесь it is, только два изменения необходимы:

num_opts.into_iter().filter(|x| x.is_some()).map(|x| x.unwrap()).collect() 
               ^~~ Take by value 
     ^~~~~~~~~~~ Consume vector, and iterate by value 

Как llogiq указывает, filter_map специализируется отфильтровывать None уже:

num_opts.into_iter().filter_map(|x| x).collect() 
           ^~~ Take by value 
     ^~~~~~~~~~~ Consume vector, and iterate by value 

А потом его работает (потребляет num_opts).

+0

Это даже лучше, чем мое решение (если вы не хотите сохранить исходный вектор - вы не можете иметь оба). Обратите внимание, что вы все равно можете использовать 'filter_map', чтобы сделать его короче – llogiq

+1

@llogiq: мне непонятно, может ли Uncopyable использовать не-Clone; поэтому OP может принять решение, использующее '.cloned()'. Спасибо за отличный 'filter_map'. –

+1

Добро пожаловать. Спасибо за 'in_iter()'. – llogiq

2

Вам не нужно копировать Uncopyable на всех, если вы хорошо с помощью VEC ссылок в оригинал Vec:

// notice the '&' before Uncopyable? 
let nums : Vec<&Uncopyable> = num_opts.iter().filter_map(|x| x.as_ref()).collect(); 

Обратите внимание, что это может не сделать трюк для y ou, если вам нужно работать с API, который требует &[Uncopyable]. В этом случае используйте решение Matthieu M., которое кстати. может быть уменьшена до:

let nums : Vec<Uncopyable> = num_opts.into_iter().filter_map(|x| x).collect(); 
Смежные вопросы