24.Swift協(xié)議

//協(xié)議:規(guī)定了用來(lái)實(shí)現(xiàn)某一特定任務(wù)或者功能的方法、屬性,以及其他需要的東西。
//類(lèi)、結(jié)構(gòu)體、枚舉都可以遵循協(xié)議,并為協(xié)議定義的這些要求提供具體實(shí)現(xiàn)。
//某個(gè)類(lèi)型能滿足某個(gè)協(xié)議的要求,就可以說(shuō)該類(lèi)型遵循這個(gè)協(xié)議
//除了遵循協(xié)議的類(lèi)型必須實(shí)現(xiàn)的要求外,還可以對(duì)協(xié)議進(jìn)行擴(kuò)展,通過(guò)擴(kuò)展來(lái)實(shí)現(xiàn)一部分要求或者實(shí)現(xiàn)一些附加功能,這樣遵循協(xié)議的類(lèi)型就能夠使用這些功能

/**1.協(xié)議語(yǔ)法
    protocol SomeProtocol {
        //這里是協(xié)議的定義部分
    }
 要讓自定義類(lèi)型遵循某個(gè)協(xié)議,在定義類(lèi)型時(shí),需要在類(lèi)型名稱(chēng)后加上協(xié)議名稱(chēng),中間以冒號(hào)(:)分割,遵循多個(gè)協(xié)議時(shí),各協(xié)議直接用逗號(hào)(,)分隔
    struct SomeStructure: FirstProtocol, AnotherProtocol {
        //這里是結(jié)構(gòu)體的定義部分
    }
 擁有父類(lèi)的類(lèi)在遵循協(xié)議時(shí),應(yīng)該講父類(lèi)名放在協(xié)議名之前,以都厚分隔:
    class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
        //這里是類(lèi)的定義部分
    }
 */

//2.屬性要求
//協(xié)議可以要求遵循協(xié)議的類(lèi)型提供d特定名稱(chēng)和類(lèi)型的實(shí)例屬性或類(lèi)型屬性;協(xié)議還指定屬性是可讀的還是可讀寫(xiě)的;但不指定x屬性是存儲(chǔ)型屬性還是計(jì)算型屬性

protocol SomeProtocolMust{//協(xié)議用var關(guān)鍵字來(lái)聲明變量屬性,在類(lèi)型聲明后加上{set get}來(lái)表示屬性是可讀可寫(xiě)的,可讀屬性用{ get }來(lái)表示
    var mustBeSettable: Int { get set }
    var justGetter: Int { get }
    //在協(xié)議中定義類(lèi)型屬性是,總是使用 static 關(guān)鍵字 作為前綴。當(dāng)類(lèi)類(lèi)型遵循協(xié)議時(shí),除了 static關(guān)鍵字,還可以使用 class 關(guān)鍵字來(lái)聲明類(lèi)型屬性
    static var someTypeProperty: Int { get set }
}
//示例:
protocol FullyNamed {//該協(xié)議除了要求遵循協(xié)議的類(lèi)型提供 fullName屬性外,并沒(méi)有其他特別的要求。
    var fullName: String { get } // 這個(gè)協(xié)議表示,任何遵循 fullyNamed的類(lèi)型,都必須有一個(gè)可讀的 String 類(lèi)型的實(shí)例屬性 fullName
}
struct PersonM: FullyNamed { //該結(jié)構(gòu)體遵循了FullyNamed協(xié)議
    var fullName: String //如果不滿足FullyNamed協(xié)議,在編譯時(shí)會(huì)報(bào)錯(cuò)
}
let johnM = PersonM(fullName: "斯威夫特")
print("johnM的名字是:\(johnM.fullName)")

class StarshipM: FullyNamed {
    var prefix: String?
    var name: String
    init(name:String, prefix: String? = nil) {
        self.name = name
        self.prefix = prefix
    }
    var fullName: String { //將 fullName 屬性實(shí)現(xiàn)為只讀的計(jì)算型屬性
        return (prefix != nil ? prefix! + " " : "") + name // 返回 prefix+name,prefix為空就返回name
    }
}
var ncc1701 = StarshipM(name: "企業(yè)號(hào)", prefix: "聯(lián)合艦隊(duì)")
print("ncc1701星艦的名字是:\(ncc1701.fullName)")

