Как переписать код в новые распакованные замыкания

Может кто-нибудь помочь мне переписать этот кусок кода с новыми распакованными замыканиями:

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);
}

детский манеж

Другие вопросы по тегам