classLinearCongruentialGenerator: RandomNumberGenerator{ var lastRandom =42.0 let m =139968.0 let a =3877.0 let c =29573.0 funcrandom() -> Double { lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m)) return lastRandom / m } } let generator =LinearCongruentialGenerator() print("Here's a random number: \(generator.random())") // Prints "Here's a random number: 0.3746499199817101" print("And another one: \(generator.random())") // Prints "And another one: 0.729023776863283"
enumOnOffSwitch: Togglable{ case off, on mutatingfunctoggle() { switchself { case .off: self= .on case .on: self= .off } } } var lightSwitch =OnOffSwitch.off lightSwitch.toggle() // lightSwitch is now equal to .on
classDice{ let sides: Int let generator: RandomNumberGenerator init(sides: Int, generator: RandomNumberGenerator) { self.sides = sides self.generator = generator } funcroll() -> Int { returnInt(generator.random() *Double(sides)) +1 } }
var d6 =Dice(sides: 6, generator: LinearCongruentialGenerator()) for_in1...5 { print("Random dice roll is \(d6.roll())") } // Random dice roll is 3 // Random dice roll is 5 // Random dice roll is 4 // Random dice roll is 5 // Random dice roll is 4
classDiceGameTracker: DiceGameDelegate{ var numberOfTurns =0 funcgameDidStart(_game: DiceGame) { numberOfTurns =0 if game isSnakesAndLadders { print("Started a new game of Snakes and Ladders") } print("The game is using a \(game.dice.sides)-sided dice") } funcgame(_game: DiceGame, didStartNewTurnWithDiceRolldiceRoll: Int) { numberOfTurns +=1 print("Rolled a \(diceRoll)") } funcgameDidEnd(_game: DiceGame) { print("The game lasted for \(numberOfTurns) turns") } }
实际上它们是这样组合的。
let tracker =DiceGameTracker() let game =SnakesAndLadders() game.delegate = tracker game.play() // Started a new game of Snakes and Ladders // The game is using a 6-sided dice // Rolled a 3 // Rolled a 5 // Rolled a 4 // Rolled a 5 // The game lasted for 4 turns
let d12 =Dice(sides: 12, generator: LinearCongruentialGenerator()) print(d12.textualDescription) // Prints "A 12-sided dice"
类似的,SnakesAndLadders 类也可以实现这个协议。
extensionSnakesAndLadders: TextRepresentable{ var textualDescription: String { return"A game of Snakes and Ladders with \(finalSquare) squares" } } print(game.textualDescription) // Prints "A game of Snakes and Ladders with 25 squares"
按条件实现协议
泛型类型可能仅在某些条件下满足协议的要求,例如当类型的通用参数符合协议时。你可以在扩展一个类型的时候列出制约,可以使泛型有条件地实现某个协议。通过泛型 where 小句将制约写在协议名称之后。
extensionArray: TextRepresentablewhereElement: TextRepresentable{ var textualDescription: String { let itemsAsText =self.map { $0.textualDescription } return"["+ itemsAsText.joined(separator: ", ") +"]" } } let myDice = [d6, d12] print(myDice.textualDescription) // Prints "[A 6-sided dice, A 12-sided dice]"
structHamster{ var name: String var textualDescription: String { return"A hamster named \(name)" } } extensionHamster: TextRepresentable{}
let simonTheHamster =Hamster(name: "Simon") let somethingTextRepresentable: TextRepresentable= simonTheHamster print(somethingTextRepresentable.textualDescription) // Prints "A hamster named Simon"
协议类型集合
协议可以作为集合的类型,比如数组和字典类型。下面是一个例子。
let things: [TextRepresentable] = [game, d12, simonTheHamster]
可以遍历数组打印文字描述。
for thing in things { print(thing.textualDescription) } // A game of Snakes and Ladders with 25 squares // A 12-sided dice // A hamster named Simon
协议继承
协议可以继承。下面是继承语法。
protocolInheritingProtocol: SomeProtocol, AnotherProtocol{ // protocol definition goes here }
protocolPrettyTextRepresentable: TextRepresentable{ var prettyTextualDescription: String { get } }
protocolNamed{ var name: String { get } } protocolAged{ var age: Int { get } } structPerson: Named, Aged{ var name: String var age: Int } funcwishHappyBirthday(tocelebrator: Named & Aged) { print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!") } let birthdayPerson =Person(name: "Malcolm", age: 21) wishHappyBirthday(to: birthdayPerson) // Prints "Happy birthday, Malcolm, you're 21!"
下面是包含一个类名的例子。
classLocation{ var latitude: Double var longitude: Double init(latitude: Double, longitude: Double) { self.latitude = latitude self.longitude = longitude } } classCity: Location, Named{ var name: String init(name: String, latitude: Double, longitude: Double) { self.name = name super.init(latitude: latitude, longitude: longitude) } } funcbeginConcert(inlocation: Location & Named) { print("Hello, \(location.name)!") }
let seattle =City(name: "Seattle", latitude: 47.6, longitude: -122.3) beginConcert(in: seattle) // Prints "Hello, Seattle!"
检查协议的一致性
你可以使用 is 和 as 操作符检查协议实现的一致性和转换到指定协议。语法相同。
下面定义一个例子。
protocolHasArea{ var area: Double { get } }
定义两个类实现这个协议。
classCircle: HasArea{ let pi =3.1415927 var radius: Double var area: Double { return pi * radius * radius } init(radius: Double) { self.radius = radius } } classCountry: HasArea{ var area: Double init(area: Double) { self.area = area } }
下面这个类不实现这个协议。
classAnimal{ var legs: Int init(legs: Int) { self.legs = legs } }
for object in objects { iflet objectWithArea = object as?HasArea { print("Area is \(objectWithArea.area)") } else { print("Something that doesn't have an area") } } // Area is 12.5663708 // Area is 243610.0 // Something that doesn't have an area
let generator =LinearCongruentialGenerator() print("Here's a random number: \(generator.random())") // Prints "Here's a random number: 0.3746499199817101" print("And here's a random Boolean: \(generator.randomBool())") // Prints "And here's a random Boolean: true"
协议扩展可以用来提供一个默认的实现。
extensionPrettyTextRepresentable{ var prettyTextualDescription: String { return textualDescription } }
协议扩展也可以用来添加约束。
extensionCollectionwhereElement: Equatable{ funcallEqual() -> Bool { for element inself { if element !=self.first { returnfalse } } returntrue } }
let equalNumbers = [100, 100, 100, 100, 100] let differentNumbers = [100, 100, 200, 100, 200]
print(equalNumbers.allEqual()) // Prints "true" print(differentNumbers.allEqual()) // Prints "false"