Следующий код полностью аннотирован:
fn enter<'a, F, R>(x: &'a i32, func: F) -> R
where
F: for<'b> FnOnce(&'b i32) -> R,
{
func(x)
}
fn identity<'a>(x: &'a i32) -> &'a i32 {
x
}
fn main() {
let x = &42;
enter(x, identity);
}
Компилятор сообщает об ошибке при компиляции:
error[E0308]: mismatched types
--> src/main.rs:14:5
|
14 | enter(x, identity);
| ^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected trait `for<'b> FnOnce<(&'b i32,)>`
found trait `for<'a> FnOnce<(&'a i32,)>`
note: the lifetime requirement is introduced here
--> src/main.rs:3:35
|
3 | F: for<'b> FnOnce(&'b i32) -> R,
| ^
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error
Тем не менее, общий -> R кажется виновником остановки компиляции, но я не знаю, почему.
Я заметил, что есть похожие вопросы, но они столкнулись с ошибкой, потому что их типы не были полностью аннотированы, и компилятор неправильно определил тип.
Связанный:
Нет это не так. Когда R объявляется, 'b находится вне контекста, поэтому не может зависеть от него (это один из способов взглянуть на это, есть и другие).
Это необходимо для того, чтобы такие API, как std::thread::LocalKey::with(), были надежными: если бы R было разрешено содержать время жизни (неявное в случае with()), ссылки на локальный поток могли бы избежать замыкание и with(), а затем используются в разных потоках, вызывая UB.
Насколько мне известно, нет никакого способа иметь общий тип возвращаемого значения и разрешить ему ссылаться на параметры.