標籤:計算 com string 系統 nbsp ini 觀察 guard 特性
在Swift中協議不僅可以定義方法和屬性,而且協議是可以擴充的,最關鍵的是,在協議的擴充中可以添加一些方法的預設實現,就是在協議的方法中可以實現一些邏輯,由於這個特性,Swift是可以面向協議進行編程的。
擴充協議和預設實現
protocol Record { var wins: Int{get} var losses:Int{get} func winningPercent() -> Double}struct BasketballRecord:Record,CustomStringConvertible { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) }}struct baseballRecord:Record,CustomStringConvertible { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) }}let teamRecord = BasketballRecord(wins: 2, losses: 10)print(teamRecord)let baseball = baseballRecord(wins: 3, losses: 10)print(baseball)
我們可以看到 這兩個結構體 都分別繼承了Record 和 CustomStringConvertible協議 其中第一個是我們自訂的協議 第二個是系統協議,在Swift中協議也是可以繼承的,於是我們可以改寫成下面的模式。
protocol Record:CustomStringConvertible { var wins: Int{get} var losses:Int{get} func winningPercent() -> Double}struct BasketballRecord:Record { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) }}struct baseballRecord:Record { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) }}
你會看到還是有冗餘的代碼 就是遵守CustomStringConvertible協議 實現的description的返回時一樣的,這個時候我們就像進一步封裝,那麼我們該怎麼做呢?這個其實就用到我們所說:協議是可以擴充的,而且在擴充中協議的屬性和方法是可以有預設實現的,我們可以這樣寫:
protocol Record:CustomStringConvertible { var wins: Int{get} var losses:Int{get} func winningPercent() -> Double}//擴充協議extension Record { var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) }}struct BasketballRecord:Record { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } }struct baseballRecord:Record { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) }}
這樣寫是不是就方便多了呢,但是仔細觀察 我們在遵守協議的各個結構體中是不是還有邏輯類似,但是寫了好幾遍的代碼呢,我們是不是也可以考慮,將計算勝率的方法也遷移到擴充中呢?
protocol Record:CustomStringConvertible { var wins: Int {get} var losses:Int {get} }//擴充協議extension Record { var description: String { return String.init(format: "wins: %d, losses:%d", [wins,losses]) } var gamePlayed:Int { return wins + losses } func winningPercent() -> Double { return Double(wins)/Double(gamePlayed) } }struct BasketballRecord:Record { var wins: Int var losses: Int}struct baseballRecord:Record { var wins: Int var losses: Int}
是不是更加簡便了呢,那麼假如一場比賽既有輸贏,又有打平的時候呢,我們新增加一個協議,當遵守了不同的協議,他們執行的預設方法,就是既滿足了有輸贏又可以打平裡面擴充的方法的預設實現,如果只遵守了一個Record協議,則執行擴充Record中的預設實現。
protocol Record:CustomStringConvertible { var wins: Int {get} var losses:Int {get} }//打平的協議protocol Tieable { var ties:Int {get set}}//擴充即遵守了Record協議的又遵守了Tieable協議extension Record where Self:Tieable { var gamePlayed:Int { return wins + losses + ties } func winningPercent() -> Double { return Double(wins)/Double(gamePlayed) }}//擴充協議extension Record { var description: String { return String.init(format: "wins: %d, losses:%d", [wins,losses]) } var gamePlayed:Int { return wins + losses } func winningPercent() -> Double { return Double(wins)/Double(gamePlayed) } }struct BasketballRecord:Record { var wins: Int var losses: Int}struct baseballRecord:Record { var wins: Int var losses: Int}//可以平局的struct FootBallRecord:Record,Tieable { var wins: Int var losses: Int var ties: Int}協議彙總
文法結構
協議1 & 協議2
範例程式碼
//判斷是否可以獲得獎勵的協議protocol Prizable { func isPrizable() -> Bool}func award(prizable: Prizable & CustomStringConvertible){ if prizable.isPrizable() { print(prizable) print("你可以獲獎") }else{ print("您不可以獲獎") }}
表示這個函數的參數 即遵守Prizable協議,也遵守了CustomStringConvertible的協議。
泛型約束
struct Student:CustomStringConvertible,Equatable,Comparable,Prizable{ var name:String var score:Int var description: String { return name } func isPrizable() -> Bool { return score > 60 }}func == (s1:Student,s2:Student)->Bool { return s1.score == s2.score}func < (s1:Student,s2:Student) ->Bool { return s1.score < s2.score}let tian = Student(name: "tian", score: 90)let a = Student(name: "Alice", score: 80)let b = Student(name: "Bob", score: 67)let c = Student(name: "Karl", score: 66)let students = [a,b,c,tian]//報錯 原因是因為Comparable 這個協議的實現中自己調用了自己 此時這種協議不能當作一種類型 在這種情況下我們可以改為下面的代碼func topOne(seq:[Comparable]) ->Comparable { }
為瞭解決上面的錯誤,我們可以這樣寫
struct Student:CustomStringConvertible,Equatable,Comparable,Prizable{ var name:String var score:Int var description: String { return name } func isPrizable() -> Bool { return score > 60 }}func == (s1:Student,s2:Student)->Bool { return s1.score == s2.score}func < (s1:Student,s2:Student) ->Bool { return s1.score < s2.score}let tian = Student(name: "tian", score: 90)let a = Student(name: "Alice", score: 80)let b = Student(name: "Bob", score: 67)let c = Student(name: "Karl", score: 66)let students = [a,b,c,tian]func topOne<T:Comparable>(seq:[T]) ->T { assert(seq.count > 0) return seq.reduce(seq[0]){ max($0, $1) }}topOne(seq: [4,5,7,8])func topPrizableOne<T:Comparable & Prizable>(seq:[T]) ->T? { return seq.reduce(nil) { (tempTop:T?,contender:T) in guard contender.isPrizable() else { return tempTop } guard let tempTop = tempTop else { return contender } return max(tempTop, contender) }}topPrizableOne(seq: students)?.name
Swift 學習筆記(面向協議編程)