Есть ли краткий способ сопоставить глубоко вложенные блоки?

На этом сайте есть ряд вопросов о сопоставлении с образцом 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. Я просил альтернативный способ сделать это.)

Если вы не можете сопоставить коробки на одном уровне без box_patterns, почему вы думаете, что возможны несколько уровней?

cafce25 19.04.2023 11:59

Я не думаю, что несколько уровней возможны. Я просил альтернативу (см. ответ @Sven Marnach).

Timmmm 19.04.2023 14:59

Ответ Свена - это просто применение ответов, которые вы нашли сами. Может быть, с новым синтаксисом, но все же...

cafce25 19.04.2023 15:02

Можете ли вы указать на существующий ответ с таким кодом, как у Свена?

Timmmm 19.04.2023 15:34
Этот сопоставляется, разыменовывается и снова сопоставляется, просто Свен делает это 6 раз.
cafce25 19.04.2023 15:36

Если бы я применил это вслепую, я бы получил 7-уровневую вложенность if, что не очень приятно. Sven's лучше, потому что он использует ранние возвраты. Возможно, вы думаете, что это очевидно, но StackOverflow предназначен не только для вопросов, которые вы считаете неочевидными. Пожалуйста, дайте больше пользы от сомнений в будущем, спасибо.

Timmmm 19.04.2023 15:48
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
6
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Помимо проблемы сопоставления с блоками, в вашем шаблоне на самом деле нет избыточной информации. Вы должны упомянуть каждый вариант перечисления хотя бы один раз, чтобы указать, что вы хотите. Лучшее, что вы можете сделать, чтобы сделать шаблон менее громоздким, — это делать по одному уровню за раз:

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 19.04.2023 12:49

@ cafce25 Мне пришлось отменить ваше изменение. Все эти типы взяты из ящика sv-parser, а unsigned_number будет иметь тип Box<UnsignedNumber>, поэтому код больше не будет компилироваться с вашими изменениями. Если мы хотим точно соответствовать unsigned_number в вопросе, нам нужно изменить тип возвращаемого значения функции на Option<Box<UnsignedNumber>> и изменить последнюю строку на Some(unsigned_number), но ваше изменение в отдельности не работает.

Sven Marnach 19.04.2023 12:57

О, я не знал, что все они были из ящика, и в ОП нет указания, что unsigned_integer тоже находится в Box, в этом случае разыменование имеет смысл.

cafce25 19.04.2023 13:07

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