Ответ 1
Как вы можете видеть, это не работает в этих условиях, потому что при компиляции необходимо убедиться, что все свойства инициализированы перед использованием 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 // 4
Как и в Xcode 7.3 beta 1, он работает с structs
, как ожидалось, но не с классами, поскольку, если они не являются final
, init(wheels: Int)
в протоколе является required init
, и его можно переопределить, поэтому он не может быть добавляется через расширение. Обходной путь (как предлагает корреспондент): Сделайте class
final
.
Другое обходное решение (в глубине, без final class
)
Чтобы работать с классами, не делая их окончательными, вы также можете отказаться от требования 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)
.
Если вы добавите его, у вас есть прежняя проблема с объявлением class
как final
, но теперь он печатает два раза "HoverCar". В любом случае, вторая проблема, вероятно, никогда не возникает, поэтому это может быть лучшим решением.
Sidenote: Если я допустил некоторые ошибки (код, язык, грамматика,...), вы можете исправить меня:)