如何在协议扩展中定义初始化程序? [英] How to define initializers in a protocol extension?

查看:98
本文介绍了如何在协议扩展中定义初始化程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

protocol Car {
     var wheels : Int { get set}

     init(wheels: Int)

}

extension Car {
    init(wheels: Int) {
        self.wheels = wheels
    }
}

关于self.wheels =车轮我得到了错误

on self.wheels = wheels i get the error

Error: variable 'self' passed by reference before being initialized

如何在协议扩展中定义初始化程序?

How can I define the initializer in the protocol extension?

推荐答案

如您所见,在这种情况下这是行不通的,因为在编译时,必须确保在使用struct/enum/之前已初始化所有属性.课.

As you can see this doesn't work under these circumstances because when compiling, one has to make sure that all properties are initialized before using the struct/enum/class.

您可以要求另一个初始化程序,以便编译器知道所有属性都已初始化:

You can make another initializer a requirement so the compiler knows that all properties are initialized:

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 // 4

从Xcode 7.3 beta 1开始,它可以按预期与structs一起使用,但不能与类一起使用,因为如果它们不是final,则协议中的init(wheels: Int)required init,因此可以覆盖它,因此不能通过扩展名添加.解决方法(如编译器所建议):制作class final.

As of Xcode 7.3 beta 1 it works with structs as expected but not with classes since if they are not final the init(wheels: Int) in the protocol is a required init and it can be overridden therefore it cannot be added through an extension. Workaround (as the complier suggests): Make the class final.

要使用类而不使它们最终定型,您还可以在协议中放弃init(wheels: Int)要求.看来它的行为与以前没有什么不同,但请考虑以下代码:

To work with classes without making them final you can also drop the init(wheels: Int) requirement in the protocol. It seems that it behaves no different than before but consider this code:

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)要求.

So if you make a Car from a generic context where the type on which you call init is only to be known as Car the extension initializer is called even though an initializer is defined in HoverCar. This only occurs because there is no init(wheels: Int) requirement in the protocol.

如果添加它,则以前的问题是将class声明为final,但是现在它打印两次"HoverCar".无论哪种方式,第二个问题都可能永远不会发生,因此它可能是一个更好的解决方案.

If you add it you have the former problem with declaring the class as final but now it prints two times "HoverCar". Either way the second problem probably never occurs so it might be a better solution.

旁注:如果我犯了一些错误(代码,语言,语法等),欢迎您纠正我:)

Sidenote: If I have made some mistakes (code, language, grammar,...) you're welcome to correct me :)

这篇关于如何在协议扩展中定义初始化程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