Рекурсивные варианты 'Box`ed enum' - PullRequest
0 голосов
/ 23 марта 2020

У меня есть enum Expr:

enum Expr {
    Const(i32),
    Add {
        lhs: Expr,
        rhs: Expr,
    },
}

Если я скомпилирую это, я получу ошибку, сообщающую, что у меня есть рекурсивные типы без косвенного обращения. Существует по крайней мере два способа добавления косвенности:

  1. Box в каждом поле в Expr::Add:

    Add {
        lhs: Box<Expr>,
        rhs: Box<Expr>,
    }
    
  2. Извлечение Expr::Add в отдельную структуру, а затем Box, используя ее в варианте enum:

    struct ExprAdd {
        lhs: Expr,
        rhs: Expr,
    }
    
    enum Expr {
        Const(i32),
        Add(Box<ExprAdd>),
    }
    

Первый способ действия вводит чрезмерное Box ING. Таким образом, число Box es равно количеству полей в варианте Expr::Add, а создание экземпляра Expr::Add является многословным:

let e = Expr::Add { 
    lhs: Box::new(Expr::Const(1)),
    rhs: Box::new(Expr::Const(2)),
};

Однако, это обеспечивает удобное сопоставление с образцом:

let e = Expr::Const(1);
match e {
    Expr::Const(c) => {}
    // Convenient destructuring.
    Expr::Add { lhs, rhs } => {}
}

Второй способ ведения дел более эффективен благодаря использованию только одного Box, но он излишне многословен (структура ExprAdd здесь на самом деле не нужна) и сопоставление с образцом ограничено:

let e = Expr::Const(1);
match e {
    Expr::Const(c) => {}
    // No convenient destructuring.
    // `expr` is of type `ExprAdd`.
    // Expr::Add(Box(ExprAdd { lhs, rhs })) => {} // fails because `Box` has private members.
    Expr::Add(expr) => { /* use `expr.lhs` and `expr.rhs` */ }
}

Вопросы

  1. Что лучше? Какой больше идиомати c?
  2. Существует ли способ объявления рекурсивного перечисления, как в примере second , который позволяет удобно сопоставлять шаблоны, как в примере first ?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...