Пример 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) # ❌ требуется явная деструктуризация
}Текущие проблемы
- Деструктуризация вложенных образцов не поддерживается
- Невозможно использовать сторожевые выражения внутри образца
- Оператор
letне поддерживает сопоставление с образцом
Предложение
Основной дизайн
Расширить синтаксис выражения match для поддержки:
- Деструктуризация вложенных образцов: деструктуризация структур на произвольную глубину
- Сторожевые выражения: добавление условия
ifпосле образца - Связывание переменных в образце: непосредственное связывание переменных из образца
Примеры
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 | У пользователей уже есть острая потребность |
Стратегия реализации
Зависимости
- Внешних зависимостей нет
- Требуется предварительно завершить базовую систему типов
Риски
- Сложность компиляции образцов может привести к проблемам с производительностью
- Глубокая вложенность может вызвать переполнение стека
Открытые вопросы
- [ ] Синтаксис циклического образца (связывание через
@)? - [ ] Поддерживать ли проверку полноты (exhaustiveness) образцов во время компиляции?
- [ ] Стратегия оптимизации производительности?
