2017-05-06 36 views
1

我試圖創建一個可容納零,一個或多個值(以某種古典),並與我會通過一個push(new_value:T)方法互動一個枚舉。它可能有None值(空),One值或Many值(基本上是矢量/切片)。不能編譯OneOrMany枚舉它允許值推到它

我試圖創建一個靈活的類型,可以是單個值或載體的包裝。

以下是我已經寫了,但我不能編譯

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

錯誤:

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` 

我的總的意圖是那麼能夠做這樣的事情:

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

這可能是一個愚蠢的經典借貸的問題,但我剛開始使用生鏽。有沒有辦法將moveexisting_value從當前擁有Option變成矢量而不必克隆它?

回答

4

您可以通過暫時replace撤展舊值-ing的valueNone,然後補回來後:

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

你不需要.clone(),雖然這將產生一個T的額外移動從self.valueold_value

考慮使用smallvec箱替代。 FormValues<T>類型相當於SmallVec<[T; 1]>。它也是用精心製作的unsafecode寫成的,這樣就不需要不必要的移動。

+0

非常感謝@kennytm它確實解決了它!出於好奇,爲什麼你說'SmallVec <[T;1]>'將阻止移動(我猜你指的是'讓OLD_VALUE =替換(MUT self.value,NoneOneOrMany ::無);')? – Boris

+0

@Boris當'self.value'是'一(噸)',就不會有在't'的兩個動作:首先從'self.value'到'old_value',第二從'old_value'到載體中。使用'SmallVec',只有一個直接從堆棧移動'[T; 1]'到堆vec。當然,對於'T == u32'來說,這真的不是什麼大問題,如果'T == SomeHugeStruct',這只是一個問題。 – kennytm