221 Views
September 12, 15
スライド概要
Swift 2.0 で登場した目玉機能の『Protocol Extension』はジェネリックという型にとらわれない仕組みを活かしたものになっています。ジェネリックでは様々な型をプロトコルなどの様々な条件を組み合わせて機能実装を行っていくんですが、条件によっては、どれが該当するのか、どれが優先されるのか、そもそもビルドエラーになるのか。基本的にはシンプルなルールを組み合わせて作れば良さそうですが、実際にやってみると結構混乱します。
その辺りをサクッと体系立てて紹介できれば…と思ったんですが、調べてみれば微妙な違いがたくさんあって、そこまでたどり着けませんでした。続きはぜひぜひ、みなさんの目で確かめてみてください。
※ Docswell での公開に移行する直前の Slideshare での閲覧数は 1,269 でした。
正統派趣味人プログラマー。プログラミングとは幼馴染です。
ジェネリック関数の 呼び出され方を調べてみる 『難しい』ことだけは分かった! ! EZ-NET 熊谷友宏 http://ez-net.jp/ 2015.09.12 @ 第 63 回 Cocoa 勉強会関西
競合書、作ってます。 VS Xcode 5 徹底解説 2014/04/28 - Xcode 5 完全攻略 2014/02/27 -
競合書、作ってました。 ! 版 絶 Xcode 5 徹底解説 2014/04/28 - 2015/08/21 KO Xcode 5 完全攻略 2014/02/27 -
熊谷友宏 EZ-NET http://ez-net.jp/ @es̲kumagai ̶ 勉強会開催 ̶ #yidev 横浜 iPhone 開発者勉強会 カジュアル Swift 勉強会 @ 青葉台 Xcode 5 徹底解説 MOSA IP Phone 音でダイヤル いつもの電卓 with 割勘ウォッチ 音で再配達ゴッド
Swift 2.0 GM
Swift 2.0 新機能 ▶ Protocol Extension ▶ if-where ▶ Error Handling ▶ for-where ▶ guard ▶ enum : String ▶ defer ▶ Type.init ▶ repeat-while ▶ #available ▶ pattern matching
Swift 2.0 新機能 http://www.slideshare.net/ tomohirokumagai54/swift-20-cswift
Protocol Extension ジェネリックの活用の幅が広がった
Swift 2.0 Protocol Extension http://www.slideshare.net/ tomohirokumagai54/wwdc21cafe
Protocol Extension プロトコルに既定の実装を追加 extension CollectionType where Generator.Element : IntegerType { var sum:Generator.Element { return self.reduce(0, combine: +) } }
ジェネリックで条件を指定 extension CollectionType where Generator.Element : IntegerType {
Array<Int>
どちらの実装が採用される?
extension CollectionType
where Generator.Element : IntegerType {
func action() -> String { return "A" }
}
extension CollectionType
where Generator.Element : BooleanType {
func action() -> String { return "B" }
}
Array<Int>
どちらの実装が採用される?
extension CollectionType
where Generator.Element : Equatable {
func action() -> String { return "A" }
}
extension CollectionType
where Generator.Element : Comparable {
func action() -> String { return "B" }
}
Array<Int>
どちらの実装が採用される?
extension CollectionType
where Generator.Element : Equatable {
func action() -> String { return "A" }
}
extension CollectionType
where Generator.Element : Hashable {
func action() -> String { return "B" }
}
Array<Int>
どちらの実装が採用される?
extension CollectionType
where Generator.Element : Comparable {
s
func action() -> String
{ return "A" }
u
o
}
u
g
i
b
m
A
extension CollectionType
where Generator.Element : ForwardIndexType {
func action() -> String { return "B" }
}
ジェネリックの呼び出され方
構造体と型指定
シンプルな構造体 struct S1 { } S1
型の直指定
シンプルな構造体 どの実装が採用される? func f(v:S1) { } func f(v:S2) { } // 該当なし? S1
シンプルな構造体 どの実装が採用される? func f(v:S1) { } func f(v:Any) { } // 該当なし? S1
シンプルな構造体 どの実装が採用される? func f(v:S2) { } func f(v:Any) { } // 該当なし? S1
オプショナル
構造体とオプショナル どの実装が採用される? func f(v:S1) { } func f(v:S1?) { } // 該当なし? S1?
構造体とオプショナル どの実装が採用される? func f(v:S1) { } func f(v:Any?) { } // 該当なし? S1?
構造体とオプショナル どの実装が採用される? func f(v:S1) { } func f(v:Any) { } // 該当なし? S1?
構造体とオプショナル どの実装が採用される? func f(v:Any) { } る func f(v:Any?) { } ※ // 該当なし? 状 に 況 よ S1?
構造体とオプショナル S1? どの実装が採用される? func f(v:Any) { } • f(Optional(s1)) func f(v:Any?) { } • let opt = Optional(s1) • f(opt) • or • f(Optional<S1>(s1))
クラス
シンプルなクラス class A1 { } A1
シンプルなクラス どの実装が採用される? func f(v:A1) { } func f(v:A2) { } // 該当なし? A1
シンプルなクラス どの実装が採用される? func f(v:A1) { } func f(v:Any) { } // 該当なし? A1
シンプルなクラス どの実装が採用される? func f(v:A2) { } func f(v:Any) { } // 該当なし? A1
クラスとオプショナル どの実装が採用される? func f(v:A1) { } func f(v:A1?) { } // 該当なし? A1?
クラス継承
クラス継承 class A1 { } class B1 : A1 { } B1 A1
クラス継承 B1 どの実装が採用される? func f(v:B1) { } func f(v:B2) { } // 該当なし? A1
クラス継承 B1 どの実装が採用される? func f(v:A1) { } func f(v:A2) { } // 該当なし? A1
クラス継承 B1 どの実装が採用される? func f(v:A1) { } func f(v:B1) { } // 該当なし? A1
クラスを親で扱うとき
クラスを親で扱うとき let v:A1 = B1() B1 A1
クラスを親で扱うとき B1 どの実装が採用される? func f(v:A1) { } func f(v:A2) { } // 該当なし? A1
クラスを親で扱うとき B1 どの実装が採用される? func f(v:B1) { } func f(v:B2) { } // 該当なし? A1
クラスを親で扱うとき B1 どの実装が採用される? func f(v:A1) { } func f(v:B1) { } // 該当なし? A1
型指定とジェネリック指定
基本的なジェネリック
おさらい 型直指定で Any func f(v:Any) { } S1
型指定とジェネリック 型直指定で Any func f(v:Any) { } func f<T>(v:T) { } func f<T:Any>(v:T) { } S1
型指定とジェネリック どの実装が採用される? func f(v:Any) { } func f<T>(v:T) { } // 該当なし? S1
型指定とジェネリック どの実装が採用される? func f<T==S1>(v:T) {NG も } そ も そ // 該当なし? S1
プロトコル
構造体とプロトコル protocol P1 { } struct S1 : P1 { } S1 P1
プロトコルを型で扱う
プロトコルを型で指定 S1 どの実装が採用される? func f(v:P1) { } // 該当なし? P1
プロトコルを型で指定 S1 どの実装が採用される? func f(v:P1) { } func f(v:S1) { } // 該当なし? P1
プロトコルを型で指定 S1 どの実装が採用される? func f(v:P1) { } func f(v:Any) { } // 該当なし? P1
プロトコルを型で指定 S1 どの実装が採用される? func f(v:P2) { } func f(v:Any) { } // 該当なし? P1
プロトコルをジェネリックで扱う
プロトコルを型で指定 S1 どの実装が採用される? func f<T:P1>(v:T) { } // 該当なし? P1
プロトコルを型で指定 S1 どの実装が採用される? func f<T:P1>(v:T) { } func f<T>(v:T) { } // 該当なし? P1
プロトコルを型で指定 S1 どの実装が採用される? func f<T:P1>(v:T) { } func f<T>(v:T) { } func f(v:S1) { } P1
プロトコルを型で指定 S1 どの実装が採用される? func f<T:P1>(v:T) { } func f<T>(v:T) { } func f(v:P1) { } P1
複数のプロトコル
複数のプロトコル S1 P2 protocol P1 { } protocol P2 { } struct S1 : P1, P2 { } P1
複数のプロトコル S1 P2 どの実装が採用される? func f(v:P1) { } func f(v:Any) { } // 該当なし? P1
複数のプロトコル S1 P2 どの実装が採用される? func f(v:P2) { } func f(v:Any) { } // 該当なし? P1
S1 複数のプロトコル P2 どの実装が採用される? P1 func f(v:P1) { } func f(v:P2) { } m A func f(v:Any) { } b u ig s u o
複数のプロトコル S1 P2 どの実装が採用される? func f(v:P1) { } P1 • f(s1 as P1) func f(v:P2) { } func f(v:Any) { } • f(s1 as P2)
ジェネリックで複数プロトコル
複数のプロトコル S1 P2 どの実装が採用される? func f<T:P1>(v:T) { } func f<T>(v:T) { } // 該当なし? P1
複数のプロトコル S1 P2 どの実装が採用される? func f<T:P2>(v:T) { } func f<T>(v:T) { } // 該当なし? P1
S1 複数のプロトコル P2 どの実装が採用される? P1 func f<T:P1>(v:T) { } func f<T:P2>(v:T) { s u } func f(v:Any) { } m A g i b o u
S1 複数のプロトコル P2 どの実装が採用される? P1 func f<T:P1>(v:T) { } • f(s1 as P1) func f<T:P2>(v:T) { } う こ func f<T>(v:T) { } ! い な ら な • f(s1 as P2) ?
複数のプロトコル S1 P2 どの実装が採用される? func f<T:P1>(v:T) { } P1 • f(s1 as P1) func f<T:P2>(v:T) { } func f<T>(v:T) { } • f(s1 as P2)
複数のプロトコル S1 P2 どの実装が採用される? func f<T:P1>(v:T) { } func f<T:P2>(v:T) { } func f(v:Any) { } P1
複数のプロトコル S1 P2 どの実装が採用される? func f<T:P1>(v:T) { } func f<T:P2>(v:T) { } func f(v:Any) { } P1
プロトコル継承
プロトコル継承 S1 P2 protocol P1 { } protocol Q2 { } protocol P2 : Q2 { } struct S1 : P1, P2 { } P1 Q2
ジェネリックで継承を扱う
プロトコル継承 S1 P2 どの実装が採用される? func f<T:P1>(v:T) { } func f<T>(v:T) { } // 該当なし? P1 Q2
プロトコル継承 S1 P2 どの実装が採用される? func f<T:P2>(v:T) { } func f<T>(v:T) { } // 該当なし? P1 Q2
S1 プロトコル継承 P2 どの実装が採用される? P1 func f<T:P1>(v:T) { } s u func f<T:P2>(v:T) { } func f(v:Any) { } m A b o u ig Q2
プロトコル継承 S1 P2 どの実装が採用される? func f<T:Q2>(v:T) { } // 該当なし? P1 Q2
プロトコル継承 S1 P2 どの実装が採用される? func f<T:Q2>(v:T) { } func f<T:P2>(v:T) { } // 該当なし? P1 Q2
S1 プロトコル継承 P2 どの実装が採用される? P1 func f<T:P1>(v:T) { } s u func f<T:Q2>(v:T) { } func f(v:Any) { } m A b o u ig Q2
じゃあ クラスではどうなるのか …!
C1 プロトコル継承 P2 protocol P1 protocol P2 : Q2 protocol Q2 protocol R1 : Q2 class C1 : C2, P1, P2 class C2 : P1, R1 C2 P1 Q2 R1 P1 Q2
クラス継承かつプロトコル継承 間に合いませんでした !
じゃあ 複数引数ではどうなるのか …!
複数引数の場合 間に合いませんでした ! !
ひとつだけ
v1 複数条件での制約 どの実装が採用される? func f<A>(v1:A, v2:A) { } func f<A, B>(v1:A, v2:B) { } // 該当なし? P1 v2 P1
じゃあ プロトコル制約はどうなるのか …!
プロトコル制約 想定する型の条件をプロトコルで指定 func f<T:CollectionType where Generator.Element:IntegerType>(v:T) { } func f<T:CollectionType where Generator.Element:BooleanType>(v:T) { }
where によるプロトコル制約 間に合いませんでした !!!
じゃあ 複数の制約はどうなるのか …!
プロトコル制約
想定する型の条件を複数指定
func f<T:CollectionType, U:Any
where Generator.Element:ForwardIndexType,
Generator:Element:Comparable>
Generator:Element == U>(v:T, w:U) {
}
複数条件でのプロトコル制約 間に合いませんでした !!!!
ひとつだけ
プロトコルが子を内包 PA P PB protocol P1 class C1 : P1 protocol P { class Base : P { typealias PA typealias PB var v1:C1 var v2:C1 } var v1:PA {get} var v2:PB {get} }
v1 複数条件での制約 どの実装が採用される? v2 func f<T:P1, U:P1>(v1:T, v2:U) { } func f<T:Any, U:Any>(v1:T, v2:U) { } // 該当なし? P1 P1
v1 複数条件での制約 どの実装が採用される? v2 func f<T:P1, U:P1>(v1:T, v2:U) { } func f<T:Any, U:Any>(v1:T, v2:U) { } // 該当なし? P1 Q1 P1
P
複数条件での制約
どの実装が採用される?
func f<T:P
Base P1 PA
P1 PB
where T.PA:P1, T.PB:P1>(v:T) {
}
func f<T:P
where T.PA:Any, T.PB:Any>(v:T) {
}
P
複数条件での制約
どの実装が採用される?
func f<T:P
Base P1 PA
Q1 PB
where T.PA:P1, T.PB:P1>(v:T) {
}
func f<T:P
where T.PA:Any, T.PB:Any>(v:T) {
}
P1
P
複数条件での制約
どの実装が採用される?
Base P1 PA
func f<T:P
P1 PB
where T.PA == T.PB>(v:T) {
}
func f<T:P
where T.PA:Any, T.PB:Any>(v:T) {
}
P
複数条件での制約
どの実装が採用される?
Base P1 PA
func f<T:P where T.PA:P1, T.PB:P1,
Q1 PB
T.PA == T.PB>(v:T) {
}
func f<T:P
where T.PA:Any, T.PB:Any>(v:T) {
}
P1
じゃあ プロトコル拡張はどうなるのか …!
プロトコル拡張 プロトコルに既定の実装を追加 extension CollectionType where Generator.Element : IntegerType { var sum:Generator.Element { return self.reduce(0, combine: +) } }
プロトコル拡張 間に合いませんでした !!!!!
型の拡張 構造体 プロトコ ル継承 プロトコ ル拡張 型の直指定 複数プロ トコル クラス とにかく 混沌としている世界 クラス継承 とプロトコル クラス継承 ジェネリッ クでの指定 プロトコル 型で縛る
統べるのは 至難の業かもしれない to be continued