На этом сайте есть ряд вопросов о сопоставлении с образцом Box<>
, и в настоящее время это невозможно сделать на стабильном Rust (один , два , три и т. д.). Но все эти вопросы касаются отдельных уровней коробки. У меня есть глубоко вложенное дерево Box/Enum. В основном я хочу сделать это:
match node {
ConstantExpression::ConstantPrimary(Box(ConstantPrimary::PrimaryLiteral(Box(
PrimaryLiteral::Number(Box(Number::IntegralNumber(Box(
IntegralNumber::DecimalNumber(Box(DecimalNumber::UnsignedNumber(unsigned_number))),
)))),
)))) => Some(unsigned_number),
_ => None,
};
Есть ли способ сделать это на стабильной Rust, который не очень многословен?
(Редактировать: это не дубликат этого вопроса; я уже знаю, что вы не можете сделать это, используя match
. Я просил альтернативный способ сделать это.)
Я не думаю, что несколько уровней возможны. Я просил альтернативу (см. ответ @Sven Marnach).
Ответ Свена - это просто применение ответов, которые вы нашли сами. Может быть, с новым синтаксисом, но все же...
Можете ли вы указать на существующий ответ с таким кодом, как у Свена?
Если бы я применил это вслепую, я бы получил 7-уровневую вложенность if
, что не очень приятно. Sven's лучше, потому что он использует ранние возвраты. Возможно, вы думаете, что это очевидно, но StackOverflow предназначен не только для вопросов, которые вы считаете неочевидными. Пожалуйста, дайте больше пользы от сомнений в будущем, спасибо.
Помимо проблемы сопоставления с блоками, в вашем шаблоне на самом деле нет избыточной информации. Вы должны упомянуть каждый вариант перечисления хотя бы один раз, чтобы указать, что вы хотите. Лучшее, что вы можете сделать, чтобы сделать шаблон менее громоздким, — это делать по одному уровню за раз:
pub fn extract_unsigned_number(node: ConstantExpression) -> Option<UnsignedNumber> {
let ConstantExpression::ConstantPrimary(constant_primary) = node else { return None };
let ConstantPrimary::PrimaryLiteral(primary_literal) = *constant_primary else { return None };
let PrimaryLiteral::Number(number) = *primary_literal else { return None };
let Number::IntegralNumber(integral_number) = *number else { return None };
let IntegralNumber::DecimalNumber(decimal_number) = *integral_number else { return None };
let DecimalNumber::UnsignedNumber(unsigned_number) = *decimal_number else { return None };
Some(*unsigned_number)
}
Вы можете сделать это немного менее повторяющимся с помощью декларативного макроса, но код станет более непонятным, поэтому лично я бы просто использовал этот код как есть.
Да, это то, что я тоже придумал.
@ cafce25 Мне пришлось отменить ваше изменение. Все эти типы взяты из ящика sv-parser
, а unsigned_number
будет иметь тип Box<UnsignedNumber>
, поэтому код больше не будет компилироваться с вашими изменениями. Если мы хотим точно соответствовать unsigned_number
в вопросе, нам нужно изменить тип возвращаемого значения функции на Option<Box<UnsignedNumber>>
и изменить последнюю строку на Some(unsigned_number)
, но ваше изменение в отдельности не работает.
О, я не знал, что все они были из ящика, и в ОП нет указания, что unsigned_integer
тоже находится в Box
, в этом случае разыменование имеет смысл.
Если вы не можете сопоставить коробки на одном уровне без
box_patterns
, почему вы думаете, что возможны несколько уровней?