在Rust可以做一个递归闭包吗? [英] Is it possible to make a recursive closure in Rust?

查看:1521
本文介绍了在Rust可以做一个递归闭包吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个非常简单的例子,但我怎么做类似的:

This is a very simple example, but how would I do something similar to:

let fact = |x: u32| {
    match x {
        0 => 1,
        _ => x * fact(x - 1),
    }
};

我知道这个具体的例子可以很容易地通过迭代完成,但我想知道是否可能对于更复杂的事情(例如遍历树)或者如果我需要使用自己的堆栈,在Rust中创建递归函数。

I know that this specific example can be easily done with iteration, but I'm wondering if it's possible to make a recursive function in Rust for more complicated things (such as traversing trees) or if I'm required to use my own stack instead.

推荐答案

有几种方法可以做到这一点。

There are a few ways to do this.

你可以把闭包放到一个结构体中,并把这个结构体传递给闭包,非法(因为它是危险的,在某些情况下,如博客帖子 Pascal链接到编辑的注释:显然不是,从Rust 1.10 ),即使它是完全安全的,因为没有突变。您甚至可以在函数中内联定义struct:

You can put closures into a struct and pass this struct to the closure, although this will possibly be made illegal (since it's dangerous, in some instances, as outlined in the blog post Pascal links to editor's note: evidently not, as of Rust 1.10), even though it's entirely safe here since there is no mutation. You can even define structs inline in a function:

fn main() {
    struct Fact<'s> { f: &'s Fn(&Fact, u32) -> u32 }
    let fact = Fact {
        f: &|fact, x| if x == 0 {1} else {x * (fact.f)(fact, x - 1)}
    };

    println!("{}", (fact.f)(&fact, 5));
}

这解决了无限类型的问题作为参数),当 let fact = | x |时, fact {...} ,因此无法参考。

This gets around the problem of having an infinite type (a function that takes itself as an argument) and the problem that fact isn't yet defined inside the closure itself when one writes let fact = |x| {...} and so one can't refer to it there.

选项是将递归函数写为 fn 项,也可以在函数中内联定义:

Another option is to just write a recursive function as a fn item, which can also be defined inline in a function:

fn main() {
    fn fact(x: u32) -> u32 { if x == 0 {1} else {x * fact(x - 1)} }

    println!("{}", fact(5));
}

如果你不需要从环境中捕获任何东西,

This works fine if you don't need to capture anything from the environment.

另一个选择是使用 fn 显式传递所需的参数/环境。

One more option is to use the fn item solution but explicitly pass the args/environment you want.

fn main() {
    struct FactEnv { base_case: u32 }
    fn fact(env: &FactEnv, x: u32) -> u32 {
        if x == 0 {env.base_case} else {x * fact(env, x - 1)}
    }

    let env =  FactEnv { base_case: 10 };
    println!("{}", fact(&env, 5));
}

所有这些都与Rust 1.10一起工作,在 fn 中定义的 fn 与在顶层定义的没有区别,只是它们只能访问在 fn 内定义它们。

All of these work with Rust 1.10 and have probably worked since version 0.6. The fn's defined inside fns are no different to those defined at the top level, except they are only accessible within the fn they are defined inside.

这篇关于在Rust可以做一个递归闭包吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