Для меня важнее понять источник проблемы, найти обходной путь, поэтому шаг за шагом. Давайте начнем с того, что работает:
struct Person {
name: String,
age: u8,
}
fn get_name<'a>(person: &'a Person) -> &'a str {
&person.name
}
fn main() {
let p = Person {
name: "Nobody".to_string(),
age: 24,
};
let age = |p: &Person| p.age;
let name = get_name;
println!("name={}, age={}", name(&p), age(&p));
}
Нет проблем при использовании функции вместо clousure. В этом случае компилятор может проверить, что требования времени жизни в порядке.
Но при попытке использовать замыкание для name
:
let name = |p : &Person | &p.name;
Вы получаете ошибку cannot infer an appropriate lifetime
.
Почему?
Закрытие захватывает свою среду: некоторая непрозрачная структура должна быть создана компилятором, и такая структура должна вызываться.
Я не полностью осведомлен о внутренних деталях, но что-то в этом роде будет создано при отладке вашего замыкания:
struct OpaqueType<'a> {
// a PhantomData because you don't capure nothing
// just to make explicit that struct lifetime bind to environment
// if you would had captured some integer:
// captured_int: &'a i32,
captured_int: PhantomData<&'a i32>,
}
impl<'a> OpaqueType<'a> {
fn call<'b>(&'b self, person: &'a Person) -> &'a str {
&person.name
}
}
И, глядя на call
, становится очевидным, что, когда аргумент кластера является ссылкой, существует два не связанных времени жизни при игре.
Наконец, ответ: как вернуть ссылку
Также обратите внимание, что в вашем случае, не объявляя тип аргумента и используя вспомогательную функцию get_name
, работает:
// let name = |p| &p.name; // does not work, not enough info to infer p type
let name = |p| get_name(p);
Я предполагаю, что в таком случае компилятор, следуя некоторому пути логического вывода, способен десугаровать таким образом, что время жизни ограничено, как и ожидалось.