Почему я не могу использовать это закрытие внутри R c ? - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть такая структура:

pub struct ImmEval<Out> {
    closure: Rc<dyn Fn(&Self) -> Out>
}
impl<Out> From<Rc<dyn Fn(&Self) -> Out>> for ImmEval<Out> {
    /// Constructs the evaluator from the specified closure.
    fn from(cl: Rc<dyn Fn(&Self) -> Out>) -> Self {
        ImmEval {closure: cl}
    }
}
impl<Out> Evaluator for ImmEval<Out> {
    type Output = Out;
    /// Evaluates and returns the result.
    fn eval(&self) -> Self::Output {
        (*self.closure)(self)
    }
}

, которая используется в таком тесте:

let counter = Cell::new(0);
{
    let eval = ImmEval::<i32>::from(Rc::from(|_: &ImmEval<i32>| {
        counter.set(counter.get() + 1);
        counter.get()
    }));

    eval.eval();
    eval.eval();
}
assert_eq!(counter.get(), 2);

Структура сама компилируется, а тест - нет. Вместо этого происходит сбой со следующим rustc сообщением:

error[E0277]: the trait bound `ImmEval<i32>: std::convert::From<std::rc::Rc<[closure@src\tests.rs:8:51: 11:10 counter:_]>>` is not satisfied
  --> src\tests.rs:8:41
   |
8  |           let eval = ImmEval::<i32>::from(Rc::from(|_: &ImmEval<i32>| {
   |  _________________________________________^
9  | |             counter.set(counter.get() + 1);
10 | |             counter.get()
11 | |         }));
   | |__________^ the trait `std::convert::From<std::rc::Rc<[closure@src\tests.rs:8:51: 11:10 counter:_]>>` is not implemented for `ImmEval<i32>`
   |
   = help: the following implementations were found:
             <ImmEval<Out> as std::convert::From<std::rc::Rc<(dyn for<'r> std::ops::Fn(&'r ImmEval<Out>) -> Out + 'static)>>>
   = note: required by `std::convert::From::from`

Конечно, это означает, что мое закрытие не является действительным Fn(&ImmEval<i32>) -> i32, но почему?

Вот пример детской площадки .

Ответы [ 2 ]

1 голос
/ 14 февраля 2020

Более элегантное решение, чем отдельное создание замыкания (как видно здесь , хотя я все еще ценю отличное объяснение проблемы), вообще не использует черту From:

impl<'l, Out> ImmEval<'l, Out> {
    pub fn new<Cl>(closure: Cl) -> Self
    where Cl: (Fn(&ImmEval<Out>) -> Out) + 'l {
        let rcl: Rc<dyn Fn(&ImmEval<Out>) -> Out> = Rc::from(closure);
        ImmEval {closure: rcl}
    }
}

Я заменил конструктор From обобщенным c new (а также добавил несколько спецификаторов времени жизни, чтобы убедиться, что замыкание живет достаточно долго), которое принимает само замыкание (без счетчика ссылок) и складывает это в один так же, как первый ответ, который я упомянул. Затем, клонируя структуру оценщика или добавляя метод get_closure, закрывающее число ссылок может быть извлечено и использовано повторно. Более того, если черта From сохранена, то результат get_closure будет использоваться так же, как первый упомянутый ответ.

1 голос
/ 13 февраля 2020

Вывод типа не может быть сделан в этой ситуации. Если вы напишите тип, который вы хотите, он будет работать:

let f: Rc<dyn Fn(&ImmEval<i32>) -> i32> = Rc::new(|_: &ImmEval<i32>| {
    counter.set(counter.get() + 1);
    counter.get()
});
let eval = ImmEval::<i32>::from(f);

Но это не решит ваши другие проблемы жизни.

...