为什么Swift的extension可以重写Double类型的默认round方法?
原因解释
首先要先明确规则的适用边界:
- 大家常说的「扩展不能重写已有方法、会触发编译报错」仅针对类(class)类型:类的方法走动态派发逻辑,扩展重写已经存在的类方法会导致运行时调用混乱,所以编译器直接禁止这类操作。
- 而
Double是值类型的结构体(struct),值类型的方法全部走静态派发,不存在动态派发的重写概念,同名方法仅为「遮蔽」效果,本身不受上面那条规则限制。
至于为什么给Double写同签名round()不会报重名错误,核心是方法查找优先级的差异:
系统原生Double并没有在自身的主定义里实现round()实例方法,我们平时用的round()相关能力,要么是全局函数func round(_: Double) -> Double,要么是FloatingPoint协议提供的跨模块默认扩展实现。Swift的方法查找规则明确:当前模块的扩展实现优先级高于跨模块的协议默认实现,因此编译器不会判定你的扩展为重复定义,会默认优先调用你在当前模块写的扩展方法。
你可以用以下代码验证两者的区别:
extension Double { func round() { print("调用自定义round方法") } } var pi = 3.14159 pi.round() // 输出:调用自定义round方法 print(round(pi)) // 调用系统全局round函数,输出:3.0
补充说明:如果你在当前模块自定义的结构体,已经在主声明里实现了某方法,再在扩展中写同签名方法依然会触发重名报错,这和Double的场景差异在于:Double的原有round()实现不属于当前模块,优先级更低,因此不会产生冲突。
内容的提问来源于stack exchange,提问作者kabachiha
相关产品推荐
相关产品推荐

