Вам необходимо добавить явную аннотацию времени жизни к parse_string
, чтобы компилятор мог определить, какие времена жизни одинаковы, а какие могут отличаться.
Fn(&str) -> &String
будет типом для функции, которая возвращает&String
того же времени жизни, что и &str
;то есть for<'b> Fn(&'b str) -> &'b String
. Вы должны сказать, что возвращенный &String
имеет то же время жизни, что и &String
, переданный в parse_string
:
fn parse_string<'a>(string: &'a String) -> impl Fn(&str) -> &'a String {
Обратите внимание, что Fn(&str)
не имеет аннотации времени жизни;это потому, что время жизни &str
, переданное в замыкание , не связано с временем жизни &String
, переданным в parse_string
.
Для того, чтобы parse_string
компилироваласьВам нужно сделать еще одно изменение. Замыкания пытаются заимствовать свое окружение, если компилятор считает, что его не нужно перемещать. Ваше замыкание, которое занимает string
, не может быть возвращено функцией, где string
является локальной переменной. Чтобы исправить это, вы move
захватили переменную в замыкании:
move |target_string| {
// pretend there is parsing logic
println!("{}", target_string);
string
}
В Rust идиоматично опускать return
в последнем выражении в функции.
Также обратите внимание&String
- необычный тип, потому что он не предлагает выразительности, которую &str
не обеспечивает. Почти всегда ошибка иметь &String
в неуниверсальном коде. См. Почему не рекомендуется принимать ссылку на String (& String), Vec (& Vec) или Box (& Box) в качестве аргумента функции? для получения дополнительной информации.
Помещение всего этоговместе, вот как я бы написал parse_string
:
fn parse_string<'a>(string: &'a str) -> impl Fn(&str) -> &'a str {
move |target_string| {
// pretend there is parsing logic
println!("{}", target_string);
string
}
}
Ваш main
также нуждается в небольшой настройке: &String::from("Hello!")
принимает ссылку на временный String
, который будет немедленно отброшен вконец строки, делает недействительной ссылку. Это легко исправить, сохранив String
в переменной, поэтому он не будет удален до конца области действия:
fn main() {
let hello = String::from("Hello!");
let parse_this = parse_string(&hello);
println!("{}", parse_this("goodbye!"));
}