首页 > 解决方案 > 如何对包含 &mut 枚举的元组进行模式匹配,并在一个匹配臂中使用枚举并在另一个匹配臂中使用递归调用?

问题描述

如何编译下面的代码?它看起来非常安全,但我无法说服编译器它是。

版本匹配*self给出了错误:

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:8:16
  |
8 |         match (*self, y) {
  |                ^^^^^ cannot move out of borrowed content

版本匹配self给出:

error[E0382]: use of moved value: `*self`
  --> src/main.rs:17:26
   |
8  |         match (self, y) {
   |                ---- value moved here
...
17 |                 (*a * b, self)
   |                          ^^^^ value used here after move
   |
   = note: move occurs because `self` has type `&'a mut Foo<'a>`, which does not implement the `Copy` trait
enum Foo<'a> {
    Foo1(Option<&'a mut Foo<'a>>),
    Foo2(i16),
}

impl<'a> Foo<'a> {
    fn bar(&'a mut self, y: i16) -> (i16, &'a mut Foo<'a>) {
        match (self, y) {
            (&mut Foo::Foo1(Some(ref mut a)), b) if (b == 5) => {
                return a.bar(y)
            },

            (&mut Foo::Foo2(ref mut a), b) if (b == 5) => {
                print!("is five");
                *a = (b + 42) as i16;

                (*a * b, self)
            },

            ref mut x => {
                print!("is not five!");
                (y, self)
            }
        }
    }
}

我觉得我需要一个如下所示的匹配臂,但它似乎不是有效的语法:

(ref mut f @ Foo::Foo1, b) if (b == 5) => {
    print!("is five");
    f.0 = b + 42;
    (b, f)
} 
error[E0532]: expected unit struct/variant or constant, found tuple variant `Foo::Foo1`
  --> src/main.rs:24:30
   |
24 |                 (ref mut f @ Foo::Foo1, b) if (b == 5) => {
   |                              ^^^^^^^^^ not a unit struct/variant or constant

这是我正在尝试编写的 adeep_fetch_mut的简化版本。toml::Value目标是能够调用.deep_fetch_mut(vec!["aaa","bbb","ccc"]),这将在toml::Value.

这个问题是如何对包含 &mut 枚举的元组进行模式匹配并在匹配臂中使用枚举的扩展?

标签: rustpattern-matchingborrow-checker

解决方案


这似乎可以编译,但它非常难看。有没有办法简化这个?

enum Foo<'a> {
    Foo1(Option<&'a mut Foo<'a>>),
    Foo2(i16),
}

impl<'a> Foo<'a> {
    fn bar(&'a mut self, y: i16) -> (i16, &'a mut Foo<'a>) {
        match (&mut *self, y) {
            (Foo::Foo1(Some(ref mut a)), b) if (b == 5) => {
                return a.bar(y)
            },

            (self2, c) => {
                let n = match (&mut *self2 , c) {
                    (Foo::Foo2(ref mut a), b) if (b == 5) => {
                        print!("is five");
                        *a = (b + 42) as i16;

                        *a * b
                    },

                    ref mut x => {
                        print!("is not five!");
                        y
                    }
                };

                return (n, self2)
            }
        }
    }
}

推荐阅读