//3.方法要求
//協(xié)議可以要求遵循協(xié)議的類(lèi)型實(shí)現(xiàn)某些指定的實(shí)例方法或類(lèi)方法。可以在協(xié)議中定義具有可變參數(shù)的方法,但是不能為其參數(shù)提供默認(rèn)值
//在協(xié)議中定義類(lèi)方法的時(shí)候,需要使用static關(guān)鍵字作為前綴,當(dāng)類(lèi)類(lèi)型遵循協(xié)議時(shí),除了static關(guān)鍵字,還可以使用class關(guān)鍵字作為前綴
protocol SomeProtocolFunc {
    static func SomeTypeMethod()
}
//示例:定義了一個(gè)只含有一個(gè)實(shí)例方法的協(xié)議
protocol RandomNumberGenerator { //該協(xié)議要求遵循協(xié)議的類(lèi)型必須擁有一個(gè)名為random,返回值類(lèi)型為Double實(shí)例方法。
    func random() -> Double
}
class LinearCongruentialGenerator: RandomNumberGenerator {//同余數(shù)生成程序
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
    func random() -> Double {
        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy: m)) //使用 truncatingRemainder 方法進(jìn)行浮點(diǎn)數(shù)取余: (lastRandom * a + c)% m 取余數(shù)
        return lastRandom / m
    }
}
let generatorLine = LinearCongruentialGenerator()
print("第一個(gè)隨機(jī)數(shù)為:\(generatorLine.random())")
print("第二個(gè)隨機(jī)數(shù)為:\(generatorLine.random())")


