2015-04-08 14 views
8

Esiste un modo per realizzare qualcosa di simile al seguente:Estrarre un iteratore Prendere in una tupla

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

Tale che a=1 e b=2 alla fine?

So che potrei semplicemente usare un vettore, ma mi piacerebbe avere variabili con nome.

+0

Un problema è che la tupla è di tipo. Quindi tupla con 2 elementi è un tipo distinto dalla tupla di 3 elementi. Take (2) potrebbe non funzionare al meglio qui, ma probabilmente dovresti richiedere una macro speciale che restituisca il tipo appropriato in base al numero che passi. –

+0

Quale comportamento vuoi quando il vettore contiene meno di due elementi? – Shepmaster

+0

@Shepmaster è un'ottima domanda. In quella luce non riesco a pensare a una ragione sufficiente per rendere possibile questa funzionalità. – anderspitman

risposta

8

Questo potrebbe non essere esattamente quello che hai chiesto, ma suppongo che tu voglia raramente convertire un vettore arbitrariamente grande in una tupla. Se si desidera solo per estrarre i primi elementi di un vettore in una tupla, è possibile farlo utilizzando pattern matching:

#![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

Mi piace, ma sarebbe bello avere qualcosa di più conciso. Creare una funzione che restituisce '(v [0] .clone(), v [1] .clone())' sembra funzionare bene. C'è un vantaggio in un modo o nell'altro? – anderspitman

+1

A parte la clonazione, uno svantaggio ovvio sarebbe che 'v [i]' potrebbe andare in panico a meno che non si verifichi esplicitamente la lunghezza del Vec, il che renderebbe il codice meno conciso. Usando la corrispondenza del modello, il compilatore controlla se la corrispondenza è esaustiva e richiede di gestire Vec di qualsiasi lunghezza arbitraria. Certo, non dovresti semplicemente usare l'irraggiungibile! macro come sopra a meno che la lunghezza del Vec sia nota in anticipo. – helios35

+2

A partire da 'rustc 1.12.0', la sintassi del pattern slice è ancora sperimentale. Vedi [numero 23121] (https://github.com/rust-lang/rust/issues/23121) – Phil

3

Ho scritto questa brutta macro ricorsiva, perché volevo imparare qualcosa sulle macro.

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

Sono nuovo di questo e probabilmente molto brutto, quindi c'è molto probabilmente un modo migliore per farlo. Solo una prova di concetto. Esso consente di scrivere

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

qualche parte in quella definizione di macro si trova la parte $v[$j], che è possibile sostituire con $v.nth($j) se si desidera utilizzarlo per iteratori.