问题
So I was playing around with protocol extensions and i ran into an "interesting" problem.
I wanted to write a Meters
and Kilometers
units type for testing some things out. Its VERY easy to do this as a class where there is a base class and both sub classes override the base, while just overriding a simple value
//Conversion factor between types
enum DISTANCE_UNIT_TYPE : Double {
case METER = 1.0;
case KILOMETER = 0.001;
}
protocol DistanceUnit {
var unitType : DISTANCE_UNIT_TYPE {get}
var value : Double { get set }
var baseValue : Double { get set }
}
struct Kilometers : DistanceUnit {
var unitType = DISTANCE_UNIT_TYPE.KILOMETER
var value : Double
var baseValue : Double
init(_ v : Double) {
value = v
baseValue = v * unitType.rawValue
}
}
struct Meters : DistanceUnit {
var unitType = DISTANCE_UNIT_TYPE.METER
var value : Double
var baseValue : Double
init(_ v : Double) {
value = v
baseValue = v * unitType.rawValue
}
}
So as you can see i have lots of duplicate code (specifically the initializers)
I tried to make a protocol extension to set the default initializer
extension DistanceUnit {
init(_ v : Double) {
value = v
baseValue = v * unitType.rawValue
}
}
but I get an error of variable 'self' passed by reference before being initalized
Is there any way to get this to work or do i just have to type lots of duplicate code? Maybe using unsafe
or something?
回答1:
I assume that fqdn
is right and we won't be able to use custom inits inside protocols extension as we would like to, but only time will tell.
But there is still some workaround:
struct Meters : DistanceUnit {
var unitType = DISTANCE_UNIT_TYPE.METER
var value : Double
var baseValue : Double
init() { // this one is needed as designated initializer for your protocol extension
value = 0
baseValue = 0
}
}
protocol DistanceUnit {
var unitType : DISTANCE_UNIT_TYPE {get}
var value : Double { get set }
var baseValue : Double { get set }
init() // this is new and you will NEED to implement this in your structure or class
}
extension DistanceUnit {
init(_ v : Double) {
self.init()
value = v
baseValue = v * unitType.rawValue
}
// you can now implement a lot more different default inits and they should work fine here :)
// here is a quick example
init(_ s : String) {
self.init(Double(s.characters.count))
}
}
Hope that will help you. I learned this trick a few days ago when i was building a custom generic singleton generator with protocol extensions (see here).
来源:https://stackoverflow.com/questions/31207908/limits-of-protocol-extensions-and-defaults-in-swift2