Почему это простое замыкание терпит неудачу, в то время как другие две функции выполняются успешно? - PullRequest
1 голос
/ 09 ноября 2019

Я создал закрывающий пример, который я не могу заставить работать, и не могу найти причину, по которой он не должен работать. Почему он не компилируется при последнем закрытии?

Детская площадка

struct S {}

fn filter<P>(predicate: P)
where
    P: Fn(&S) -> bool,
{
    predicate(&S {});
}

fn main() {
    // this works
    filter(|_s| true);

    // this also works
    fn cb1(_s: &S) -> bool {
        true
    }
    filter(cb1);

    // but this doesn't work
    let cb2 = |_s| true;
    filter(cb2);
}

Вывод:

error[E0631]: type mismatch in closure arguments
  --> /tmp/closure.rs:19:5
   |
18 |     let cb2 = |_s| true;
   |               --------- found signature of `fn(_) -> _`
19 |     filter(cb2);
   |     ^^^^^^ expected signature of `for<'r> fn(&'r S) -> _`
   |
note: required by `filter`
  --> /tmp/closure.rs:3:1
   |
3  | fn filter<P>(predicate: P) where P: Fn(&S) -> bool,
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0271]: type mismatch resolving `for<'r> <[closure@/tmp/closure.rs:18:15: 18:24] as std::ops::FnOnce<(&'r S,)>>::Output == bool`
  --> /tmp/closure.rs:19:5
   |
19 |     filter(cb2);
   |     ^^^^^^ expected bound lifetime parameter, found concrete lifetime
   |
note: required by `filter`
  --> /tmp/closure.rs:3:1
   |
3  | fn filter<P>(predicate: P) where P: Fn(&S) -> bool,
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ответы [ 2 ]

2 голосов
/ 09 ноября 2019

Из следующих Несоответствия типов при разрешении замыкания, которое принимает аргументы по ссылке и Как объявить время жизни для аргумента замыкания? кажется, что решение состоит в том, чтобы изменить:

fn filter<P>(predicate: P)
where
    P: Fn(&S) -> bool,
{
    predicate(&S {});
}

до

fn filter<'a, P>(predicate: P)
where
    P: Fn(&'a S) -> bool,
{
    predicate(&S {});
}

Хотя я не уверен почему. Похоже, это связано с предполагаемыми временами жизни, когда замыкание указывается внутри строки, тогда как оно сохраняется в переменной и используется позже. Но неясно, почему &S требуется время жизни 'a, когда &S не является возвращаемым результатом. Если вы понимаете это, пожалуйста, объясните в комментарии.

Хотя этот вопрос «решен», опубликованный изначально случай сбоя фактически не помогает моей истинной проблеме, потому что я не могу редактировать исходный кодУ меня возникли проблемы с https://docs.rs/walkdir/2.2.9/walkdir/struct.IntoIter.html#method.filter_entry

Проблема возникла, когда я попытался передать сохраненный обратный вызов в метод filter_entry. Решением было бы указать явное время жизни в filter_entry подписи, как описано ранее в этом посте, но вы можете сделать это только, если вы хотите редактировать сторонний код. Я думаю, что, к сожалению, ответ на эту конкретную проблему таков: «Вы не можете использовать хранимое замыкание с filter_entry»

0 голосов
/ 09 ноября 2019

Я думаю, к сожалению, ответ на эту конкретную проблему: «Вы не можете использовать хранимое замыкание с filter_entry»

Подход из Ответ Шепмастера может применяться для достижения этой цели. Как и в этом ответе, мы можем определить обобщенную функцию constrain, требующую типа с типами границ времени жизни, которые потребуются для удовлетворения filter. Мы применяем функцию к замыканию и затем сохраняем ее в. Обратите внимание, что вызов constrain(cb) при вызове filter (который был моей первой попыткой) не работает, потому что компилятор не может определить тип переменной закрытия, когда она передается в constrain, больше, чем когда он былпередано в filter.

Вызов constrain не имеет никакого эффекта во время выполнения, он просто направляет компилятор, чтобы определить границы времени жизни для переменной, которая нам нужна для filter. Это позволяет сохранить закрытие и вызвать filter без изменения его подписи:

fn constrain<F>(fun: F) -> F
where
    F: for<'a> Fn(&'a S) -> bool,
{
    fun
}

fn main() {
    let cb = constrain(|_s| true);
    filter(cb);
}

Playground.

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