この記事はSwift Advent Calendar 2016の24日目の記事です。 Swift4で導入されるConditional conformances(条件付き適合)について調べてみました。
Conditional conformances(条件付き適合)とは
Swift Evolutionでは、今後のSwift向けのいろいろな機能が検討されています。 Xcode8がでるまでは、Swift3向けの機能でもりあがっていましたが、Swift3もおちついてきて、Swift4向けの機能の検討にうつってきています。 先日、SE-0143 Conditional conformances がSwift4にむけて承認されました。
Conditional conformancesとはなんでしょうか。 Genericsはプロトコルに適合できませんが、これを特定の条件下でできるようにしたのが、Conditional conformancesです。
例えば、下記のようなArrayを作ります。
ArrayのElementがEquatableの場合、Array
下記のようにArrayのArrayの==演算をしようとしても、通常はエラーとなります。
let a1: Array<Int> = [1,2,3,4,5] let a2: Array<Int> = [1,2,3,4,5] let diffBetweenArray = (a1 == a2) let diffBetweenArryOfArray = ([a1] == [a2]) // Error!
Array自体にEquatableを適合させようとしても、Swift3.0ではエラーとなってしまいます。
// Error!! extension Array:Equatable where Element: Equatable { static func == (lhs: Array<Element>,rhs: Array<Element>) -> Bool { return ..... } }
Conditional conformances(条件付き適合)が採用されると、例えば、Arrayは、ElementがEquqtableに適合していた場合、Equatableに適合することができるようになります。
Arrayで==が使えるけど?
Array
/// Returns `true` if these arrays contain the same elements. public func ==<Element : Equatable>(lhs: ContiguousArray<Element>, rhs: ContiguousArray<Element>) -> Bool
ジェネリクスの動的な型チェック
ジェネリクスがプロトコルに適合することで、動的な型チェックも可能となります。
下記はSE-0143にあげてあった例ですが、プロトコルPに適合しているかどうかでArrayの型チェックを行うことができます。 これは意外に実プロジェクトで役にたちそうな気がしますね。
protocol P { func doSomething() } struct S: P { func doSomething() { print("S") } } // Array conforms to P if it's element type conforms to P extension Array: P where Element: P { func doSomething() { for value in self { value.doSomething() } } } // Dynamically query and use conformance to P. func doSomethingIfP(_ value: Any) { if let p = value as? P { p.doSomething() } else { print("Not a P") } } doSomethingIfP([S(), S(), S()]) // prints "S" three times doSomethingIfP([1, 2, 3]) // prints "Not a P"
これからのジェネリクス
Conditional conformancesや今後のジェネリクスについては、Swiftのジェネリクスの設計方針(Generics manifesto)にも書いてあります。
このConditional conformancesについては、Swift4で導入される予定です。