无法编译允许将值推入其中的OneOrMany枚举

时间:2017-05-06 06:51:37

标签: rust

我试图创建一个可以包含零个,一个或多个值(不知何故经典)的枚举,并通过单个push(new_value:T)方法与之交互。它可以具有None值(空),One值或Many值(基本上是矢量/切片)。

我试图为灵活类型创建一个包装器,它可以是单个值,也可以是矢量。

这是我写的但是我无法编译

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

这可能是一个愚蠢的经典借用问题,但我刚开始使用Rust。有没有办法让我move existing_value从它当前拥有Option到一个向量而不必克隆它?

1 个答案:

答案 0 :(得分:4)

您可以暂时replace使用value None移出旧值,然后稍后填写:

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.value额外移动到old_value

请考虑使用smallvec包。 FormValues<T>类型相当于SmallVec<[T; 1]>。它也是用精心设计的unsafe code编写的,因此不需要进行不必要的移动。