Rust 是否不可能在使用智能指针(如Box、Rc或Arc)的递归数据类型上进行嵌套匹配?

Rust 是否不可能在使用智能指针(如Box、Rc或Arc)的递归数据类型上进行嵌套匹配?,rust,Rust,我正在尝试端口,它计算x^x的nth导数,象征性地表示生锈。这似乎很容易: use std::rc::Rc; type Expr = Rc<Expr2>; enum Expr2 { Int(i32), Var(String), Add(Expr, Expr), Mul(Expr, Expr), Pow(Expr, Expr), Ln(Expr), } use Expr2::*; fn pown(a: i32, b: i32) -

我正在尝试端口,它计算x^x的
n
th导数,象征性地表示生锈。这似乎很容易:

use std::rc::Rc;

type Expr = Rc<Expr2>;

enum Expr2 {
    Int(i32),
    Var(String),
    Add(Expr, Expr),
    Mul(Expr, Expr),
    Pow(Expr, Expr),
    Ln(Expr),
}

use Expr2::*;

fn pown(a: i32, b: i32) -> i32 {
    match b {
        0 => 1,
        1 => a,
        n => {
            let b = pown(a, b / 2);
            let b2 = b * b;
            if n % 2 == 0 {
                b2
            } else {
                b2 * a
            }
        }
    }
}

fn add(f: Expr, g: Expr) -> Expr {
    match (f, g) {
        (Int(m), Int(n)) => Int(m + n),
        (Int(0), f) => f,
        (f, Int(n)) => add(Int(n), f),
        (f, Add(Int(n), g)) => add(Int(n), add(f, g)),
        (Add(f, g), h) => add(f, add(g, h)),
        (f, g) => Add(f, g),
    }
}

fn mul(f: Expr, g: Expr) -> Expr {
    match (f, g) {
        (Int(m), Int(n)) => Int(m * n),
        (Int(0), f) => Int(0),
        (Int(1), f) => f,
        (f, Int(n)) => mul(Int(n), f),
        (f, Mul(Int(n), g)) => mul(Int(n), mul(f, g)),
        (Mul(f, g), h) => mul(f, mul(g, h)),
        (f, g) => Mul(f, g),
    }
}

fn pow(f: Expr, g: Expr) -> Expr {
    match (f, g) {
        (Int(m), Int(n)) => Int(pown(m, n)),
        (f, Int(0)) => Int(1),
        (f, Int(1)) => f,
        (Int(0), f) => Int(1),
        (f, g) => Pow(f, g),
    }
}

fn ln(f: Expr) -> Expr {
    match f {
        Int(1) => Int(0),
        f => Ln(f),
    }
}

fn d(x: String, f: Expr) -> Expr {
    match f {
        Int(_) => Int(0),
        Var(y) => if x == y {
            x
        } else {
            y
        },
        Add(f, g) => add(d(x, f), d(x, g)),
        Mul(f, g) => add(mul(f, d(x, g)), mul(g, d(x, f))),
        Pow(f, g) => mul(
            pow(f, g),
            add(mul(mul(g, d(x, f)), pow(f, Int(-1))), mul(ln(f), d(x, g))),
        ),
        Ln(f) => mul(d(x, f), pow(f, Int(-1))),
    }
}

fn count(f: Expr) -> i32 {
    match f {
        Int(_) | Var(_) => 1,
        Add(f, g) | Mul(f, g) | Pow(f, g) => count(f) + count(g),
        Ln(f) => count(f),
    }
}

fn string_of_expr(f: Expr) -> String {
    count(f).to_string();
}

fn nest(n: i32, f: Expr, x: Expr) -> Expr {
    if n == 0 {
        x
    } else {
        nest(n - 1, f, f(x))
    }
}

fn deriv(f: Expr) -> Expr {
    let df = d("x", f);
    format!("D({}) = {}", string_of_expr(f), string_of_expr(df));
    df
}

