类似但不同的匹配条款

时间:2016-10-02 09:30:14

标签: pattern-matching rust

我们说我有一个enum,但有一些变种:

#[derive(Copy,Clone)]
enum Foo {
    Left(isize),
    Right(isize),
    Other,
    //...
}

我希望对此进行模式匹配,对LeftRight采用非常相似但不相同的处理。

我最终得到了:

match foo {
     Left(i) | Right(i) => {
          let i2 = match foo {
               Left(_) => -i,
               Right(_) => i,
               _  => unreachable!(),
          };
          move_sideways(i2);
          // non-trivial code, ie not a simple function call
     },
     Other => { ... }
}

这并不令人满意,并且依赖于第一次不消费foo。我是否有一个很好的习惯用法,以避免重新匹配或复制规则?

3 个答案:

答案 0 :(得分:2)

我可能会接受Lukas提出的建议,但无论如何我试图设计一些东西。如果您无法改变Foo的构建方式,它可能对您有所帮助。

我不会说它超级优雅,但尝试了:

use self::Foo::*;

#[derive(Copy, Clone)]
enum Foo {
    Left(isize),
    Right(isize),
    Other,
    //...
}

impl From<Foo> for Option<isize> {
    fn from(foo: Foo) -> Option<isize> {
        match foo {
            Left(i) => Some(-i),
            Right(i) => Some(i),
            _ => None
        }
    }
}

fn main() {
    let foo = Left(4);

    if let Some(i) = <Option<isize>>::from(foo) {
        move_sideways(i);
    } else {
        match foo {
            Other => { },
            _ => unreachable!()
        }
    };
}

答案 1 :(得分:2)

无需修改数据结构就无法避免重复规则。但是如果你想避免让Foo成为Copy类型(保留所有其他类型),这里稍作修改:

let foo = Left(34);
match foo {
    foo2 @ Left(_) | foo2 @ Right(_) => {
        let i = match foo2 {
            Left(i) => -i,
            Right(i) => i,
            _ => unreachable!(),
        };
        // ... non-trivial code
    }
    Other => (),
}

foo中的值将移至foo2

(使用阴影可能看起来更干净 - foo而不是foo2 ...)

答案 2 :(得分:1)

首先想到的是将enum包裹到Option而不是使用Other构造函数:

enum Foo {
    Left(isize),
    Right(isize)
}

let foo = Some(Left(1));
let x = match foo {
    Some(y) => {
        let i2 = match y {
            Left(i) => -i,
            Right(i) => i
        };
        do_something(i2)
    },
    None => 0
};

如果您不想这样做,可以链接两个match - 表达式,并使用第一个来处理LeftRight的预处理:

let bar = Right(2);
let z = match match bar {
    Left(i) => Some(-i),
    Right(i) => Some(i),
    Other => None 
} {
    Some(i) => do_something(i),
    None => 0
};

如果由于您的案例更复杂,这无济于事,我只会使用一个match - 表达式,其中包含LeftRightOther的单独案例并将公共代码移动到一个函数中。