Как видите, в данных обстоятельствах это не работает, потому что при компиляции нужно убедиться, что все свойства инициализированы перед использованием 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». В любом случае вторая проблема, вероятно, никогда не возникнет, поэтому это может быть лучшим решением.
Примечание: если я допустил какие-то ошибки (код, язык, грамматика и т. д.), вы можете меня исправить :)
person
Qbyte
schedule
25.06.2015