2015-04-08 2 views
8

Есть ли способ сделать что-то вроде следующего:Распакуйте Take итератор в кортеж

let v = vec![1,2,3]; 
let (a,b) = v.iter().take(2); 

Такое, что a=1 и b=2 в конце?

Я знаю, что могу просто использовать вектор, но я хотел бы иметь именованные переменные.

+0

Одна проблема - это кортеж - тип. Так что кортеж с 2 элементами отличается от набора из трех элементов. take (2) может быть не лучшей функцией здесь, но вам, вероятно, потребуется специальный макрос, который возвращает соответствующий тип на основе числа, которое вы передаете. –

+0

Какое поведение вы хотите, если вектор содержит менее двух элементов? – Shepmaster

+0

@Shepmaster - отличный вопрос. В этом свете я не могу придумать достаточно хорошую причину, чтобы эта функциональность была возможной. – anderspitman

ответ

8

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

#![feature(slice_patterns)] 
fn main() { 
    let v = vec![1,2,3]; 
    let (a, b) = match &v[..] { 
     &[first, second, ref _tail..] => (first, second), 
     _ => unreachable!() 
    }; 
    assert_eq!((a, b), (1,2)); 
} 
+0

Мне это нравится, но было бы неплохо иметь что-то более сжатое. Создание функции, которая возвращает '(v [0] .clone(), v [1] .clone())', похоже, тоже работает. Есть ли преимущество в том или ином виде? – anderspitman

+1

Помимо клонирования, одним из очевидных недостатков было бы то, что 'v [i]' может паниковать, если вы явно не проверите длину Vec, что сделает код менее кратким. Используя сопоставление с образцом, компилятор проверяет, является ли совпадение исчерпывающим, и требует, чтобы вы обрабатывали Vec любой произвольной длины. Конечно, вы не должны просто использовать недостижимые! как указано выше, если длина Vec не известна заранее. – helios35

+2

Как и в случае с 'rustc 1.12.0', синтаксис шаблона фрагмента все еще экспериментальный. См. [Проблема № 23121] (https://github.com/rust-lang/rust/issues/23121) – Phil

3

itertools клеть имеет такие методы, как tuples и next_tuple, которые могут помочь с этим.

3

Я написал этот уродливый рекурсивный макрос, потому что хотел узнать что-то о макросах.

macro_rules! tuplet { 
{ ($y:ident $(, $x:ident)*) = $v:expr } => { 
    let ($y,$($x),*) = tuplet!($v ; 1 ; ($($x),*) ; ($v[0])); }; 
{ $v:expr ; $j:expr ; ($y:ident $(, $x:ident)*) ; ($($a:expr),*) } => { 
    tuplet!($v ; $j+1 ; ($($x),*) ; ($($a),*,$v[$j])) }; 
{ $v:expr ; $j:expr ;() ; $accu:expr } => { $accu } 
} 

Я новичок в этом и, вероятно, очень плохо в нем, так что, скорее всего, это лучший способ сделать это. Просто доказательство концепции. Это позволяет писать

v = vec![1,2,3]; 
tuplet!((a,b,c) = v); 

где-то в этом макроопределении вы найдете часть $v[$j], которую вы могли бы заменить на $v.nth($j), если вы хотите использовать его для итераторов.

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