Прежде всего, позвольте мне сказать, что проблема не имеет ничего общего с использованием синтаксиса impl Trait
. Я преобразовал закрытие в именованную структуру и получил те же результаты.
Итак, давайте посмотрим на код, который вы хотели бы заставить работать:
let f = apply(second, i);
let _ = tuples.iter().filter(f);
Что компилятор может сказать по этому поводу?
error[E0277]: the trait bound `for<'r> impl std::ops::FnMut<(&(_, _),)>: std::ops::FnMut<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` is not satisfied
--> <anon>:11:27
|
11 | let _ = tuples.iter().filter(f);
| ^^^^^^ trait `for<'r> impl std::ops::FnMut<(&(_, _),)>: std::ops::FnMut<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` not satisfied
error[E0277]: the trait bound `for<'r> impl std::ops::FnMut<(&(_, _),)>: std::ops::FnOnce<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` is not satisfied
--> <anon>:11:27
|
11 | let _ = tuples.iter().filter(f);
| ^^^^^^ trait `for<'r> impl std::ops::FnMut<(&(_, _),)>: std::ops::FnOnce<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` not satisfied
Итак, у нас есть тип X, и ему нужно реализовать черту Y, но этого не происходит. Но давайте посмотрим внимательно:
for<'r> impl
std::ops::FnMut<(&(_, _),)>:
std::ops::FnMut<(&'r &(_, _),)>
Ах ха! filter
ожидает функцию, которая принимает ссылку на ссылку на кортеж, тогда как функция, которую мы передаем, принимает ссылку на кортеж. filter
передает ссылку на ссылку, потому что tuples.iter()
перебирает ссылки, а filter
передает ссылки на них.
Хорошо, давайте изменим определение second
, чтобы принимать ссылки на ссылки:
fn second<'a, A, B: ?Sized>(&&(_, ref second): &&'a (A, B)) -> &'a B {
second
}
Компилятор все еще недоволен:
error[E0277]: the trait bound `for<'r> impl std::ops::FnMut<(&&(_, _),)>: std::ops::FnMut<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` is not satisfied
--> <anon>:11:27
|
11 | let _ = tuples.iter().filter(f);
| ^^^^^^ trait `for<'r> impl std::ops::FnMut<(&&(_, _),)>: std::ops::FnMut<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` not satisfied
error[E0271]: type mismatch resolving `for<'r> <impl std::ops::FnMut<(&&(_, _),)> as std::ops::FnOnce<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>>::Output == bool`
--> <anon>:11:27
|
11 | let _ = tuples.iter().filter(f);
| ^^^^^^ expected bound lifetime parameter , found concrete lifetime
|
= note: concrete lifetime that was found is lifetime '_#24r
expected bound lifetime parameter , found concrete lifetime
... Что это значит?
Тип f
— это некоторый тип, который реализует FnMut(&'c &'b (&'a str, &Fn(i32) -> bool)) -> bool
. При вызове apply
, B == &'c &'b (&'a str, &Fn(i32) -> bool)
и C == bool
. Обратите внимание, что B
здесь является одним фиксированным типом; 'c
представляет одно фиксированное время жизни, которое называется конкретным временем жизни.
Давайте посмотрим на подпись filter
:
fn filter<P>(self, predicate: P) -> Filter<Self, P> where
Self: Sized, P: FnMut(&Self::Item) -> bool,
Здесь P
должен реализовать FnMut(&Self::Item) -> bool
. На самом деле, этот синтаксис является сокращением для for<'r> FnMut(&'r Self::Item) -> bool
. Здесь. 'r
— это связанный параметр времени жизни.
Итак, проблема в том, что наша функция, реализующая FnMut(&'c &'b (&'a str, &Fn(i32) -> bool)) -> bool
, не реализует for<'r> FnMut(&'r Self::Item) -> bool
. Нам понадобится функция, реализующая for<'c> FnMut(&'c &'b (&'a str, &Fn(i32) -> bool)) -> bool
. Единственный способ сделать это на данный момент — написать apply
следующим образом:
fn apply<A, B, C, F, G>(mut f: F, a: A) -> impl FnMut(&B) -> C
where F: FnMut(&B) -> G,
G: FnMut(A) -> C,
A: Clone
{
move |b| f(b)(a.clone())
}
или более явная версия:
fn apply<A, B, C, F, G>(mut f: F, a: A) -> impl for<'r> FnMut(&'r B) -> C
where F: for<'r> FnMut(&'r B) -> G,
G: FnMut(A) -> C,
A: Clone
{
move |b| f(b)(a.clone())
}
Если Rust в конечном итоге поддерживает более высокий уровень типов, может найти более элегантный способ решить эту проблему.
person
Francis Gagné
schedule
17.09.2016
apply
иsecond
— я пытаюсь решить проблему с HRTB. - person iopq   schedule 17.09.2016