Skip to content

Пример RFC: расширенный синтаксис сопоставления с образцом ​

Внимание: это пример шаблона RFC, демонстрирующий, как написать полноценное предложение RFC. Пожалуйста, используйте этот шаблон в качестве образца при составлении собственного RFC.

Статус: пример (только для справки)

Автор: Чэньсюй (пример автора) Дата создания: 2025-01-05 Последнее обновление: 2026-02-12

Резюме ​

Добавить в YaoXiang более мощные возможности сопоставления с образцом, включая вложенные образцы, сторожевые выражения и связывание с образцом в let.

Мотивация ​

Зачем нужна эта возможность? ​

Текущее выражение match имеет ограниченную функциональность и не может обрабатывать следующие распространённые сценарии:

yaoxiang
# Невозможно деструктурировать вложенные структуры
Person: Type = { name: String, address: Address }
Address: Type = { city: String, zip: Int }
match person {
    Person(name: "Alice", address: Address(city: "Beijing", _)) => "Alice from Beijing"  # ❌ не поддерживается
}

# Невозможно связывать переменные внутри образца
match result {
    ok(value) => print(value)          # ❌ требуется явная деструктуризация
}

Текущие проблемы ​

  1. Деструктуризация вложенных образцов не поддерживается
  2. Невозможно использовать сторожевые выражения внутри образца
  3. Оператор let не поддерживает сопоставление с образцом

Предложение ​

Основной дизайн ​

Расширить синтаксис выражения match для поддержки:

  1. Деструктуризация вложенных образцов: деструктуризация структур на произвольную глубину
  2. Сторожевые выражения: добавление условия if после образца
  3. Связывание переменных в образце: непосредственное связывание переменных из образца

Примеры ​

yaoxiang
# Вложенная деструктуризация
Person: Type = { name: String, address: Address }
Address: Type = { city: String, zip: Int }

match person {
    Person(name: "Alice", address: Address(city: "Beijing", _)) => "Alice from Beijing"
    Person(name: n, address: Address(city: c, _)) => n + " from " + c
}

# Сторожевые выражения
match n {
    n if n > 0 and n < 10 => "1-9"
    n if n >= 10 => "10+"
    _ => "unknown"
}

# Связывание в образце
match result {
    ok(value) => print(value)          # value уже связана
    err(e) => log_error(e)
}

# Вложенность + связывание
match data {
    User(name: first, profile: Profile(age: a)) if a >= 18 => first + " is adult"
}

Сопоставление с образцом в операторе let ​

yaoxiang
# Новый синтаксис
let Point(x: 0, y: _) = point  # связывание только когда x == 0
let Ok(value) = result         # деструктуризация Result

# Множественное связывание
let (a, b, c) = tuple          # деструктуризация кортежа

Подробное проектирование ​

Изменения синтаксиса ​

MatchExpr   ::= 'match' Expr '{' MatchArm+ '}'
MatchArm    ::= Pattern ('|' Pattern)* ('if' Expr)? '=>' Expr ','
Pattern     ::= LiteralPattern
              | IdentifierPattern
              | StructPattern
              | TuplePattern
              | OrPattern
              | RestPattern

LiteralPattern ::= '_' | Literal
IdentifierPattern ::= Identifier (':' Pattern)?
StructPattern ::= Identifier '(' FieldPattern (',' FieldPattern)* ','? ')'
FieldPattern  ::= Identifier ':' Pattern | Identifier
TuplePattern  ::= '(' Pattern (',' Pattern)* ','? ')'
OrPattern     ::= Pattern '|' Pattern
RestPattern   ::= '...'

Влияние на систему типов ​

  • Необходимо расширить проверку типов при сопоставлении с образцом
  • Переменные образца получают корректный тип при успешном сопоставлении

Изменения в компиляторе ​

КомпонентИзменение
lexerдобавление токенов, связанных с образцами
parserдобавление логики разбора образцов
typecheckвывод типов и связывание в образцах
codegenгенерация кода для сопоставления с образцом

Обратная совместимость ​

  • ✅ Полностью обратно совместимо
  • Только добавляется новый синтаксис, существующий синтаксис match не изменяется

Компромиссы ​

Преимущества ​

  • Более выразительный синтаксис, более лаконичный код
  • Согласованность с сопоставлением с образцом в主流 языках (Rust, Scala, Elixir)
  • Уменьшение количества ошибок времени выполнения благодаря раннему обнаружению несоответствий

Недостатки ​

  • Увеличение сложности реализации компилятора
  • Небольшой рост кривой обучения

Альтернативы ​

ВариантПочему не выбран
Только деструктуризация верхнего уровняНе позволяет обрабатывать распространённые вложенные сценарии
Использование функционального стиляНеестественно смешивается с императивным кодом
Отложить до v2.0У пользователей уже есть острая потребность

Стратегия реализации ​

Зависимости ​

  • Внешних зависимостей нет
  • Требуется предварительно завершить базовую систему типов

Риски ​

  • Сложность компиляции образцов может привести к проблемам с производительностью
  • Глубокая вложенность может вызвать переполнение стека

Открытые вопросы ​

  1. [ ] Синтаксис циклического образца (связывание через @)?
  2. [ ] Поддерживать ли проверку полноты (exhaustiveness) образцов во время компиляции?
  3. [ ] Стратегия оптимизации производительности?

Ссылки ​