swift2 の新機能 protocol extension
TRANSCRIPT
2
安達 勇一• 2013/12 入社
• TwitterID: @UsrNameu1
• Github: https://github.com/UsrNameu1
• Blog: http://dev.classmethod.jp/author/yad
• で連載やってます
Protocolのおさらい
• Javaでいうところのインターフェイスのようなもの
6Ⓒ Classmethod, Inc.
protocol Comparable { func compareTo(other: Self) -> Bool}
#cmdevio
Protocolのおさらい
• Protocolに定義できる宣言は
• メソッド
• プロパティ
• subscript
7Ⓒ Classmethod, Inc.
func append(x: Generator.Element)
var hashValue: Int { get }
subscript(index: Int) -> Generator.Element
#cmdevio
Protocolのおさらい
• Protocolに定義できる宣言は
• イニシャライザ
• typealias
• 演算子
8Ⓒ Classmethod, Inc.
init(floatLiteral value: Double)
typealias Element
func == (lhs: Self, rhs: Self) -> Bool
#cmdevio
Protocolのおさらい
• Selfは定義したProtocolに準拠した型を示す
9Ⓒ Classmethod, Inc.
protocol Equatable { func == (lhs: Self, rhs: Self) -> Bool}struct Entity { let id: Int}extension Entity: Equatable {}func == (lhs: Entity, rhs: Entity) -> Bool { return lhs.id == rhs.id}
#cmdevio
Protocolのおさらい
• Selfは定義したProtocolに準拠した型を示す
10Ⓒ Classmethod, Inc.
protocol Equatable { func == (lhs: Self, rhs: Self) -> Bool}struct Entity { let id: Int}extension Entity: Equatable {}func == (lhs: Entity, rhs: Entity) -> Bool { return lhs.id == rhs.id} EquatableのSelfはここではEntityとしてふるまう
#cmdevio
Protocolのおさらい
• Selfはドット経由でProtocolの中で用いれるtypealiasにアクセスできる
11Ⓒ Classmethod, Inc.
protocol Containable { typealias InnerType func contain(content: Self.InnerType)}
#cmdevio
Extensionのおさらい
• Objective-Cでいうところのカテゴリのようなもの
13Ⓒ Classmethod, Inc.
extension Int { func power(times: Int) -> Int { return Int( pow(Double(self), Double(times)) ) }}
#cmdevio
Extensionのおさらい
• Objective-Cでいうところのカテゴリのようなもの
14Ⓒ Classmethod, Inc.
extension Int { func power(times: Int) -> Int { return Int( pow(Double(self), Double(times)) ) }} Int型に累乗計算をするpowerメソッドを追加
#cmdevio
Extensionのおさらい
• Extensionに定義できる宣言は
• 計算プロパティ(クラス、ストラクチャに対して) • タイププロパティ • メソッド • subscript • イニシャライザ • ネストされた型
15Ⓒ Classmethod, Inc. #cmdevio
Extensionのおさらい
• Extensionで既存の型をProtocolに 準拠できる
16Ⓒ Classmethod, Inc.
protocol Writable { func write(content: Self)}extension String: Writable { func write(content: String) { .... }}
#cmdevio
Extensionのおさらい
• class, struct, enumに対して宣言できた
17Ⓒ Classmethod, Inc.
extension SomeClass {}extension SomeStruct {}extension SomeEnum {}
#cmdevio
Protocol Extension とは
• class, struct, enum に加えて protocol に対してもExtensionが 宣言できるようになった
19Ⓒ Classmethod, Inc.
protocol Writable { func write(content: Self)}extension Writable { …}
#cmdevio
Protocol に対する実装• Protocol 本体での宣言に対する デフォルト実装をExtensionで決められる
22Ⓒ Classmethod, Inc.
protocol NumberComponent { typealias NumberType var defaultNumber : NumberType { get }}extension NumberComponent { typealias NumberType = Int var defaultNumber: Int { return 1 }} #cmdevio
Protocol に対する実装• Protocol 本体での宣言に対する デフォルト実装をExtensionで決められる
23Ⓒ Classmethod, Inc.
protocol NumberComponent { typealias NumberType var defaultNumber : NumberType { get }}extension NumberComponent { typealias NumberType = Int var defaultNumber: Int { return 1 }}
デフォルトの NumberTypeはInt
デフォルトのdefaultNumberはIn
#cmdevio
Protocol に対する実装
• デフォルト実装は準拠する型で実装する必要がない
24Ⓒ Classmethod, Inc.
class NumberRepository: NumberComponent {
}
#cmdevio
Protocol に対する実装
• デフォルト実装は準拠する型で実装する必要がない
25Ⓒ Classmethod, Inc.
class NumberRepository: NumberComponent {
}デフォルト実装が宣言されているときはエラーにならない
#cmdevio
Protocol に対する実装• Protocol本体のインターフェイスを使って 実装できる
26Ⓒ Classmethod, Inc.
protocol SequenceType { func map<T>( transform: Self.Generator.Element -> T ) -> [T] func filter( includeElement: Self.Generator.Element -> Bool ) -> [Self.Generator.Element]}
#cmdevio
Protocol に対する実装• Protocol本体のインターフェイスを使って 実装できる
27Ⓒ Classmethod, Inc.
protocol SequenceType { func map<T>( transform: Self.Generator.Element -> T ) -> [T] func filter( includeElement: Self.Generator.Element -> Bool ) -> [Self.Generator.Element]}
個々の要素をマッピングするメソッド
要素をフィルタリングするメソッド
#cmdevio
Protocol に対する実装• Protocol本体のインターフェイスを使って 実装できる
28Ⓒ Classmethod, Inc.
extension SequenceType { func filterMap<T>( includeElement: Self.Generator.Element -> Bool, transform: Self.Generator.Element -> T ) -> [T] { return filter(includeElement) .map(transform) }} #cmdevio
Protocol に対する実装• Protocol本体のインターフェイスを使って 実装できる
29Ⓒ Classmethod, Inc.
extension SequenceType { func filterMap<T>( includeElement: Self.Generator.Element -> Bool, transform: Self.Generator.Element -> T ) -> [T] { return filter(includeElement) .map(transform) }}
要素をフィルタリングしたあとで マッピングするメソッド
#cmdevio
Extension対象への制約
• Extension対象への制約を ジェネリクスと同じwhere構文でつけられる
31Ⓒ Classmethod, Inc.
extension SequenceType where Generator.Element == Bool { var anyTrue: Bool { return reduce(false) { acc, elem in acc || elem } } }
#cmdevio
Extension対象への制約
• Extension対象への制約を ジェネリクスと同じwhere構文でつけられる
32Ⓒ Classmethod, Inc.
extension SequenceType where Generator.Element == Bool { var anyTrue: Bool { return reduce(false) { acc, elem in acc || elem } } }
Protocolへの実装を 利用する際に 満たす必要のある制約
#cmdevio
Extension対象への制約
• Extension対象への制約を ジェネリクスと同じwhere構文でつけられる
33Ⓒ Classmethod, Inc.
// true[true, false, false].anyTrue// false[false, false, false].anyTrue
#cmdevio
34Ⓒ Classmethod, Inc.
SequenceType Generator.Element
Array<Bool> Element = Bool
Extension対象への制約Bool
var anyTrue
#cmdevio
35Ⓒ Classmethod, Inc.
SequenceType Generator.Element
Array<Bool> Element = Bool
Extension対象への制約Bool
var anyTrue
anyTrueプロパティの 宣言を行った際に
#cmdevio
36Ⓒ Classmethod, Inc.
SequenceType Generator.Element
Array<Bool> Element = Bool
Extension対象への制約Bool
var anyTrue
呼び出した型が SequenceTypeに 準拠しているかチェック
#cmdevio
37Ⓒ Classmethod, Inc.
SequenceType Generator.Element
Array<Bool> Element = Bool
Extension対象への制約Bool
var anyTrue
SequenceTypeの Generator.Elementが Boolか チェック
#cmdevio
38Ⓒ Classmethod, Inc.
SequenceType Generator.Element
Array<Bool> Element = Bool
Extension対象への制約Bool
var anyTrue
SequenceTypeのGenerator.Elementが Boolなのでデフォルト実装を使える
#cmdevio
Extension対象への制約
• Extension対象への制約を ジェネリクスと同じwhere構文でつけられる
39Ⓒ Classmethod, Inc.
// true[true, false, false].anyTrue// false[false, false, false].anyTrue
Generator.Element == Bool を満たす型に対しては anyTrueプロパティを呼び出せる
#cmdevio
Extension対象への制約
• Extension対象への制約を 満たさないような型に対しては準拠していても インターフェイスを呼び出せない
40Ⓒ Classmethod, Inc.
// エラー[1, 2, 3].anyTrue[3.4, 5.6, 3.2].anyTrue
#cmdevio
41Ⓒ Classmethod, Inc.
SequenceType Generator.Element
Array<Int> Element = Int
Extension対象への制約Bool
var anyTrue
SequenceTypeの Generator.Elementが Boolかチェック
x
#cmdevio
42Ⓒ Classmethod, Inc.
SequenceType Generator.Element
Array<Int> Element = Int
Extension対象への制約Bool
var anyTrue
SequenceTypeのGenerator.Elementが Boolではないので デフォルト実装を使えない
x
#cmdevio
Extension対象への制約
• Extension対象への制約を 満たさないような型に対しては準拠していても インターフェイスを呼び出せない
43Ⓒ Classmethod, Inc.
// エラー[1, 2, 3].anyTrue[3.4, 5.6, 3.2].anyTrue
Generator.Element == Boolの制約に合わないため、 anyTrueプロパティは呼び出せない
#cmdevio
Selfへの制約
• Protocolに準拠した型を示すSelfもExtensionの 制約対象とできる
45Ⓒ Classmethod, Inc.
protocol Ordered { func precedes(other: Self) -> Bool}
#cmdevio
Selfへの制約
• Protocolに準拠した型を示すSelfもExtensionの 制約対象とできる
46Ⓒ Classmethod, Inc.
protocol Ordered { func precedes(other: Self) -> Bool}「先行する」という関係をprecedesメソッドで 定義したOrderedプロトコル
#cmdevio
Selfへの制約
• Protocolに準拠した型を示すSelfもExtensionの 制約対象とできる
47Ⓒ Classmethod, Inc.
extension Ordered where Self: Comparable { func precedes(other: Self) -> Bool { return self < other }}
#cmdevio
Selfへの制約
• Protocolに準拠した型を示すSelfもExtensionの 制約対象とできる
48Ⓒ Classmethod, Inc.
extension Ordered where Self: Comparable { func precedes(other: Self) -> Bool { return self < other }}
Comparableプロトコルに準拠した型に 対しては既存の演算子を先行する関係の定義に流用する
#cmdevio
• Protocolに準拠した型を示すSelfもExtensionの 制約対象とできる
Selfへの制約
49Ⓒ Classmethod, Inc.
extension Int: Ordered {}1.precedes(0)extension Double: Ordered {}(1.2).precedes(4.1)
#cmdevio
Selfへの制約
51Ⓒ Classmethod, Inc.
OrderedComparable
Double Int
Orderedに既存の型を準拠させる際に
func precedes
#cmdevio
Selfへの制約
52Ⓒ Classmethod, Inc.
OrderedComparable
Double Int
既存の型がComparableに準拠しているか チェックされる
func precedes
#cmdevio
Selfへの制約
53Ⓒ Classmethod, Inc.
OrderedComparable
Double Int
Comparableにも準拠していれば デフォルト実装を使える
func precedes
#cmdevio
• Protocolに準拠した型を示すSelfもExtensionの 制約対象とできる
Selfへの制約
54Ⓒ Classmethod, Inc.
extension Int: Ordered {}1.precedes(0)extension Double: Ordered {}(1.2).precedes(4.1)Comparableプロトコルに準拠した型に対しては 先行する関係を示したprecedeメソッドを 実装なしで呼べる
#cmdevio
• Protocolに準拠した型を示すSelfもExtensionの 制約対象とできる
Selfへの制約
55Ⓒ Classmethod, Inc.
struct Rational: Ordered { var numer: Int var denom: Int} // エラー
#cmdevio
Selfへの制約
56Ⓒ Classmethod, Inc.
OrderedComparable
Rational
既存の型がComparableに準拠しているか チェックされる
func precedes
x
#cmdevio
Selfへの制約
57Ⓒ Classmethod, Inc.
OrderedComparable
Rational
func precedes
x
Comparableに準拠していなければ デフォルト実装が使えない
x
#cmdevio
• Protocolに準拠した型を示すSelfもExtensionの 制約対象とできる
Selfへの制約
58Ⓒ Classmethod, Inc.
struct Rational: Ordered { var numer: Int var denom: Int} // エラー
Comparableプロトコルに準拠しない型に対しては precedesメソッドの実装が必要
#cmdevio
グローバル関数の変更
• Swift 1.2 ではProtocol Extensionがつかえず、 Protocolに対するメソッド呼び出しは グローバル関数で実現されていた。
理想
現実
61Ⓒ Classmethod, Inc.
contains([1, 2, 3, 4], 5)
[1, 2, 3, 4].contains(5)
#cmdevio
グローバル関数の変更
• Swift 1.2 ではProtocol Extensionがつかえず、 Protocolに対するメソッド呼び出しは グローバル関数で実現されていた。
理想
現実
62Ⓒ Classmethod, Inc.
contains([1, 2, 3, 4], 5)
[1, 2, 3, 4].contains(5)
要素がEquatableなSequenceTypeに対して . でメソッド呼び出しを行いたかった
第一引数をProtocolに準拠した型の値とした 関数で呼び出していた
#cmdevio
グローバル関数の変更理想
現実
63Ⓒ Classmethod, Inc.
contains(filter([1, 2, 3, 4]) { a in a % 2 == 0 }, 5)
[1, 2, 3, 4].filter { a in a % 2 == 0}.contains(5)
要素がEquatableなSequenceTypeに対して . でメソッド呼び出しを行いたかった
第一引数をProtocolに準拠した型の値とした 関数で呼び出していた
#cmdevio
グローバル関数の変更
• Swift 1.2 -> 2 でグローバル関数の多くがProtocolのメソッドに移行した
65Ⓒ Classmethod, Inc.
https://developer.apple.com/library/prerelease/ios/releasenotes/General/iOS90APIDiffs/modules/Swift.html
#cmdevio
グローバル関数の変更
• Swift 1.2 -> 2 でグローバル関数の多くがProtocolのメソッドに移行した
66Ⓒ Classmethod, Inc.
https://developer.apple.com/library/prerelease/ios/releasenotes/General/iOS90APIDiffs/modules/Swift.html
#cmdevio
グローバル関数の変更
• Swift 1.2 -> 2 でグローバル関数の多くがProtocolのメソッドに移行した
Swift 1.2
Swift 2
67Ⓒ Classmethod, Inc.
contains([1, 2, 3, 4], 5)
[1, 2, 3, 4].contains(5)
#cmdevio
• Swift 1.2 -> 2 でグローバル関数の多くがProtocolのメソッドに移行した Swift 1.2
Swift 2
グローバル関数の変更
68Ⓒ Classmethod, Inc.
contains(filter([1, 2, 3, 4]) { a in a % 2 == 0 }, 5)
[1, 2, 3, 4].filter { a in a % 2 == 0}.contains(5)
#cmdevio
•プロトコル拡張を使ってプログラミングするhttp://ez-net.jp/article/4F/W2t_ixtF/OKrMCHTLSvx7/
• Protocol-Oriented Programming in Swifthttps://developer.apple.com/videos/wwdc/2015/?id=408
70Ⓒ Classmethod, Inc.
References
#cmdevio
73Ⓒ Classmethod, Inc.
http://dev.classmethod.jp/smartphone/wwdc-2015-
swift-2/