//4.Mutating 方法要求
//將mutating關(guān)鍵字作為方法的前綴寫(xiě)在func關(guān)鍵字之前,表示可以在該方法中修改它所屬的實(shí)例以及實(shí)例的任意屬性的值。
//實(shí)現(xiàn)協(xié)議中的mutating方法時(shí),若是類(lèi)類(lèi)型則不用謝mutating關(guān)鍵字。對(duì)于結(jié)構(gòu)體和枚舉,則必須寫(xiě)mutating關(guān)鍵字。
protocol Togglable {
    mutating func toggle() // toggle()方法在定義時(shí)使用mutating標(biāo)記,表明當(dāng)它被調(diào)用時(shí),將會(huì)改變遵循協(xié)議的類(lèi)型的實(shí)例
}
enum OnOffSwitch: Togglable {
    case off,on
    mutating func toggle() { //當(dāng)枚舉或結(jié)構(gòu)體實(shí)現(xiàn)toggle()方法時(shí)需要在前面加上mutating前綴
        switch self {
        case .off:
            self = .on
        case .on:
            self = .off
        }
    }
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle()
print("開(kāi)關(guān)的值為:\(lightSwitch)")


//5.構(gòu)造器要求
//協(xié)議可以要求遵循協(xié)議的類(lèi)型實(shí)現(xiàn)指定的構(gòu)造器。你可以想編寫(xiě)普通構(gòu)造器那樣,在協(xié)議的定義里寫(xiě)下構(gòu)造器的聲明,但不需要寫(xiě)花括號(hào)和構(gòu)造器的實(shí)體:
protocol SomeProtocolInit{
    init(someParameter: Int)
}
//可以在遵循協(xié)議的類(lèi)中實(shí)現(xiàn)構(gòu)造器,無(wú)論是作為指定構(gòu)造器,還是作為便利構(gòu)造器,都必須為構(gòu)造器實(shí)現(xiàn)標(biāo)上required修飾符:
class SomeClassInit: SomeProtocolInit {
    required init(someParameter: Int) { //使用required 修飾符可以確保所有子類(lèi)也必須提供此構(gòu)造器實(shí)現(xiàn),從而也能符合協(xié)議。如果類(lèi)已經(jīng)被標(biāo)記為 final 那么不需要在協(xié)議構(gòu)造器的實(shí)現(xiàn)中使用required修飾符,因?yàn)閒inal類(lèi)不能有子類(lèi)。
        //這里是構(gòu)造器的實(shí)現(xiàn)部分
    }
}
//如果一個(gè)子類(lèi)重寫(xiě)了父類(lèi)的指定構(gòu)造器,并且該構(gòu)造器滿足了某個(gè)協(xié)議的要求,那么該構(gòu)造器的實(shí)現(xiàn)需要同時(shí)標(biāo)注required 和 override修飾符
protocol SomeProtocolSup {
    init()
}
class SomeSuperClassSup {
    init() {
        //這里是構(gòu)造器的實(shí)現(xiàn)部分
    }
}
class SomeSubClassSup: SomeSuperClassSup,SomeProtocolSup {
    //因?yàn)樽裱藚f(xié)議,所以要加上 required; 因?yàn)槔^承自父類(lèi),所以需要加上 override
    required override init() {
        //這里是構(gòu)造器的實(shí)現(xiàn)部分
    }
}
//協(xié)議還可以為遵循協(xié)議的類(lèi)型定義可失敗構(gòu)造器要求。遵循協(xié)議的類(lèi)型可以通過(guò)可失敗構(gòu)造器(init?)或非可失敗構(gòu)造器(init)來(lái)滿足協(xié)議中定義的可失敗構(gòu)造器要求。協(xié)議中定義的非可失敗構(gòu)造器要求可以通過(guò)非可失敗構(gòu)造器(init)或隱式解包可失敗構(gòu)造器(init?。﹣?lái)滿足。


//6.協(xié)議作為類(lèi)型
//協(xié)議開(kāi)一被昂做一個(gè)成熟的類(lèi)型來(lái)使用,使用場(chǎng)景有:作為函數(shù)、方法或構(gòu)造器中的參數(shù)類(lèi)型或返回值類(lèi)型;作為常量、變量或?qū)傩缘念?lèi)型、作為數(shù)組、字典或其他容器中的元素類(lèi)型。
class DiceP {//骰子
    let sides: Int //表示 骰子有幾個(gè)面
    let gennerator: RandomNumberGenerator // 為骰子提供一個(gè)隨機(jī)數(shù)生成器
    init(sides: Int, gennerator: RandomNumberGenerator) {
        self.sides = sides
        self.gennerator = gennerator
    }
    func roll() -> Int { //骰出來(lái)的數(shù)字
        return Int(gennerator.random() * Double(sides)) + 1
    }
}
var d6 = DiceP(sides: 6, gennerator: LinearCongruentialGenerator())
for _ in 1...5 {
    print("隨機(jī)的骰子數(shù)為:\(d6.roll())")
}


//7.委托代理模式
//委托是一種設(shè)計(jì)模式,它允許類(lèi)或結(jié)構(gòu)體將一些需要它們負(fù)責(zé)的功能委托給其他類(lèi)型的實(shí)例。委托模式的實(shí)現(xiàn)很簡(jiǎn)單:定義協(xié)議來(lái)封裝那些需要被委托的功能,這樣就能確保遵循協(xié)議的類(lèi)型能提供這些功能。委托模式可以用來(lái)響應(yīng)特定的動(dòng)作,或者接收外部數(shù)據(jù)源提供的數(shù)據(jù),而無(wú)需關(guān)心外部數(shù)據(jù)源的類(lèi)型。
protocol DiceGameP { //可以被任意涉及骰子的游戲遵循。
    var dice: DiceP { get }
    func play()
}
protocol DiceGameDelegate {//可以被任意類(lèi)型遵循,用來(lái)追蹤DiceGame的游戲過(guò)程
    func gameDidStart(_ game: DiceGameP)
    func game(_ game: DiceGameP, didStartNewTurnWithDiceRoll diceRoll: Int)
    func gameDidEnd(_ game: DiceGameP)
}
class SnakesAndLadders: DiceGameP { // 遵循DiceGameP協(xié)議
    let finalSquare = 25
    let dice = DiceP(sides: 6, gennerator: LinearCongruentialGenerator())//只要求dice為可讀
    var square = 0
    var board: [Int]
    init() {
        board = [Int](repeating: 0, count: finalSquare + 1)
        board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
        board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
    }
    var delegate: DiceGameDelegate?
    func play() {
        square = 0//當(dāng)前位置
        delegate?.gameDidStart(self)//開(kāi)始游戲
        gameLoop: while square != finalSquare {//循環(huán) 當(dāng)前位置 != 終點(diǎn)位置
            let diceRoll = dice.roll()//骰出來(lái)的數(shù)字
            delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)//游戲中,
            switch square + diceRoll {//當(dāng)前位置 + 骰出來(lái)的數(shù)字
            case finalSquare: // 終點(diǎn)位置
                break gameLoop // 結(jié)束游戲
            case let newSquare where newSquare > finalSquare: // 超過(guò)終點(diǎn)位置
                continue gameLoop//開(kāi)始下一輪循環(huán)
            default:
                square += diceRoll
                square += board[square]
            }
        }
        delegate?.gameDidEnd(self) // 游戲結(jié)束
    }
}

