У меня есть enum Expr
:
enum Expr {
Const(i32),
Add {
lhs: Expr,
rhs: Expr,
},
}
Если я скомпилирую это, я получу ошибку, сообщающую, что у меня есть рекурсивные типы без косвенного обращения. Существует по крайней мере два способа добавления косвенности:
Box
в каждом поле в Expr::Add
:
Add {
lhs: Box<Expr>,
rhs: Box<Expr>,
}
Извлечение 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` */ }
}
Вопросы
- Что лучше? Какой больше идиомати c?
- Существует ли способ объявления рекурсивного перечисления, как в примере second , который позволяет удобно сопоставлять шаблоны, как в примере first ?