fn main() {
    let x = "x";
    let f = pow(x, x);
    // FIXME: Read command-line argument
    let df = nest(9, deriv, f);
    format!("{}", count(df));
}
使用std::rc::rc;
Expr型=Rc;
枚举Expr2{
Int(i32),
变量(字符串),
添加(Expr,Expr),
Mul(Expr,Expr),
战俘(Expr,Expr),
Ln(Expr),
}
使用Expr2::*;
fn功率(a:i32,b:i32)->i32{
比赛b{
0 => 1,
1=>a,
n=>{
设b=pown(a,b/2);
设b2=b*b;
如果n%2==0{
b2
}否则{
b2*a
}
}
}
}
fn添加(f:Expr,g:Expr)->Expr{
匹配(f,g){
(Int(m),Int(n))=>Int(m+n),
(Int(0),f)=>f,
(f,Int(n))=>添加(Int(n),f),
(f,Add(Int(n),g))=>Add(Int(n),Add(f,g)),
(加(f,g,h)=>加(f,加(g,h)),
(f,g)=>添加(f,g),
}
}
fn mul(f:Expr,g:Expr)->Expr{
匹配(f,g){
(Int(m),Int(n))=>Int(m*n),
(Int(0),f)=>Int(0),
(Int(1),f)=>f,
(f,Int(n))=>mul(Int(n),f),
(f,Mul(Int(n),g))=>Mul(Int(n),Mul(f,g)),
(Mul(f,g,h)=>Mul(f,Mul(g,h)),
(f,g)=>Mul(f,g),
}
}
fn-pow(f:Expr,g:Expr)->Expr{
匹配(f,g){
(Int(m,Int(n))=>Int(pown(m,n)),
(f,Int(0))=>Int(1),
(f,Int(1))=>f,
(Int(0),f)=>Int(1),
(f,g)=>功率(f,g),
}
}
fn-ln(f:Expr)->Expr{
匹配f{
Int(1)=>Int(0),
f=>Ln(f),
}
}
fnd(x:String,f:Expr)->Expr{
匹配f{
Int()=>Int(0),
Var(y)=>如果x==y{
x
}否则{
Y
},
加(f,g)=>加(d(x,f),d(x,g)),
Mul(f,g)=>add(Mul(f,d(x,g)),Mul(g,d(x,f)),
功率(f,g)=>mul(
战俘(f,g),
加上(mul(mul(g,d(x,f)),pow(f,Int(-1)),mul(ln(f),d(x,g)),
),
Ln(f)=>mul(d(x,f),pow(f,Int(-1)),
}
}
fn计数(f:Expr)->i32{
匹配f{
Int(124;)Var(124;)=>1,
加上(f,g)| Mul(f,g)| Pow(f,g)=>计数(f)+计数(g),
Ln(f)=>计数(f),
}
}
fn string_of_expr(f:expr)->string{
计数(f).到_字符串();
}
fn嵌套(n:i32,f:Expr,x:Expr)->Expr{
如果n==0{
x
}否则{
嵌套(n-1,f,f(x))
}
}
fn deriv(f:Expr)->Expr{
设df=d(“x”,f);
格式!(({})={},表达式(f)的字符串_,表达式(df)的字符串_);
df
}
fn main(){
设x=“x”;
设f=pow(x,x);
//FIXME:读取命令行参数
设df=nest(9,deriv,f);
格式!(“{}”,计数(df));
}
该类型需要转换为Rust中计数的引用
enum
,模式匹配使代码非常相似,除了。。。它不起作用。据我所知,锈迹中的图案与取消引用
Rc
的结果不匹配。所以,无论我做什么,它都会在嵌套模式上失败,比如
(f,Add(Int(n),g))


我是否遗漏了一些东西,或者嵌套模式真的不可能与Rust中的递归数据类型相匹配?显然,有一种称为“框语法”的东西可以在一个已经在绘图板上绘制了四年的模式(除其他外)中取消引用。

似乎是的,目前不可能做到这一点。递归数据类型需要间接寻址,例如
Rc
。在与嵌套模式进行匹配时,间接寻址需要取消引用。在今天的Rust中,没有办法在模式匹配中取消引用

解决方法是手工编译模式,即,就好像只有C-style
开关一样


一种称为“框模式”的功能可能会在将来解决这个问题,但它尚未发布。

嵌套模式真的不可能与Rust中的递归数据类型匹配吗?-不,这是完全可能的,也是标准的。解除对
Rc
的引用后,锈迹中的图案无法匹配-您在该代码中根本没有解除引用。@Shepmaster:“这是完全可能和标准的”。伟大的我做错了什么,怎么做才是对的?我引用的东西比我想引用的多了一点。我想问的是嵌套模式是否真的不可能匹配,这是可能的,也是正常的。对于任何虚假的希望,我深表歉意。另请参见