class DiceGameTracker: DiceGameDelegate {//記錄游戲的過(guò)程
    var numberOfTurns = 0
    func gameDidStart(_ game: DiceGameP) {// 游戲開(kāi)始
        numberOfTurns = 0
        if game is SnakesAndLadders {
            print("開(kāi)始了蛇和梯子的新游戲")
        }
        print("游戲使用了 \(game.dice.sides)角骰子")
    }
    func game(_ game: DiceGameP, didStartNewTurnWithDiceRoll diceRoll: Int) { //游戲中
        numberOfTurns += 1
        print("骰子骰出來(lái)的數(shù)字是\(diceRoll)")
    }
    func gameDidEnd(_ game: DiceGameP) { // 游戲結(jié)束
        print("比賽持續(xù)了\(numberOfTurns)圈")
    }
}

let trackerP = DiceGameTracker()
let gameP = SnakesAndLadders()
gameP.delegate = trackerP
gameP.play()


//8.通過(guò)擴(kuò)展添加協(xié)議一致性
//可以通過(guò)擴(kuò)展 讓已有類(lèi)型 遵循并符合協(xié)議;擴(kuò)展可以為已有類(lèi)型添加屬性、方法、下標(biāo)以及構(gòu)造器,因此可以符合協(xié)議中的相應(yīng)要求。
//注意:通過(guò)擴(kuò)展令已有類(lèi)型遵循并符合協(xié)議時(shí),該類(lèi)型的所有實(shí)例也會(huì)隨之獲得協(xié)議中定義的各項(xiàng)功能。
protocol TextRepresentable {//該協(xié)議只具有一個(gè)文本描述的功能
    var textualDescription: String { get }
}
extension DiceP: TextRepresentable { // 為 DiceP 類(lèi)添加擴(kuò)展,另其遵循 TextRepresentable 協(xié)議
    var textualDescription: String { // 實(shí)現(xiàn)協(xié)議方法
        return "這是一個(gè)\(sides)面骰子"
    }
}
//現(xiàn)在 所有的 DiceP 的實(shí)例 都可以看做TextRepresentable類(lèi)型
let d12 = DiceP(sides: 12, gennerator: LinearCongruentialGenerator())
print(d12.textualDescription)

extension SnakesAndLadders: TextRepresentable {
    var textualDescription: String {
        return "這是一個(gè)有\(zhòng)(finalSquare)個(gè)格子的蛇與梯子游戲"
    }
}
print(gameP.textualDescription)


