protocol Car { var wheels : Int { get set} init(wheels: Int) } extension Car { init(wheels: Int) { self.wheels = wheels } }
on self.wheelels = wheel我得到错误
Error: variable 'self' passed by reference before being initialized
如何在协议扩展中定义初始化程序?
正如您可以看到,这在这些情况下不起作用,因为编译必须确保在使用struct / enum / class之前初始化所有属性。
您可以使另一个初始化程序成为一个要求,因此编译器知道所有属性都已初始化:
protocol Car { var wheels : Int { get set } // make another initializer // (which you probably don't want to provide a default implementation) // a protocol requirement. Care about recursive initializer calls :) init() init(wheels: Int) } extension Car { // now you can provide a default implementation init(wheels: Int) { self.init() self.wheels = wheels } } // example usage // mark as final final class HoverCar: Car { var wheels = 0 init() {} } let drivableHoverCar = HoverCar(wheels: 4) drivableHoverCar.wheels // 6
从Xcode 7.3 beta 1开始,它可以像预期一样使用结构体,但不适用于类,因为如果它们不是最终的,那么协议中的init(wheels:Int)就是一个必需的init,它可以被覆盖,因此不能通过扩展来添加。解决方法(按照编译器的建议):使课程最终化。
另一种解决办法(深入;没有最后的班级)
要使用类而不使它们成为最终,您还可以在协议中删除init(wheels:Int)要求。看来它的行为与以前没有什么不同,但考虑这个代码:
protocol Car { var wheels : Int { get set } init() // there is no init(wheels: Int) } extension Car { init(wheels: Int) { self.init() print("Extension") self.wheels = wheels } } class HoverCar: Car { var wheels = 0 required init() {} init(wheels: Int) { print("HoverCar") self.wheels = wheels } } // prints "HoverCar" let drivableHoverCar = HoverCar(wheels: 4) func makeNewCarFromCar<T: Car>(car: T) -> T { return T(wheels: car.wheels) } // prints "Extension" makeNewCarFromCar(drivableHoverCar)
因此,如果您从通用上下文中创建一个Car,其中调用init的类型仅被称为Car即使在HoverCar中定义了初始化程序,也会调用扩展初始化程序。这只是因为在协议中没有init(wheels:Int)要求。
如果添加它,则将前一个问题声明为final,但现在打印两次“HoverCar”。无论哪种方式,第二个问题可能永远不会发生,所以它可能是一个更好的解决方案