2016-07-10 2 views
3

У меня есть массив фиксированного размера в Rust [String; 2], и я хочу превратить его в (String, String). Могу ли я сделать это без копирования значений?Перемещение значений из массива в кортеж

Кусок кода, который я работаю, в частности, следующие:

let (basis, names_0, names_1) = if let Some(names) = self.arg_name { 
    (ComparisonBasis::Name, names[0], names[1]) 
} else { 
    (ComparisonBasis::File, self.arg_file[0], self.arg_file[1]) 
}; 

типов:

self.arg_name: Option<[String; 2]> 
self.arg_file: Vec<String> 

Сейчас я получаю ошибки

cannot move out of type `[std::string::String; 2]`, a non-copy fixed-size array [E0508] 

и

cannot move out of indexed content [E0507] 

для двух рукавов if

+0

В конце концов, я думаю, это немного переусердствует, чтобы попытаться оптимизировать вызовы клонировать. Кусок кода в вопросе называется ровно один раз для запуска программы, и это всего две (возможно небольшие) строки. – Apanatshka

ответ

4

Вы опущены изрядное количество контекста, так что я беру догадку в нескольких аспектах. Я также немного подхожу к вопросу, который вы задали , а не к более неопределенному из ваших фрагментов.

struct NeverSpecified { 
    arg_names: Option<[String; 2]>, 
    arg_file: Vec<String>, 
} 

impl NeverSpecified { 
    fn some_method_i_guess(mut self) -> (String, String) { 
     if let Some(mut names) = self.arg_names { 
      use std::mem::replace; 
      let name_0 = replace(&mut names[0], String::new()); 
      let name_1 = replace(&mut names[1], String::new()); 
      (name_0, name_1) 
     } else { 
      let mut names = self.arg_file.drain(0..2); 
      let name_0 = names.next().expect("expected 2 names, got 0"); 
      let name_1 = names.next().expect("expected 2 names, got 1"); 
      (name_0, name_1) 
     } 
    } 
} 

Я использую std::mem::replace для переключения содержимого массива, в то время оставляя его в допустимом состоянии. Это необходимо, потому что Rust не позволит вам иметь «частично действительный» массив. В этом пути нет копий или ассигнований.

На другом пути нам нужно вытащить элементы из вектора вручную. Опять же, вы не можете просто перемещать значения из контейнера с помощью индексации (на самом деле это ограничение индексации в целом). Вместо этого я использую Vec::drain, чтобы по существу вырезать первые два элемента из вектора, а затем извлечь их из результирующего итератора. Чтобы быть ясным: этот путь не включает никаких копий или распределений, либо.

Как и в стороне, эти expect методов не должны когда-либо быть вызваны (с drain делает проверки границ), но лучше, чем параноик жаль; если вы хотите, чтобы заменить их unwrap() вызовов вместо этого, что должно быть хорошо ..

+0

Это именно то, что я искал :) Извините за неопределенность в вопросе. – Apanatshka

+0

@Apanatshka: Чтобы быть ясным, ни одна ветвь в этом примере не требует копирования или выделения; это * чисто * движется (и пустые значения в первой ветви). Просто хотел уточнить, так как ваш комментарий к вашему вопросу может означать, что вы думаете, что нет никакого способа сделать это без копирования. –

+0

Я понимаю, что ваш пример не выполняет никакого копирования (но он выделяет новый (пустой) 'String's right?). Я просто решил, что в этом случае вызов 'clone' в порядке и немного меньше усилий для написания и чтения :) – Apanatshka

Смежные вопросы