вернуть рекурсивное замыкание, которое перемещает переменную среды в нее из функции? - PullRequest
0 голосов
/ 02 октября 2018

Способы, которые делают рекурсивное закрытие, мне не подходят из принятого ответа на вопрос:

Можно ли сделать рекурсивное закрытие в Rust?

Мое замыкание должно быть возвращено из функции, необходимо переместить переменную из окружения в нее и изменить ее.

Тогда я нахожу способ более подходящим для меня:

Анонимная рекурсия с замыканиями

use std::cell::RefCell;

fn main() {
    let id = &(|a| a) as &Fn(u64) -> u64;
    let (fib, fib_p): (_, RefCell<&Fn(u64) -> u64>);
    fib_p = RefCell::new(id);

    fib = |n: u64| {
        if n < 2 {
            n
        } else {
            (fib_p.borrow())(n - 2) + (fib_p.borrow())(n - 1)
        }
    };

    *fib_p.borrow_mut() = &fib;

    println!("{}", fib(10));        
}

Приведенный выше код работает нормально.

Но мое замыкание необходимо вернуть из функции, поэтому оно не может быть ссылкой для предотвращениясправка, и мы не знаем размер замыкания во время компиляции, поэтому я использовал для этого умный указатель Box.Код ниже выдает ошибку:

use std::cell::RefCell;

fn main() {
    let id: Box<Fn(u64) -> u64> = Box::new(|a| a);
    let (fib, fib_p): (Box<Fn(u64) -> u64>, RefCell<&Box<Fn(u64) -> u64>>);
    fib_p = RefCell::new(&id);

    fib = Box::new(|n: u64| {
        if n < 2 {
            n
        } else {
            (fib_p.borrow())(n - 2) + (fib_p.borrow())(n - 1)
        }
    });

    *fib_p.borrow_mut() = &fib;

    println!("{}", fib(10));        
}
error[E0597]: `fib_p` does not live long enough
  --> src/main.rs:12:15
   |
8  |     fib = Box::new(|n: u64| {
   |                    -------- capture occurs here
...
12 |             (&fib_p.borrow())(n - 2) + (&fib_p.borrow())(n - 1)
   |               ^^^^^ borrowed value does not live long enough
...
19 | }
   | - borrowed value dropped before borrower
   |
   = note: values in a scope are dropped in the opposite order they are created

1 Ответ

0 голосов
/ 02 октября 2018

Вы можете заключить свой рекурсивный контекст в нерекурсивное замыкание:

pub fn fib() -> Box<Fn(u64) -> u64> {
    Box::new(|n: u64| {
        let id = &(|a| a) as &Fn(u64) -> u64;
        let (fib, fib_p): (_, RefCell<&Fn(u64) -> u64>);
        fib_p = RefCell::new(id);

        fib = |n: u64| {
            if n < 2 {
                n
            } else {
                (fib_p.borrow())(n - 2) + (fib_p.borrow())(n - 1)
            }
        };

        *fib_p.borrow_mut() = &fib;

        fib(n)
    })
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...