在上一篇介紹了使用協定來規範應該實作的屬性、方法或是建構式,今天要來聊到如何使用 Extension 茁壯 Protocol 的方式。
extension 型別/協定 {
...
}
可以使用 Extension 擴展原本型別,在不透過更改既有型別的內容,來新增的東西,來看個範例:
protocol Flying {
static func fly()
}
struct Person: Flying { }
extension Flying {
static func fly() {
print("I can fly!")
}
}
Person.fly()
// I can fly!
Flying
協定中定義了一個型別方法 fly()
,原本 Person struct 應該要實作這個型別方法,但是我們透過 extension
來延伸這個協定,在裡面定義了 fly()
的實作方式,所以我們在 Person struct 就不用在實作 fly()
方法。
protocol People {
var name: String { get }
}
extension People {
var name: String {
"安竹皮皮"
}
}
struct 人: People { }
let andrew = 人()
print(andrew.name)
屬性也是一樣,都可以用 extension 來擴展。
但並不是使用 extension 擴展就不能在原有的型別中定義同樣的屬性或是方法,還是可以的,而且如果既有型別中有特別定義的話,還是會以自己的為主:
protocol Engineer {
func attendMeeting()
}
extension Engineer {
func attendMeeting() {
print("Go!")
}
}
struct SeniorEngineer: Engineer {
func attendMeeting() {
print("So busy, No way!")
}
}
let developer = SeniorEngineer()
developer.attendMeeting()
// So busy, No way!
定義了一個協定 Engineer
,Engineer 要開會,有一個 attendMeeting()
方法必須實作,這邊使用了 extension 來定義實作詳細方式,print("Go!")
,但是在 SeniorEngineer
結構中雖然遵循了 Engineer Protocol,但是資深工程師總是忙碌了一點,對於參加會議另外定義了方法,實作內容為 print("So busy, No way!")
,儘管在擴展協定中有定義好 attendMeeting()
的實作內容,但是既有的型別中如果也有定義的話,會先以自己的為主喔。
protocol Engineer {
func attendMeeting()
}
struct SeniorEngineer {
func attendMeeting() {
print("No way!")
}
}
extension SeniorEngineer: Engineer { }
在 SeniorEngineer
結構,雖然有時做 attendMeetin()
方法,但是沒有遵循 Engineer Protocol,即使滿足了協定中的要求,也不會自動遵循 Protocol,除非我們自己加上要遵循的 Protocol。
透過 extension,我們可以擴展這個結構,事後來遵循 Engineer Protocol。
我們在定義協定時,可以在協定名稱後方加上 : class
,這樣這個協定就只有 Class 的相關型別才能夠遵循:
protocol Engineer: class {
func attendMeeting()
}
struct SeniorEngineer {
func attendMeeting() {
print("No way!")
}
}
extension SeniorEngineer: Engineer { }
// error: Non-class type 'SeniorEngineer' cannot conform to class protocol 'Engineer'
如果不是 Class 型別來遵循時,就會跳出 Non-class type 'SeniorEngineer' cannot conform to class protocol 'Engineer'
這種錯誤訊息。
Extension 除了可以用於 Protocol,還可以被具有封裝特性的型別來使用喔,所以舉凡 Class、Struct 以及 Enum 都可以來使用 extension 來擴展型別或是協定喔。
Extension 讓我們可以在不碰到既有型別的原始碼,可以加上自定義的一些功能,這種方式就稱為 Retrospective Modeling。