具有外部变量的递归函数

时间:2017-02-17 22:49:22

标签: recursion rust scoping

我在变量范围内苦苦挣扎。我目前有类似的代码:

use std::collections::HashMap;

fn main() {
    let mut cache: HashMap<usize, usize> = HashMap::new();

    fn fib(n: usize) -> usize {
        // Special values
        if n == 0 || n == 1 {
            return 1;
        }

        // Check if value is in cache
        if let Some(&a) = cache.get(&n) {
            return a;
        }

        // Calculate
        let f = fib(n - 2) + fib(n - 1);

        // Insert in cache for later use
        cache.insert(n, f);

        return f;
    }

    println!("The 11th Fibonacci number is: {}", fib(10));
}

我想生成Fibonacci数字,但也使用缓存跳过重新计算相同的项目。实际的代码做了一些较重的计算,但也使用了递归。

但是,尝试编译时,我会在can't capture dynamic environment in a fn item; use the || { ... } closure form insteadcache.get收到cache.insert警告。将此闭包表单应用于该代码:

use std::collections::HashMap;

fn main() {
    let mut cache: HashMap<usize, usize> = HashMap::new();

    let fib = |n: usize| -> usize {
        // Special values
        if n == 0 || n == 1 {
            return 1;
        }

        // Check if value is in cache
        if let Some(&a) = cache.get(&n) {
            return a;
        }

        // Calculate
        let f = fib(n - 2) + fib(n - 1);

        // Insert in cache for later use
        cache.insert(n, f);

        return f;
    };

    println!("The 11th Fibonacci number is: {}", fib(10));
}

修复了cache错误,但在cannot find function `fib` in this scope处发出let f = ...警告。

我还尝试使用Is it possible to make a recursive closure in Rust?中所述的环境,但是我不喜欢两次调用相同的函数,因此在环境中有可变缓存的情况下借用了两次环境。 / p>

我该如何处理这个奇怪的案例?

1 个答案:

答案 0 :(得分:3)

您使用环境的方式正确,但您需要确保所有需要变量的内容都是可变的:

use std::collections::HashMap;

fn main() {
    struct FibEnv { cache: HashMap<usize, usize> }

    fn fib(mut env: &mut FibEnv, n: usize) -> usize {
        // Special values
        if n == 0 || n == 1 {
            return 1;
        }

        // Check if value is in cache
        if let Some(&a) = env.cache.get(&n) {
            return a;
        }

        // Calculate
        let f = fib(&mut env, n - 2) + fib(&mut env, n - 1);

        // Insert in cache for later use
        env.cache.insert(n, f);

        return f;
    }

    let cache: HashMap<usize, usize> = HashMap::new();
    let mut env = FibEnv { cache: cache };
    println!("The 11th Fibonacci number is: {}", fib(&mut env, 10));
}

正如@Shepmaster在评论中所述,以下内容更为简单:

use std::collections::HashMap;

fn main() {
    fn fib(cache: &mut HashMap<usize, usize>, n: usize) -> usize {
        // Special values
        if n == 0 || n == 1 {
            return 1;
        }

        // Check if value is in cache
        if let Some(&a) = cache.get(&n) {
            return a;
        }

        // Calculate
        let f = fib(cache, n - 2) + fib(cache, n - 1);

        // Insert in cache for later use
        cache.insert(n, f);

        return f;
    }

    let mut cache: HashMap<usize, usize> = HashMap::new();
    println!("The 11th Fibonacci number is: {}", fib(&mut cache, 10));
}