Как переписать код в новые распакованные замыкания
Может кто-нибудь помочь мне переписать этот кусок кода с новыми распакованными замыканиями:
struct Builder;
pub fn build(rules: |params: &mut Builder|) -> Builder {
let mut builder = Builder::new();
rules(&mut builder);
builder
}
Я пытался написать так, но я получил ошибку при жизни:
pub fn build<F>(rules: F) -> Builder where F: FnOnce<(&mut Builder,), ()> {
let mut builder = Builder::new();
rules(&mut builder);
builder
}
valico/src/builder.rs:48:59: 48:71 error: missing lifetime specifier [E0106]
valico/src/builder.rs:48 pub fn build<F>(rules: F) -> Builder where F: FnOnce<(&mut Builder,), ()> {
^~~~~~~~~~~~
Какую продолжительность жизни мне нужно указать? Упрощенный пример в песочнице.
1 ответ
Это требует более высоких рангов, в частности, более высоких рангов жизни. Полный неосведомленный синтаксис будет F: for<'a> FnOnce<(&'a mut Builder,), ()>
,
Использование целой жизни функции не может работать, например, если мы
pub fn build<'b, F>(rules: F) -> Builder where F: FnOnce<(&'b mut Builder,), ()>
Это говорит о том, что build
работает с любой продолжительностью жизни, которую пожелает вызывающий абонент (например, они могут выбрать 'b
== 'static
), но это недопустимо, потому что существует конкретное время жизни, которое необходимо использовать: время жизни &mut builder
внутри функции. С помощью F: for<'a> ...
в переплете говорит, что F
работает с любой продолжительностью жизни 'a
Таким образом, компилятор видит, что законно заменить один из &mut builder
,
Как я уже говорил выше, это действительно ужасный неосведомленный синтаксис. Есть два последовательных способа сделать это намного лучше. Во-первых, каноническим способом использования закрывающих черт является ()
сахар: for<'a> FnOnce(&'a mut Builder) -> ()
или, как с остальной частью Rust, -> ()
можно отбросить: for<'a> FnOnce(&'a mut Builder)
, (NB. Это просто сахар для FnOnce<...>
, но только сахаристый синтаксис будет стабилизирован для взаимодействия с этими чертами на уровне 1,0.)
Затем синтаксис paren имеет немного дополнительное правило: он автоматически вставляет время жизни, которое действует как for<'a>
(в частности, он подвергается исключению из жизни с любым вставленным временем жизни, помещенным в for
на черту) так просто F: FnOnce(&mut Builder)
эквивалентно F: for<'a> FnOnce(&'a mut Builder)
и это рекомендуемая версия.
Применение этих исправлений к вашему примеру с манежем:
pub fn initialize_with_closure<F>(rules: F) -> uint where F: FnOnce(&mut uint) {
let mut i = 0;
rules(&mut i);
i
}
// equivalently
pub fn initialize_with_closure_explicit<F>(rules: F) -> uint where F: for<'a> FnOnce(&'a mut uint) -> () {
let mut i = 0;
rules(&mut i);
i
}
pub fn main() {
initialize_with_closure(|i: &mut uint| *i = *i + 20);
initialize_with_closure_explicit(|i: &mut uint| *i = *i + 20);
}