How can I pattern match a tuple containing a &mut enum and use the enum in one match arm and a recursive call in another?

∥☆過路亽.° 提交于 2019-12-11 09:02:58

问题


How can the code below be made to compile? It seems perfectly safe, but I can't convince the compiler that it is.

The version matching *self gives the error:

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

The version matching self gives:

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

I feel like I would need a match arm such as the following, but it doesn't seem to be valid syntax:

(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

This is a dumbed down version of a deep_fetch_mut of a toml::Value that I am trying to write. The goal would be to be able to call .deep_fetch_mut(vec!["aaa","bbb","ccc"]), that will return a mutable reference to that value inside the toml::Value.

This question is an extension of How can I pattern match a tuple containing a &mut enum and use the enum in the match arm?


回答1:


This seems to compile, but it's very ugly. Is there a way to simplify this?

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


来源:https://stackoverflow.com/questions/51330147/how-can-i-pattern-match-a-tuple-containing-a-mut-enum-and-use-the-enum-in-one-m

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!