From 8ec0820b5ae2bb3597f45b3fd0ccf6202da16746 Mon Sep 17 00:00:00 2001 From: futantan Date: Mon, 29 Jun 2015 19:24:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A02.0=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=83=A8=E5=88=86=E7=9A=84=E8=8B=B1=E6=96=87=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=B7=BB=E5=8A=A0=E9=83=A8=E5=88=86=E7=9A=84?= =?UTF-8?q?md=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/22_Protocols.md | 76 +++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md index dad93021..3e31a805 100644 --- a/source/chapter2/22_Protocols.md +++ b/source/chapter2/22_Protocols.md @@ -815,3 +815,79 @@ for _ in 1...5 { // 0 // 0 ``` + +## Protocol Extensions + +Protocols can be extended to provide method and property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function. + +For example, the `RandomNumberGenerator` protocol can be extended to provide a `randomBool()` method, which uses the result of the required `random()` method to return a random `Bool` value: + +```swift +extension RandomNumberGenerator { + func randomBool() -> Bool { + return random() > 0.5 + } +} +``` + +By creating an extension on the protocol, all conforming types automatically gain this method implementation without any additional modification. + +```swift +let generator = LinearCongruentialGenerator() +print("Here's a random number: \(generator.random())") +// prints "Here's a random number: 0.37464991998171" +print("And here's a random Boolean: \(generator.randomBool())") +// prints "And here's a random Boolean: true" +``` + +### Providing Default Implementations + +You can use protocol extensions to provide a default implementation to any method or property requirement of that protocol. If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension. + +> NOTE +> Protocol requirements with default implementations provided by extensions are distinct from optional protocol requirements. Although conforming types don’t have to provide their own implementation of either, requirements with default implementations can be called without optional chaining. + +For example, the `PrettyTextRepresentable` protocol, which inherits the `TextRepresentable` protocol can provide a default implementation of its required `asPrettyText()` method to simply return the result of the `asText()` method: + +```swift +extension PrettyTextRepresentable { + func asPrettyText() -> String { + return asText() + } +} +``` + +### Adding Constraints to Protocol Extensions + +When you define a protocol extension, you can specify constraints that conforming types must satisfy before the methods and properties of the extension are available. You write these constraints after the name of the protocol you’re extending using a `where` clause, as described in ([Where 子句](TODO)).: + +For instance, you can define an extension to the `CollectionType` protocol that applies to any collection whose elements conform to the `TextRepresentable protocol` from the example above. + +```swift +extension CollectionType where Generator.Element : TextRepresentable { + func asList() -> String { + return "(" + ", ".join(map({$0.asText()})) + ")" + } +} +``` + +The `asList()` method takes the textual representation of each element in the collection and concatenates them into a comma-separated list. + +Consider the `Hamster` structure from before, which conforms to the `TextRepresentable` protocol, and an array of `Hamster` values: + +```swift +let murrayTheHamster = Hamster(name: "Murray") +let morganTheHamster = Hamster(name: "Morgan") +let mauriceTheHamster = Hamster(name: "Maurice") +let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster] +``` + +Because `Array` conforms to `CollectionType`, and the array’s elements conform to the `TextRepresentable` protocol, the array can use the `asList()` method to get a textual representation of its contents: + +```swift +print(hamsters.asList()) +// prints "(A hamster named Murray, A hamster named Morgan, A hamster named Maurice)" +``` + +> NOTE +> If a conforming type satisfies the requirements for multiple constrained extensions that provide implementations for the same method or property, Swift will use the implementation corresponding to the most specialized constraints.