Swift 运算符声明改进(SE-0077):从数值优先级到 precedencegroup 偏序体系

发布时间:2026/9/23 6:12:35

Swift 运算符声明改进(SE-0077):从数值优先级到 precedencegroup 偏序体系 文档【免费下载链接】swift-evolutionThis maintains proposals for changes and user-visible enhancements to the Swift Programming Language.项目地址https://gitcode.com/gh_mirrors/sw/swift-evolution点击查看免费下载本文基于 swift-evolution 仓库中的 SE-0077 提案 撰写。SE-0077Improved operator declarations是 Swift 3.0 时代重构运算符声明语法与优先级机制的里程碑提案它废除了用整数表达优先级的旧方式引入precedencegroup声明式语法将单一优先级层级替换为基于偏序关系的有向无环图。读者读完本文后将能完整理解precedencegroup的associativity、higherThan、lowerThan、assignment四个核心属性的语义与取舍掌握自定义运算符接入 Swift 标准优先级体系的方法并理解 Swift 编译器如何通过传递性与可达性判定两个运算符能否省略括号。该提案已随 Swift 3.0 落地实现见 releases/swift-3_0.md。提案背景为什么要重写运算符声明在 Swift 早期Swift 2.x时代运算符声明采用数值优先级 结合性的写法声明体是一个无序的属性集合// Swift 2.x 写法 infix operator { precedence 100 associativity left }SE-0077 指出这种设计存在三类根本性缺陷构成了提案的完整动机。数值定义优先级的弊端最初运算符拥有整齐的优先级数值90、100、110、120、130、140、150、160。但随着语言演进越来越多的运算符被引入且优先级数值不能随意改动否则就是破坏性变更于是出现了大量缝合怪数值Range 运算符获得了 135as获得了 132??的优先级高于但低于as因此被硬塞给 131。结果是在与??之间再也无法插入任何自定义运算符。这是数值优先级体系的必然宿命——整数区间有限运算符不断增多最终任何两个已有运算符之间都无法再插入新运算符。单一优先级层级的弊端旧体系要求一个运算符与所有其他运算符都存在优先级关系因为所有运算符共享同一条数值线。这在很多场景下是多余的、甚至有害的。提案列举了两个高频错误模式a b c // 常见的误写模式 a / b as Double // 常见的误写模式C 编译器有时会对这类写法给出警告但 Swift 不会。根因在于优先级对任意两个运算符对都有定义。如果只与位运算相关、/只与算术运算相关那么上面两个表达式就必须加括号从而在编译期就避免这类隐蔽 bug。旧声明语法的弊端旧语法本质上是一袋无结构的词an unstructured bag of words与 Swift 其他声明的风格严重不一致SE-0077 的目标之一就是让运算符声明语法与语言整体风格对齐。解决方案总览运算符 优先级组提案的核心思路是把优先级从运算符身上剥离抽象为独立的优先级组precedence group运算符通过类似继承的语法归属到某个组// 之前 infix operator { precedence 100 associativity left } // 之后 precedencegroup ComparisonPrecedence { associativity: left higherThan: LogicalConjunctionPrecedence } infix operator : ComparisonPrecedence在 Swift 3.0 中这正是我们至今仍在使用的语法。新的声明语法详解运算符声明不再有声明体prefix/infix/postfix运算符声明都简化为一行、无大括号prefix operator ! infix operator 优先级组声明associativity 与组归属优先级组通过precedencegroup关键字声明内部可选的属性包括结合性left或right。infix运算符通过: 组名挂靠到某个组precedencegroup Additive { associativity: left } infix operator : Additive infix operator - : Additive多个运算符可以共享同一个优先级组这正是标准库中、-、、-、|、^同属AdditionPrecedence的实现方式。优先级机制偏序取代全序单一优先级层级的概念被彻底移除。两个相邻的infix运算符若要省略括号其所属优先级组之间必须存在明确的优先级关系否则编译报错precedencegroup Additive { associativity: left } precedencegroup Multiplicative { associativity: left higherThan: Additive } precedencegroup BitwiseAnd { associativity: left } infix operator : Additive infix operator * : Multiplicative infix operator : BitwiseAnd 1 2 * 3 // ok* 的优先级高于 1 2 3 // 错误 与 之间没有定义优先级关系注意BitwiseAnd与Additive/Multiplicative均无关联因此1 2 3必须显式写括号从而规避了引言中a b c这类隐蔽 bug。每个运算符 / 优先级组只能声明一次因此在已有组之间新增优先级关系这条路也被封死保证优先级关系图对读者是稳定、可预期的。传递性传播编译器会对组间关系施加传递性公理。只要A B且B C即可推断A Cprecedencegroup Exponentiative { associativity: left higherThan: Multiplicative } infix operator ** : Exponentiative 1 2 ** 3 // 等价于 1 (2 ** 3)此处Exponentiative Multiplicative、Multiplicative Additive由传递性推出Exponentiative Additive。同时一个优先级组可以声明多个优先级关系多个higherThan/lowerThan条目。DefaultPrecedence未指定组的归宿未显式声明所属组的infix运算符会被隐式归入DefaultPrecedence组precedencegroup DefaultPrecedence { higherThan: Ternary }因此以下两个声明完全等价infix operator | : DefaultPrecedence infix operator |assignment可选链中的特殊折叠行为Swift 2.2 的assignment修饰符允许标记了assignment的运算符被折叠进可选链foo?.bar 2会按foo?(.bar 2)解析而不是在类型检查阶段失败于(foo?.bar) 2。SE-0077 将该行为迁移为优先级组属性assignment: true由组整体继承这一语义。lowerThan跨模块插入低优先级运算符higherThan只能引用低于自己的组无法把新运算符插到已有运算符之下此时可使用lowerThan。若目标运算符位于另一个模块通过lowerThan即可完成插入因为无法修改别处的声明只能在自己的组中反向声明关系// module Swift precedencegroup Additive { higherThan: Range } precedencegroup Multiplicative { higherThan: Additive } // module A precedencegroup Equivalence { higherThan: Comparative lowerThan: Additive // 可行Additive 位于另一模块 } infix operator ~ : Equivalence 1 2 ~ 3 // (1 2) ~ 3因为 Additive Equivalence 1 * 2 ~ 3 // (1 * 2) ~ 3因为 Multiplicative Additive Equivalence 1 2 ~ 3 // 1 (2 ~ 3)因为 Equivalence Comparative 1 2 ~ 3 // 1 (2 ~ 3)因为 Equivalence Comparative Assignment 1 ... 2 ~ 3 // 错误Range 与 Equivalence 之间没有关系详细设计优先级图、可达性与环路检测优先级组关系构成有向无环图所有优先级组之间的higherThan/lowerThan关系构成一张Directed Acyclic GraphDAG。查询两个运算符之间的优先级关系等价于图中的**可达性Reachability**问题——这是该机制在算法层面的本质。传递性检查环路即编译错误所有优先级关系必须是传递且无环的。定义A B、B C的同时又定义A C会直接编译报错。提案给出两个典型环路示例precedencegroup A { higherThan: B } precedencegroup B { higherThan: A } // 构成 A B A 的环precedencegroup A { } precedencegroup B { higherThan: A } precedencegroup C { higherThan: B lowerThan: A } // 构成 C B A C 的环检查是否存在这类矛盾等价于检查优先级组的 DAG 是否包含有向环。禁止拼接无关的导入组通过传递性规则在两个已导入且原本无关的组之间建立新关系属于编译错误// Module X precedencegroup A { } precedencegroup C { } // Module Y import X precedencegroup B { higherThan: A lowerThan: C }编译器会报错B uses transitivity to define relationship between imported groups A and C。理由是若允许这种拼接开发者就能间接在标准库优先级组之间制造关系破坏图的清晰度、误导读者。特殊运算符编译器硬编码内置运算符is、as、as?、as!、、?:有既定优先级但不能用 Swift 语法声明它们属于语法糖。编译器内部将它们的优先级硬编码效果等同于执行了以下并非合法 Swift 的声明// NOT valid Swift infix operator is : CastingPrecedence infix operator as : CastingPrecedence infix operator as? : CastingPrecedence infix operator as! : CastingPrecedence infix operator ?: : TernaryPrecedence infix operator : AssignmentPrecedence文法变化语言层面发生如下词法/文法调整移除局部关键字assignment、precedence新增关键字precedencegroup以及局部关键字higherThan、lowerThan。完整文法如下operator-declaration → prefix-operator-declaration | postfix-operator-declaration | infix-operator-declaration prefix-operator-declaration → prefix operator operator postfix-operator-declaration → postfix operator operator infix-operator-declaration → infix operator operator infix-operator-groupₒₚₜ infix-operator-group → : precedence-group-name precedence-group-declaration → precedencegroup precedence-group-name { precedence-group-attributes } precedence-group-attributes → precedence-group-assignmentₒₚₜ precedence-group-associativityₒₚₜ precedence-group-relationsₒₚₜ precedence-group-assignment → assignment : boolean-literal precedence-group-associativity → associativity : precedence-group-associativity-option precedence-group-associativity-option → left | right precedence-group-relations → precedence-group-relation | precedence-group-relation precedence-group-relations precedence-group-relation → higherThan : precedence-group-name precedence-group-relation → lowerThan : precedence-group-name precedence-group-name → identifier注意assignment的取值是boolean-literal即true/false而associativity只允许left或right无none选项。标准库迁移完整的优先级组层次SE-0077 将标准库所有运算符声明重写为优先级组形式。以下层级在 Swift 3.0 及后续版本中长期稳定是自定义运算符接入时的坐标系全部来自提案原文的 Standard library changes 一节precedencegroup AssignmentPrecedence { assignment: true associativity: right } precedencegroup TernaryPrecedence { associativity: right higherThan: AssignmentPrecedence } precedencegroup DefaultPrecedence { higherThan: TernaryPrecedence } precedencegroup LogicalDisjunctionPrecedence { associativity: left higherThan: TernaryPrecedence } precedencegroup LogicalConjunctionPrecedence { associativity: left higherThan: LogicalDisjunctionPrecedence } precedencegroup ComparisonPrecedence { higherThan: LogicalConjunctionPrecedence } precedencegroup NilCoalescingPrecedence { associativity: right higherThan: ComparisonPrecedence } precedencegroup CastingPrecedence { higherThan: NilCoalescingPrecedence } precedencegroup RangeFormationPrecedence { higherThan: CastingPrecedence } precedencegroup AdditionPrecedence { associativity: left higherThan: RangeFormationPrecedence } precedencegroup MultiplicationPrecedence { associativity: left higherThan: AdditionPrecedence } precedencegroup BitwiseShiftPrecedence { higherThan: MultiplicationPrecedence }对应的运算符归属如下摘录postfix operator postfix operator -- // postfix operator ! prefix operator prefix operator -- prefix operator ! prefix operator ~ prefix operator prefix operator - // infix operator : AssignmentPrecedence infix operator * : AssignmentPrecedence infix operator / : AssignmentPrecedence infix operator % : AssignmentPrecedence infix operator : AssignmentPrecedence infix operator - : AssignmentPrecedence infix operator : AssignmentPrecedence infix operator : AssignmentPrecedence infix operator : AssignmentPrecedence infix operator ^ : AssignmentPrecedence infix operator | : AssignmentPrecedence // infix operator ?: : TernaryPrecedence infix operator || : LogicalDisjunctionPrecedence infix operator : LogicalConjunctionPrecedence infix operator : ComparisonPrecedence infix operator : ComparisonPrecedence infix operator : ComparisonPrecedence infix operator : ComparisonPrecedence infix operator : ComparisonPrecedence infix operator ! : ComparisonPrecedence infix operator : ComparisonPrecedence infix operator ! : ComparisonPrecedence infix operator ~ : ComparisonPrecedence infix operator ?? : NilCoalescingPrecedence // infix operator as : CastingPrecedence // infix operator as? : CastingPrecedence // infix operator as! : CastingPrecedence // infix operator is : CastingPrecedence infix operator .. : RangeFormationPrecedence infix operator ... : RangeFormationPrecedence infix operator : AdditionPrecedence infix operator - : AdditionPrecedence infix operator : AdditionPrecedence infix operator - : AdditionPrecedence infix operator | : AdditionPrecedence infix operator ^ : AdditionPrecedence infix operator * : MultiplicationPrecedence infix operator / : MultiplicationPrecedence infix operator % : MultiplicationPrecedence infix operator * : MultiplicationPrecedence infix operator : MultiplicationPrecedence infix operator : BitwiseShiftPrecedence infix operator : BitwiseShiftPrecedence从源码结构可以看出一条清晰的自底向上链Assignment Ternary Default LogicalDisjunction LogicalConjunction Comparison NilCoalescing Casting RangeFormation Addition Multiplication BitwiseShift。这套体系至今仍是 Swift 运算符优先级的事实标准后续提案如 SE-0531 字面量表达式在描述编译期常量折叠时也明确声明运算符优先级与结合性遵循 Swift 标准规则。对现有代码的影响与迁移标准库所有运算符声明被重写优先级组被引入即上文清单。用户自定义运算符同样需要重写。迁移工具会移除旧声明的大括号体infix运算符会被隐式归入DefaultPrecedence。潜在破坏依赖用户自定义运算符之间隐式优先级关系的代码可能被破坏——旧体系中任意两个运算符都有可比优先级新体系下没有显式关系的组之间不可比。这类代码需要手工将运算符加入期望的优先级组来修复。未来方向重排标准库优先级提案明确指出创建它的主要动机之一就是打破标准库运算符的单一层级例如让只与位运算相关、/只与算术相关。但重排标准库优先级是另一个提案的主题需要单独讨论——SE-0077 只负责搭建语法与机制地基。这一地基属性也体现在后续演进中SE-0389 附属宏 特别规定operator与precedencegroup声明永远不能由宏生成因为宏可能借此改写既有代码的优先级图造成看到宏展开的代码与未看到展开的代码之间出现微妙的语义差异——这从侧面印证了优先级组声明在语言语义中的核心地位。备选方案回顾SE-0077 的评审过程中讨论过多套替代设计理解它们有助于把握最终方案的设计取向。分离声明结合性与优先级associativity Multiplicative left precedence Multiplicative Additive precedence Exponentiative Multiplicative任何一条声明中出现组名即视为组定义关系声明只允许以保持一致性。对禁止拼接无关导入组的限制仍然保留。不使用优先级组让每个运算符各自声明优先级关系precedence - precedence precedence / * precedence % * precedence * 缺点关系图会大得多、也更难理解而且优先级组概念仍然存在——只是让每个组中有一个特权运算符作为代表。元循环meta-circular语法让某个特殊类型的常量参与编译期计算struct PrecedenceGroup { enum Associativity { case left, right, none } let associativity: Associativity let higherThan: [StaticString] let lowerThan: [StaticString] } let Multiplicative PrecedenceGroup(.left, [Associativity], [])评审者 John McCall 的结论是运算符优先级本质上必须通过某种方式传达给编译器才能解析代码本提案只是在决定传达的语法既然简单的声明就够了就没有理由采用概念上更复杂的方案。把拼接无关组降级为警告优点简化语言模型、减轻编译器负担当优先级层级被更新破坏时开发者可以快速 hack把所有组拼在一起让代码立即恢复运行。缺点允许了提案所担心的读者困惑场景。用precedence取代precedencegroup优点更短、声明命名风格与协议一致。缺点需要把precedence变成关键字而precedencegroup更能准确表达声明对象的含义。其他语法变体评审中还讨论了大量措辞与书写形式变体关系关键字候选有above/below、upper/lower、greaterThan/lessThan、strongerThan/weakerThan、gt/lt、before/after结合性关键字候选有associate以及associativity(left)、逗号分隔属性、/中缀风格、precedencegroup与单行声明混合等十余种写法详见提案的 Possible syntax variations 一节。最终选定的precedencegroupassociativity:/higherThan:/lowerThan:大括号风格兼顾了可读性、与 Swift 声明风格的统一性以及语法可扩展性。总结SE-0077 用一套简洁、可组合、可验证的声明式语法彻底取代了 Swift 2.x 的数值优先级体系组抽象优先级从运算符身上剥离成为可复用的precedencegroup运算符通过: 组名挂靠偏序取代全序只有在组间显式声明或由传递性推导出关系时才能省略括号从语言层面消灭了一整类优先级误写 bug图论建模组关系构成 DAG环路检测保证一致性可达性查询决定解析结果模块安全的扩展性lowerThan允许跨模块在既有运算符之下插入新组同时禁止通过传递性拼接两个无关的导入组长期稳定标准库的整套优先级层次从 Swift 3.0 沿用至今成为后续所有语言特性从字面量宏到附属宏共同依赖的语义基石。无论是为库定义新的自定义运算符还是阅读 Swift 源码中的precedencegroup声明理解 SE-0077 的设计动机与机制细节都是必不可少的。延伸阅读完整提案见 proposals/0077-operator-precedence.mdSwift 3.0 发布说明见 releases/swift-3_0.md若想了解运算符声明与宏系统的边界约束可参考 SE-0389 附属宏。赞分享文档【免费下载链接】swift-evolutionThis maintains proposals for changes and user-visible enhancements to the Swift Programming Language.项目地址https://gitcode.com/gh_mirrors/sw/swift-evolution点击查看免费下载相关推荐Slang 运算符优先级一致性测试体系从 16 级优先级表到 36 项可执行声明的验证实践Slang 运算符优先级一致性测试体系从 16 级优先级表到 36 项可执行声明的验证实践 导读 本文基于 Slang 着色语言项目中的一致性测试文档 RE编译器图形学编程语言SE-0096Swift 中 dynamicType 从属性到运算符的演进与 type(of:) 的诞生SE 0096Swift 中 dynamicType 从属性到运算符的演进与 type of: 的诞生 导读 SE 0096Converting dynam文档Swift 进化提案解读SE-0024 可选值赋值运算符 ?? 的提出、否决与启示Swift 进化提案解读SE 0024 可选值赋值运算符 ?? 的提出、否决与启示 导读 SE 0024《Optional Value Setter ??文档创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/23 6:12:35