//9.通過(guò)擴(kuò)展遵循協(xié)議
//當(dāng)一個(gè)類(lèi)型已經(jīng)符合了某個(gè)協(xié)議中的所有要求,卻還沒(méi)有聲明遵循該協(xié)議時(shí),可以通過(guò)空擴(kuò)展體的擴(kuò)展來(lái)遵循該協(xié)議:
struct Hamster {
    var name: String
    var textualDescription: String {
        return "小老鼠的名字叫\(zhòng)(name)"
    }
}
extension Hamster: TextRepresentable{}
//此時(shí),Hamster的實(shí)例可以作為T(mén)extRepresentable類(lèi)型使用:
let simonTheHamster = Hamster(name: "碩鼠")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
print(somethingTextRepresentable.textualDescription)


//10.協(xié)議類(lèi)型的集合
//協(xié)議類(lèi)型可以在數(shù)組或者字典這樣的集合中使用。
let thingsP: [TextRepresentable] = [gameP, d12, simonTheHamster]
for thing in thingsP {
    print("遍歷thingsP 數(shù)組: \(thing.textualDescription)")
}


//11.協(xié)議的繼承
//協(xié)議能夠繼承一個(gè)或多個(gè)其他協(xié)議,可以在繼承的協(xié)議的基礎(chǔ)上增加新的要求,協(xié)議的繼承語(yǔ)法與類(lèi)的繼承相似,多個(gè)被繼承的協(xié)議間用逗號(hào)分隔
protocol InHeritingProtocol: SomeProtocolSup, SomeProtocolFunc {
    //這里是協(xié)議的定義部分
}
protocol PrettyTextRepresentablePR: TextRepresentable { //PrettyTextRepresentablePR 協(xié)議繼承了 TextRepresentable 協(xié)議;任何遵循PrettyTextRepresentablePR協(xié)議的類(lèi)型在滿足該協(xié)議的要求時(shí), 也必須滿足 TextRepresentable 協(xié)議的要求。
    var prettyTextualDescription: String { get }
}
//擴(kuò)展SnakesAndLadders 類(lèi) 使其遵循 PrettyTextRepresentablePR 協(xié)議
extension SnakesAndLadders: PrettyTextRepresentablePR {
    var prettyTextualDescription: String {
        var output = textualDescription + ":\n"
        for index in 1...finalSquare {
            switch board[index] {
            case let ladder where ladder > 0:
                output += "▲ "
            case let snake where snake < 0:
                output += "▼ "
            default:
                output += "○ "
            }
        }
        return output
    }
}
print(gameP.prettyTextualDescription)


//12.類(lèi)類(lèi)型專(zhuān)屬協(xié)議
//可以在協(xié)議的繼承列表中,通過(guò)添加class關(guān)鍵字來(lái)限制協(xié)議只能被類(lèi)類(lèi)型遵循,而結(jié)構(gòu)體或枚舉不能遵循該協(xié)議.
//class關(guān)鍵字必須第一個(gè)出現(xiàn)在協(xié)議的繼承列表中,在其他繼承的協(xié)議之前:
protocol SomeClassOnlyProtocol: class, SomeProtocolFunc {
    //這里是類(lèi)類(lèi)型專(zhuān)屬協(xié)議的定義部分
}
//注意:當(dāng)協(xié)議定義的要求需要遵循協(xié)議的類(lèi)型必須是引用語(yǔ)義而非值語(yǔ)義時(shí),應(yīng)該采用類(lèi)類(lèi)型專(zhuān)屬協(xié)議。


//13.協(xié)議合成
//有時(shí)候需要同時(shí)遵循多個(gè)協(xié)議,可以將多個(gè)協(xié)議采用 SomeProtocol & AnothreProtocol這樣的格式進(jìn)行組合,稱(chēng)為協(xié)議合成
protocol NamedP {
    var name: String { get }
}
protocol AgedP {
    var age: Int { get }
}
struct PersonP: NamedP, AgedP {
    var name: String
    var age: Int
}
func wishHappyBirthday(to celebrator: NamedP & AgedP){
    print("生日快樂(lè),\(celebrator.name), 你今年\(celebrator.age)歲了")
}
let birthdayPerson = PersonP(name: "豆豆", age: 3)
wishHappyBirthday(to: birthdayPerson)

