Ответ
Да, начиная с Swift 2, можно предоставить реализацию по умолчанию для методов и вычисляемых свойств протокола с помощью расширения протокола (protocol extension).
protocol Vehicle {
var fuelLevel: Double { get }
func startEngine()
}
// Расширение протокола с реализацией по умолчанию
extension Vehicle {
// Реализация метода по умолчанию
func startEngine() {
print("Engine started for a generic vehicle.")
}
// Вычисляемое свойство по умолчанию
var isFuelLow: Bool {
return fuelLevel < 0.1
}
}
struct Car: Vehicle {
var fuelLevel: Double
// Метод startEngine() не реализован — используется версия по умолчанию
}
let myCar = Car(fuelLevel: 0.5)
myCar.startEngine() // Выводит: "Engine started for a generic vehicle."
print(myCar.isFuelLow) // Выводит: false
Важные детали:
- Переопределение: Тип, соответствующий протоколу, может предоставить свою собственную реализацию, которая будет иметь приоритет над реализацией по умолчанию.
- Ограничения: Реализация по умолчанию не может добавлять stored properties или новые требования к протоколу.
- Специализация: Можно создавать расширения с ограничениями
whereдля предоставления реализаций по умолчанию только определенным типам.extension Vehicle where Self: Electric { func startEngine() { print("Silent electric engine started.") } }
Ответ 18+ 🔞
О, смотри-ка, какая интересная хуйня! Swift, блядь, с версии 2.0 подсуетился и сделал так, что протоколам можно давать дефолтные пиздюлины — то есть, реализацию по умолчанию. Делается это через расширение протокола, ёпта!
protocol Vehicle {
var fuelLevel: Double { get }
func startEngine()
}
// Вот сюда, в это расширение, и пихаем всю дефолтную логику, чтоб она не мозолила глаза
extension Vehicle {
// Метод по умолчанию
func startEngine() {
print("Engine started for a generic vehicle.")
}
// Вычисляемое свойство по умолчанию — да, и такое можно, блядь!
var isFuelLow: Bool {
return fuelLevel < 0.1
}
}
struct Car: Vehicle {
var fuelLevel: Double
// А тут startEngine() даже не паримся реализовывать — берём то, что дали сверху!
}
let myCar = Car(fuelLevel: 0.5)
myCar.startEngine() // Напечатает эту общую хуйню: "Engine started for a generic vehicle."
print(myCar.isFuelLow) // false, потому что бензина ещё дохуя
Но есть, конечно, свои подводные ебучки, блядь:
-
Переопределить можно всегда. Если твоя структура или класс вдруг возьмут и скажут «нахуй эту дефолтную логику, я сам знаю, как заводиться!» — то их реализация будет главнее. Просто объявляешь свой метод внутри типа, и всё, дефолтный идёт лесом.
-
Нельзя воткнуть stored properties. Расширение протокола — это не волшебная палочка, блядь. Требования протокола добавить или stored properties налепить через него — низя. Только методы и вычисляемые свойства.
-
А вот это вообще мощь: можно делать специализированные дефолтные реализации через
where. Типа, «вот этой конкретной категории уёбков — особый привет».
extension Vehicle where Self: Electric {
func startEngine() { print("Silent electric engine started.") }
}
Вот так вот, блядь. Удобная штука, если не перепихивать туда всю бизнес-логику, а то получится пиздопроебибна, в которой потом сам чёрт ногу сломит.