为何带关联值的Equatable枚举无法自动生成==运算符实现?
带关联值的枚举为何无法默认生成Equatable实现?
先看一个常见的带关联值的枚举示例:
enum Foo { case bar(param0: Bar) case baz(param0: Baz) case foo }
很多时候开发者会手动编写这样的Equatable扩展:
extension Foo: Equatable { static func == (lhs: Foo, rhs: Foo) -> Bool { "\(lhs)" == "\(rhs)" } }
为什么这类实现无法默认生成,必须手动编写?
核心原因在于你写的这种Equatable实现逻辑,和Swift自动合成Equatable的逻辑完全不是一回事:
- 自动合成的前提是结构语义相等:Swift会自动为枚举合成Equatable实现的前提是,枚举所有关联类型都遵守Equatable。合成的逻辑是严格比较枚举的case是否一致,以及对应关联值是否相等——这是基于类型结构的语义相等判断,符合Equatable协议的设计初衷。
- 字符串比较是特殊的外部表示相等:你用
"\(lhs)" == "\(rhs)"的方式,本质是比较枚举实例的字符串描述是否一致,这属于外部表示层面的相等,而非语义相等。比如:- 两个语义不同的实例,可能因为
description的实现问题,字符串表示完全一致; - 同一个语义的实例,可能因为
description的格式调整(比如添加了额外信息),字符串表示变得不同; - 这种判断逻辑完全依赖于
CustomStringConvertible的实现,稳定性和可靠性远不如结构比较。
- 两个语义不同的实例,可能因为
Swift不会默认采用这种非标准的相等判断逻辑,因为它无法确定开发者是否真的需要用字符串描述来定义相等性。只有当你明确需要这种特殊逻辑时,才需要手动编写对应的Equatable实现。
另外要说明:如果你的枚举关联类型都遵守Equatable,根本不需要手动写扩展——Swift会自动帮你合成正确的Equatable实现,完全不会产生样板代码。只有当关联类型不遵守Equatable,你又想用字符串比较这种特殊方式时,才需要手动实现。
内容的提问来源于stack exchange,提问作者Anton Tropashko
相关产品推荐
相关产品推荐