//將Location類(lèi)和前面的Named協(xié)議進(jìn)行組合:
class LocationP {
    var latitude: Double
    var longitude: Double
    init(latitude: Double, longitude: Double) {
        self.latitude = latitude
        self.longitude = longitude
    }
}
class CityP: LocationP, NamedP {
    var name: String
    init(name: String, latitude: Double, longitude: Double) {
        self.name = name
        super.init(latitude: latitude, longitude: longitude)
    }
}
func beginConcert(in location: LocationP & NamedP) { //接受任何Location的子類(lèi),并且遵循Named協(xié)議
    print("Hello, \(location.name)!")
}
let seattle = CityP(name: "狗狗", latitude: 42.3, longitude: -120.4)
beginConcert(in: seattle)


//14.檢查協(xié)議一致性
//可以使用 is 和 as 操作符來(lái)檢查是否符合協(xié)議,并且可以轉(zhuǎn)換到指定的協(xié)議類(lèi)型。
//is  用來(lái)檢查實(shí)例是否符合某個(gè)協(xié)議,若符合則返回true,否則返回false
//as? 返回一個(gè)可選值,當(dāng)實(shí)例符合某個(gè)協(xié)議時(shí),返回類(lèi)型為協(xié)議類(lèi)型的可選值,否則返回nil
//as! 將實(shí)例強(qiáng)制向下轉(zhuǎn)換到某個(gè)協(xié)議類(lèi)型,如果強(qiáng)轉(zhuǎn)失敗,會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤
protocol HasAreaJ {
    var area: Double { get }
}
class CircleJ: HasAreaJ {
    let pi = 3.1415927
    var radius: Double
    var area: Double { return pi * radius * radius}
    init(radius: Double) { self.radius = radius }
}
class CountryJ: HasAreaJ {
    var area: Double
    init(area: Double) { self.area = area }
}
class AnimalJ {
    var legs: Int
    init(legs: Int) { self.legs = legs }
}
let objects: [AnyObject] = [
    CircleJ(radius: 2.0),
    CountryJ(area: 234610),
    AnimalJ(legs: 4)
]
for object in objects {
    if let objectWithArea = object as? HasAreaJ {
        print("遵循了HasAreaJ協(xié)議:\(objectWithArea.area)")
    } else {
        print("沒(méi)有遵循HasAreaJ協(xié)議")
    }
}

