匹配多个盒装值

问题描述 投票:0回答:2

我有以下代码,可以正常编译

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    Const(i32),
    Neg(Box<Expression>),
    Add(Box<Expression>, Box<Expression>),
}

fn simplify(expr: &Expression) -> Expression {
    match expr {
        Expression::Neg(x) => match **x {
            Expression::Const(n) => Expression::Const(-n),
            _ => expr.clone() 
        },  

        // GIVES ERROR
        // Expression::Add(x, y) => match (**x, **y) {
        //     (Expression::Const(n), Expression::Const(m)) => Expression::Const(n + m),
        //     _ => expr.clone() 
        // },
    
    
        Expression::Add(x, y) => match **x {
            Expression::Const(n) => match **y {
                Expression::Const(m) => Expression::Const(n + m), 
                _ => expr.clone() 
            }   
            _ => expr.clone() 
        }   


        _ => expr.clone() 
    }   
}

但是,如果我用注释掉的版本替换

Expression::Add
臂,则会出现以下编译器错误

error[E0507]: cannot move out of `**x` which is behind a shared reference
  --> src/lib.rs:21:41
   |
21 |         Expression::Add(x, y) => match (**x, **y) {
   |                                         ^^^ move occurs because `**x` has type `Expression`, which does not implement the `Copy` trait

error[E0507]: cannot move out of `**y` which is behind a shared reference
  --> src/lib.rs:21:46
   |
21 |         Expression::Add(x, y) => match (**x, **y) {
   |                                              ^^^ move occurs because `**y` has type `Expression`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0507`.

是否有理由我们可以与单独的

**x
匹配,但不能在像
(**x, **y)
这样的元组中匹配?前者实际上是被转换还是隐藏了一些语法糖?有没有比两个嵌套匹配更简单的方法来编写这个
Add
臂?

编辑:我还看到有一个

ref
关键字,它应该解决类似的问题,但是将我的元组匹配表达式更改为
(ref **x, ref **y)
会产生语法错误(
error: expected expression, found keyword ref
)。

rust match move-semantics
2个回答
1
投票

TL;DR:

(&**x, &**y)
比赛。


这里发生的事情很有趣。 TL;DR 是:当您

match v {}
时,您不会阅读
v
。您为 v 创建了一个
地方

A place 是我们可以阅读的东西。或者写信给。或者什么也不做。重要的是,仅仅创造场所并不涉及这样的操作。您可以稍后读/写它,但是当您创建它时,它只是一个地方。

在您的

match
中,
x
y
的类型为
&Box<Expression>
。当我们
match **x
时,我们不读
x
。因此,我们也不会移动
**x
。我们所做的是为
**x
创造一个地方。然后我们将这个地方与
Expression::Const(n)
进行匹配。现在我们读取
x
并从中提取
n
。但是
n
i32
-
Copy
- 所以这很好。

相反,当您使用元组

(**x, **y)
时,由于您不直接与
**x
**y
匹配,因此您确实会读取它们。因为你读了它们,而它们不是
Copy
(
Expression
),所以你就离开了它们。现在这是一个错误,因为您无法移出共享引用。您之后匹配它们,但它们已经移动了。


0
投票

你可以试试

match(x.as_ref(),y.as_ref())

© www.soinside.com 2019 - 2024. All rights reserved.