rust - 无法编译允许将值插入其中的 OneOrMany 枚举

标签 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 到一个向量中,而不必克隆它?

最佳答案

您可以暂时移出旧值 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.value 额外移动至 old_value

考虑使用 smallvec crate 代替。 FormValues<T>类型相当于 SmallVec<[T; 1]> .也是精心编写的unsafe code这样就不需要不必要的移动。

关于rust - 无法编译允许将值插入其中的 OneOrMany 枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43817631/

相关文章:

rust - 令人困惑的无法到达的模式错误

rust - 我可以创建一个既适用于值又适用于特征的借用引用的结构吗?

rust - 如何克隆生成器?

rust - &mut unsafe {}和unsafe {&mut}有什么区别?

rust - 乘法时移动值

plugins - 如何正确注册 Rust 编译器插件?

rust - 关联超特征类型的别名

rust - libwasm_bindgen-a2e136f9a24e6618.rlib 挂起,编译时不占用 CPU

rust - 为什么将函数移至默认特征方法会导致借入错误?

rust - 为什么 Rust 不能为我的特征方法推断出合适的生命周期?