Swift协议扩展初始化器强制调用self.init()问题咨询及解决
这是个非常典型的Swift协议初始化器规则问题,我来帮你拆解清楚:
为什么编译器强制要求调用self.init()?
首先得明确Swift初始化器的核心规则:对于值类型(比如你的Structure结构体),便捷初始化器必须调用同一个类型中的指定初始化器,不能直接返回——因为指定初始化器的职责是确保所有存储属性都被正确初始化,而便捷初始化器是基于指定初始化器来简化初始化流程的。
回到你的代码:协议Protocol要求的init()是一个指定初始化器要求,但当你在协议扩展中提供它的默认实现时,这个默认实现的初始化器会被当作便捷初始化器对待(这是Swift的设计规则:协议扩展中的初始化器默认实现无法替代类型自身对协议指定初始化器的显式实现)。
所以这个扩展里的init()作为便捷初始化器,必须调用Structure的指定初始化器来完成所有存储属性的初始化(哪怕你的结构体没有定义任何存储属性,Swift编译器依然会严格遵循这个规则)。如果省略self.init(),编译器会判定你没有完成初始化流程的闭环,因此抛出错误。
而你现在调用self.init()时,因为Structure没有显式实现init(),所以又会回到协议扩展的init()里,形成无限递归循环。
如何解决这个问题?
有两种常见的解决方案,你可以根据需求选择:
方案1:显式实现协议要求的指定初始化器
直接在Structure中实现Protocol要求的init(),这样调用Structure()时会直接使用结构体自己的初始化器,不会再走协议扩展的逻辑:
struct Structure: Protocol { init(string: String) { } // 显式实现协议要求的指定初始化器 init() { // 这里可以添加自定义逻辑,或者留空(如果没有存储属性需要初始化) print("结构体自己的init()") } }
这样调用Structure()时,会执行你写的init(),不会触发无限循环。
方案2:在协议扩展的初始化器中调用具体的指定初始化器
如果你不想显式实现init(),可以在协议扩展的init()里调用Structure已有的指定初始化器(比如init(string: String)),这样就能完成初始化流程,同时避免递归:
extension Protocol { init() { print("协议扩展的init()") // 调用结构体的指定初始化器,而不是递归调用自己 self.init(string: "") } }
这样当你调用Structure()时,会先执行协议扩展里的打印,然后调用init(string: "")完成结构体的初始化,不会出现无限循环。
内容的提问来源于stack exchange,提问作者prat14k

