2017-05-06 1 views
1

Ich versuche, eine Enumeration zu erstellen, die Null, einen oder viele Werte enthalten kann (irgendwie klassisch) und mit denen ich durch eine einzige push(new_value:T)-Methode interagieren würde. Es könnte entweder None Wert (leer), One Wert oder Many Wert (im Grunde ein Vektor/Scheibe) haben.Kompilieren einer OneOrMany-Enumeration, die das Einfügen von Werten ermöglicht

Ich versuche, einen Wrapper für einen flexiblen Typ zu erstellen, der entweder ein einzelner Wert oder ein Vektor sein kann. Hier

ist das, was ich geschrieben habe, aber das kann ich nicht kompilieren

enum NoneOneOrMany<T> { 
    None, 
    One(T), 
    Many(Vec<T>), 
} 

struct FormValues<T> { 
    value: NoneOneOrMany<T>, 
} 

impl<T> FormValues<T> { 
    pub fn new() -> FormValues<T> { 
     FormValues { value: NoneOneOrMany::None } 
    } 

    pub fn push(&mut self, new_value: T) { 
     match self.value { 
      NoneOneOrMany::None => self.value = NoneOneOrMany::One(new_value), 
      NoneOneOrMany::One(existing_value) => { 
       let mut vec = Vec::<T>::new(); 
       vec.push(existing_value); 
       vec.push(new_value); 
       self.value = NoneOneOrMany::Many(vec); 
      } 
      NoneOneOrMany::Many(ref mut vec) => { 
       vec.push(new_value); 
      } 
     } 
    } 
} 

die Fehler:

error[E0507]: cannot move out of borrowed content 
    --> src/main.rs:17:15 
    | 
17 |   match self.value { 
    |    ^^^^ cannot move out of borrowed content 
18 |    NoneOneOrMany::None => self.value = NoneOneOrMany::One(new_value), 
19 |    NoneOneOrMany::One(existing_value) => { 
    |        -------------- hint: to prevent move, use `ref existing_value` or `ref mut existing_value` 

Meine Gesamt Absicht war dann in der Lage sein, so etwas zu tun:

fn print_form_value<T: Debug>(x: FormValues<T>) { 
    match x.value { 
     NoneOneOrMany::None => println!("Empty"), 
     NoneOneOrMany::One(val) => println!("Holds one value => {:?}", val), 
     NoneOneOrMany::Many(vec) => println!("Holds several values => {:?}", vec), 
    } 
} 

fn test_oneOrMany() { 
    let mut x = FormValues::<u32>::new(); 
    x.push(1); 
    x.push(2); 

    let mut y = FormValues::<u32>::new(); 
    y.push(3); 

    let mut z = FormValues::<u32>::new(); 

    print_form_value(x); 
    print_form_value(y); 
    print_form_value(z); 
} 

Es ist wahrscheinlich eine alberne klassische Kreditfrage, aber ich habe gerade begonnen, Rust zu verwenden. Gibt es eine Möglichkeit, moveexisting_value von ihm ist Option in einem Vektor zu besitzen, ohne es zu klonen?

Antwort

4

Sie könnten den alten Wert von vorübergehend replace bewegen-out -Ing die value mit einem None, und es dann später füllen zurück:

pub fn push(&mut self, new_value: T) { 
    let old_value = replace(&mut self.value, NoneOneOrMany::None); 
    self.value = match old_value { 
     NoneOneOrMany::None => { 
      NoneOneOrMany::One(new_value) 
     } 
     NoneOneOrMany::One(existing_value) => { 
      NoneOneOrMany::Many(vec![existing_value, new_value]) 
     } 
     NoneOneOrMany::Many(mut vec) => { 
      vec.push(new_value); 
      NoneOneOrMany::Many(vec) 
     } 
    } 
} 

Sie brauchen nicht zu .clone(), obwohl dies ein entstehen Extra Bewegung von T von self.value bis old_value

Betrachten Sie stattdessen die Kiste. Der FormValues<T> Typ entspricht SmallVec<[T; 1]>. Es ist auch mit sorgfältig gestalteten unsafecode geschrieben, so dass die unnötige Bewegung nicht benötigt wird.

+0

vielen dank @kennytm es tatsächlich gelöst! Aus Neugier, warum sagst du, dass 'SmallVec <[T;1]>' die Verschiebung verhindern würde (ich vermute, du beziehst dich auf 'let old_value = replace (& mut self.value, NoneOneOrMany :: None); ')? – Boris

+0

@Boris Wenn 'self.value'' One (t) 'war, gäbe es zwei Züge des' t': zuerst von 'self.value' nach' old_value', zweitens von 'old_value' zum Vektor. Mit 'SmallVec' würde es nur eine Bewegung direkt vom Stapel geben' [T; 1] 'zum Haufen vec. Für 'T == u32' ist das natürlich keine große Sache, es ist nur ein Problem, wenn' T == SomeHugeStruct'. – kennytm

Verwandte Themen