Вы используете лот ссылок, которые не кажутся необходимыми, и вам все сложнее понять это:
- A
fn
равно уже функция указатель , так что вы можете передавать их по значению вместо использования другого уровня ссылок.Это проще, потому что указатель функции 'static
. - Все эти
&f64
являются неизменяемыми, поэтому могут быть заменены на f64
без изменения логики.Это должна быть та же скорость, что и (или , возможно, быстрее, чем) при использовании ссылки.
Как только вы это сделаете, у вас не останется много ссылок, и это будетяснее, что вызывает проблему:
fn ensure_tonicty(tone_fn: fn(f64, f64) -> bool) -> impl Fn(&Vec<f64>) -> bool {
|floats: &Vec<f64>| -> bool {
let first = *floats.first().unwrap();
let rest = &floats[1..];
fn f(tone_fn: fn(f64, f64) -> bool, prev: f64, xs: &[f64]) -> bool {
match xs.first() {
Some(&x) => tone_fn(prev, x) && f(tone_fn, x, &xs[1..]),
None => true,
}
};
f(tone_fn, first, rest);
};
}
Теперь ошибка:
error[E0373]: closure may outlive the current function, but it borrows `tone_fn`, which is owned by the current function
--> src/lib.rs:2:12
|
2 | return |floats: &Vec<f64>| -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `tone_fn`
...
11 | return f(tone_fn, first, rest);
| ------- `tone_fn` is borrowed here
|
note: closure is returned here
--> src/lib.rs:2:12
|
2 | return |floats: &Vec<f64>| -> bool {
| ____________^
3 | | let first = *floats.first().unwrap();
4 | | let rest = &floats[1..];
5 | | fn f(tone_fn: fn(f64, f64) -> bool, prev: f64, xs: &[f64]) -> bool {
... |
11 | | return f(tone_fn, first, rest);
12 | | };
| |_____^
help: to force the closure to take ownership of `tone_fn` (and any other referenced variables), use the `move` keyword
|
2 | return move |floats: &Vec<f64>| -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
В разделе help
рассказывается, как именно это исправить: сделать закрытие move
его окружение.Результат:
fn ensure_tonicty(tone_fn: fn(f64, f64) -> bool) -> impl Fn(&[f64]) -> bool {
move |floats: &[f64]| -> bool {
let first = floats[0];
let rest = &floats[1..];
fn f(tone_fn: fn(f64, f64) -> bool, prev: f64, xs: &[f64]) -> bool {
match xs.first() {
Some(&x) => tone_fn(prev, x) && f(tone_fn, x, &xs[1..]),
None => true,
}
};
f(tone_fn, first, rest)
}
}
Если вы вернете замыкание из другой функции, вам почти всегда понадобится это ключевое слово.В противном случае любые переменные, упомянутые в замыкании, будут ссылками на значения, которые выйдут из области видимости после завершения функции.Использование ключевого слова move
перемещает эти значения таким образом, чтобы они шли туда, куда идет замыкание.
Также обратите внимание на другие изменения, которые я сделал, чтобы сделать код более идиоматическим:
- Используйте выражения вместо
return
ключевого слова. - Используйте
&[f64]
вместо &Vec<f64>
в аргументах функции (см. Почему не рекомендуется принимать ссылку на строку (& String), Vec (& Vec) или Box (& Box) в качестве аргумента функции? ).