//15.可選的協(xié)議要求
//協(xié)議可以定義可選要求,遵循協(xié)議的類(lèi)型可以選擇是否實(shí)現(xiàn)這些要求。
//在協(xié)議中使用 optional 關(guān)鍵字 作為前綴來(lái)定義可選要求;在需要和OC代碼打交道中,協(xié)議 和 可選要求 都必須帶上@objc屬性;
//標(biāo)記@objc特性的協(xié)議只能被繼承自O(shè)C類(lèi)的類(lèi) 或者 @objc類(lèi)遵循,其他類(lèi)以及結(jié)構(gòu)體和枚舉均不能遵循這種協(xié)議。
//使用可選要求時(shí),他們的類(lèi)型會(huì)自動(dòng)變成可選的,比如:一個(gè)類(lèi)型為(Int) -> String 的方法 會(huì)變成 ((Int) -> String)? 需要注意的是整個(gè)函數(shù)類(lèi)型是可選的,而不是函數(shù)的返回值。
@objc protocol CounterDataSource {
    @objc optional func incrementForCount(count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}
//嚴(yán)格上來(lái)講,上面這個(gè)協(xié)議中的方法和屬性都是可選的,遵循該協(xié)議的類(lèi)可以不實(shí)現(xiàn)這些要求,但不推薦這么做。
class Counter {
    var count = 0
    var dataSource: CounterDataSource?
    func increment() {
        if let amount = dataSource?.incrementForCount?(count: count){
            count += amount
        } else if let amount = dataSource?.fixedIncrement {
            count += amount
        }
    }
}
class ThreeSource: NSObject, CounterDataSource {
    let fixedIncrement = 3
}
var counterF = Counter()
counterF.dataSource = ThreeSource()
for _ in 1...4 {
    counterF.increment()
    print("累加的值為:\(counterF.count)")
}


//16.協(xié)議擴(kuò)展
//協(xié)議可以通過(guò)擴(kuò)展來(lái)為遵循協(xié)議的類(lèi)型提供屬性、方法以及下標(biāo)的實(shí)現(xiàn)。
//通過(guò)這種方式,你可以基于協(xié)議本身來(lái)實(shí)現(xiàn)這些功能,而無(wú)需再每個(gè)遵循協(xié)議的類(lèi)型中都重復(fù)同樣的實(shí)現(xiàn),也無(wú)需使用全局函數(shù)。
extension RandomNumberGenerator {
    func randomBool() -> Bool {
        return random() > 0.5
    }
}
let genneratorR = LinearCongruentialGenerator()
print("隨機(jī)數(shù)為:\(genneratorR.random())")
print("隨機(jī)的布爾值為:\(genneratorR.randomBool())")

//提供默認(rèn)實(shí)現(xiàn)
//如果遵循協(xié)議的類(lèi)型為這些要求提供了自己的實(shí)現(xiàn),那么這些自定義實(shí)現(xiàn)將會(huì)替代擴(kuò)展中的默認(rèn)實(shí)現(xiàn)被使用。
//通過(guò)協(xié)議擴(kuò)展為協(xié)議要求提供的默認(rèn)實(shí)現(xiàn)和可選的協(xié)議要求不同。雖然在這兩種情況下,遵循協(xié)議的類(lèi)型都無(wú)需自己實(shí)現(xiàn)這些要求,但是通過(guò)擴(kuò)展提供的默認(rèn)實(shí)現(xiàn)可以直接調(diào)用,而無(wú)需使用可選鏈?zhǔn)秸{(diào)用。
extension PrettyTextRepresentablePR { //PrettyTextRepresentablePR 協(xié)議 繼承自 TextRepresentable協(xié)議,可以為其提供一個(gè) prettyTextualDescription 屬性,只是簡(jiǎn)單地返回textualDescription 屬性的值
    var prettyTextualDescription: String {
        return textualDescription
    }
}

//為協(xié)議擴(kuò)展添加限制條件
//在擴(kuò)展協(xié)議的時(shí)候,可以指定一些限制條件,只有遵循協(xié)議的類(lèi)型滿足這些限制條件是,才能獲得協(xié)議擴(kuò)展提供的默認(rèn)實(shí)現(xiàn)。這些限制條件寫(xiě)在協(xié)議名之后,使用where子句來(lái)描述。
//示例:擴(kuò)展Collection 協(xié)議,但是只適用于集合中的元素遵循了 TextRepresentable 協(xié)議的情況
extension Collection where Iterator.Element: TextRepresentable {
    var textualDescription: String { //返回整個(gè)集合的文本描述
        let itemsAsText = self.map { $0.textualDescription }
        return "[" + itemsAsText.joined(separator: ", ") + "]"
    }
}

let gougouTheHamster = Hamster(name: "狗狗")
let maomaoTheHamster = Hamster(name: "貓貓")
let laoshuTheHamster = Hamster(name: "就叫老鼠")
let hamsters = [gougouTheHamster,maomaoTheHamster,laoshuTheHamster]
//hamsters 數(shù)組符合 Collection協(xié)議,而數(shù)組中的元素又符合TextRepresentable協(xié)議,所以數(shù)組可以使用 textualDescription 屬性得到數(shù)組內(nèi)容的文本表示
print("為協(xié)議擴(kuò)展添加限制:\(hamsters.textualDescription)")
//注意: 若多個(gè)協(xié)議擴(kuò)展都為了同一個(gè)協(xié)議要求 提供了默認(rèn)實(shí)現(xiàn),而遵循協(xié)議的類(lèi)型又同時(shí)瞞住這些協(xié)議擴(kuò)展的限制條件,那么將會(huì)使用限制條件最多的那個(gè)協(xié)議擴(kuò)展提供的默認(rèn)實(shí)現(xiàn)。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容