手写实现数独游戏:面试被问原理答不上来?这篇救急

手写实现数独游戏:面试被问原理答不上来?这篇救急 面试时面试官轻飘飘一句:“手写实现一个数独游戏的求解器,讲讲你的思路。” 很多人脑子瞬间空白。不是没写过,是没把 手写实现 数独游戏的核心逻辑吃透。…

2026/9/23 6:12:35

ER图从入门到实战:实体关系建模与数据库设计核心指南

1. 一个让我彻底重视ER图的真实场景先说个我自己的经历。几年前我带一个小型项目,负责设计用户、订单、商品、库存模块的数据库。当时觉得业务简单,随手建了十来张表,外键看心情加,字段命名全凭直觉。结果上线三个月后&#xff0c…

2026/9/23 6:12:35

广州到珠海长隆交通方案对比:从入门到精通的实战指南

广州到珠海长隆交通方案对比:从入门到精通的实战指南 刚拿到车钥匙或者第一次带家人去珠海长隆的朋友,是不是也被“广州到珠海长隆”这个关键词搜出来的海量攻略搞晕了?官方文档太长抓不住重点,小红书帖子又是碎片化的种草,根本没法形成系统性的认知。很…

2026/9/23 7:12:37

大厂老员工回流,30万离职赔偿金该不该退?一份决策框架

