如何添加并使用枚举用例作为协议类型要求?
解决方案
问题原因
协议扩展中的self是Component协议类型,编译器无法确认它对应具体枚举的.custom用例,因此直接使用guard case .custom(let value) = self会触发编译错误。
方案一:让每个枚举自行实现customValue(推荐)
这是最安全、性能最优的方式,每个遵守Component协议的枚举直接实现customValue,利用自身的枚举用例进行模式匹配:
protocol Component: Equatable { static var `default`: Self { get } static func custom(value: Int) -> Self var customValue: Int? { get } } // 示例枚举1 enum ButtonComponent: Component { case `default` case custom(Int) static var `default`: ButtonComponent { .default } static func custom(value: Int) -> ButtonComponent { .custom(value) } var customValue: Int? { guard case .custom(let value) = self else { return nil } return value } } // 示例枚举2 enum IconComponent: Component { case `default` case custom(Int) static var `default`: IconComponent { .default } static func custom(value: Int) -> IconComponent { .custom(value) } var customValue: Int? { guard case .custom(let value) = self else { return nil } return value } }
此时相等性检查可以直接用==操作符,因为协议继承了Equatable,枚举会自动合成相等性实现(只要所有关联值类型符合Equatable)。
方案二:利用反射实现默认的customValue
如果想避免重复编写customValue的实现,可以通过反射在协议扩展中提取.custom用例的关联值,但这种方式依赖枚举用例的名称,且性能略差:
protocol Component: Equatable { static var `default`: Self { get } static func custom(value: Int) -> Self var customValue: Int? { get } } extension Component { var customValue: Int? { let mirror = Mirror(reflecting: self) guard mirror.displayStyle == .enum, let caseLabel = mirror.children.first?.label, caseLabel == "custom", let value = mirror.children.first?.value as? Int else { return nil } return value } } // 示例枚举只需实现协议核心要求,无需重复编写customValue enum ButtonComponent: Component { case `default` case custom(Int) static var `default`: ButtonComponent { .default } static func custom(value: Int) -> ButtonComponent { .custom(value) } }
关于相等性检查
只要让协议继承Equatable,遵守协议的枚举会自动合成相等性判断逻辑(前提是枚举的所有关联值类型都符合Equatable),直接使用==即可比较两个枚举实例是否相等。
内容的提问来源于stack exchange,提问作者christophriepe
相关产品推荐
相关产品推荐

