Рекурсивное замыкание как параметр функции «не может определить подходящий срок службы из-за противоречивых требований» - PullRequest
0 голосов
/ 03 октября 2018

Этот вопрос является более сложным, чем Закрытие, поскольку функциональный параметр «не может определить подходящий срок службы из-за противоречивых требований» * .

Существует рекурсивное замыкание, которое перемещает переменную среды в него.

Код ниже работает, инструмент представляет собой набор полезных функций для функционального программирования, включая создание рекурсивного замыкания :

extern crate tool;
use tool::prelude::*;
use std::cell::Cell;

fn main() {
    let a = Cell::new(false);

    let fib = fix(move |f, x| {
        a.set(true);
        if x == 0 || x == 1 {
            x
        } else {
            // `f` is `fib`
            f(x - 1) + f(x - 2)
        }
    });

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

Я хочуМы знаем, можно ли передать это замыкание в функцию, а затем вызвать эту функцию в этом замыкании, код ниже выдает ошибку.

extern crate tool;
use tool::prelude::*;
use std::cell::RefCell;

fn main() {
    let a = RefCell::new(false);

    let fib = fix(move |f, x| {
        *a.borrow_mut() = true;
        if x == 0 || x == 1 {
            x
        } else {
            // `f` is `fib`
            b(Box::new(f), x - 1) + f(x - 2)
        }
    });

    fn b (c: Box<Fn(u64) -> u64>, n: u64) -> u64 {
        c(n)
    }

    println!("{}", b(Box::new(fib), 10));
}
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:14:24
   |
14 |             b(Box::new(f), x - 1) + f(x - 2)
   |                        ^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 8:19... 
  --> src/main.rs:8:19
   |
8  |       let fib = fix(move |f, x| {
   |  ___________________^
9  | |         *a.borrow_mut() = true;
10 | |         if x == 0 || x == 1 {
11 | |             x
...  |
15 | |         }
16 | |     });
   | |_____^
   = note: ...so that the expression is assignable:
           expected &dyn std::ops::Fn(u64) -> u64
              found &dyn std::ops::Fn(u64) -> u64
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the expression is assignable:
           expected std::boxed::Box<(dyn std::ops::Fn(u64) -> u64 + 'static)>
              found std::boxed::Box<dyn std::ops::Fn(u64) -> u64>

1 Ответ

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

Похоже, вы смешиваете несколько понятий здесь.Прежде всего, вы должны понимать разницу между ними:

  1. fn(A) -> B
  2. impl Fn(A) -> B или T: Fn(A) -> B
  3. &dyn Fn(A) -> B
  4. Box<dyn Fn(A) -> B>

Число 1 - это тип указателя на функцию, как в C.

Число 2 - это обобщенный тип, который реализует функцию trait Fn, то есть тип callable .

Number 3 - это динамическая ссылка на вызываемый объект (ключевое слово dyn является необязательным).

Число 4 - это объект черты , то есть вызываемый в штучной упаковке объект со стертым реальным типом.

Теперь посмотрите на определение tool::fix:

pub fn fix<A, B, F>(f: F) -> impl Fn(A) -> B 
where
    F: Fn(&Fn(A) -> B, A) -> B, 

Из этого видно, что fix использует номер 2 для параметра f, но номер 3 для параметра A f.Кроме того, он возвращает число 2.

Сложность в том, что f - это функция, которая принимает функцию в качестве аргумента.Сам по себе f может быть любого типа, который реализует Fn, но первый аргумент этой функции должен иметь вид &dyn Fn.

Ваша первоначальная ошибка возникает из-за попытки пометить &dyn Fn(A) -> B, но вы не можете сделать это в общем, потому что такое значение может содержать ссылки, а для Box требуется тип 'static.

Но, учитывая все это, вы можете тщательно написать свою функцию, не используя BoxТаким образом, ваша проблема просто исчезает, и результат лучше ( детская площадка ):

fn main() {
    fn wrap (wrap_fn: impl Fn(&dyn Fn(u64) -> u64, u64) -> u64) -> impl Fn(u64) -> u64 {
        let a = RefCell::new(false);

        let fib = fix(move |f, x| {
            *a.borrow_mut() = true;
            if x == 0 || x == 1 {
                x
            } else {
                // `f` is `fib`
                wrap_fn(f, x - 1) + wrap_fn(f, x - 2)
            }
        });  

        fib
    }

    fn b (c: &dyn Fn(u64) -> u64, n: u64) -> u64 {
        c(n)
    }

    println!("{}", (wrap(b))(10));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...