1. 先把这个选择题翻译成人话:你面临的到底是什么前两天有个读者给我发私信,原话是这样的:“博主,我今年40岁,之前在一家头部互联网公司干了10年,月薪2万,前几年被裁的时候拿了30万赔偿金。现在…

2026/9/23 7:12:37

本地大模型显存精准评估与Qwen3.8适配指南

1. 这不是“选模型”,是给你的电脑做一次精准的显存体检你看到标题里写的“8G显存选4B,24G上Qwen3.8”,别急着抄作业——这句话背后藏着一个被绝大多数教程刻意忽略的事实:显存占用从来不是模型参数量简单除以2就能算出来的。我用…

2026/9/23 7:12:37

SAP WM 配置全链路:从组织结构到上架下架策略与接口验证

简介:这份文档面向SAP实施顾问、仓储管理业务人员及MM/WM模块学习者,系统讲解WM模块的配置方法,帮助读者理解如何通过参数与策略设置优化仓储作业流程。内容围绕主数据与策略两大主线展开:主数据部分涵盖仓库号控制参数、编号范围…

2026/9/23 7:12:37

事倍功半和事半功倍性能优化

别再事倍功半了,手写实现才是事半功倍的正解 刚毕业那会儿,我盯着屏幕上报错的 IndexOutOfBoundsException…

2026/9/23 7:12:37

技术型创业公司如何突破B端商业化困境

1. 技术型创业公司的商业化困境2019年,我亲眼见证了一个工业AI视觉检测团队的兴衰。这个团队的技术实力堪称顶尖——他们的算法在国际竞赛中斩获第一,检测精度比人工高出50倍,处理速度比同行快10倍。然而,当他们带着这套系统去拜访…

2026/9/23 7:07:37

车载智能语音系统实战项目源码拆解

车载智能语音系统实战项目源码拆解 学会语法却不知怎么搭项目,这是很多开发者的死穴。 你背熟了 Python 的类定义,Java 的线程池,Go 的协程,但一提到车载智能语音系统,脑子就是一片空白。…

2026/9/22 10:02:42

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/22 9:07:39

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/23 0:01:54

3个实战技巧搞定形式英语:从看教程到跑通性能优化

3个实战技巧搞定形式英语:从看教程到跑通性能优化 看了一堆教程还是不会写项目?别慌,这种“眼高手低”的困境在开发者圈子里太常见了。很多人以为卡点在语法,其实真正拦路虎是缺乏将知识点串联成完整链路的能力。今天咱们不聊虚的,直接拿【形式英语】这…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码