ジェネリック関数の呼び出され方 #cocoa_kansai
TRANSCRIPT
EZ-NET 熊⾕友宏 http://ez-net.jp/
2015.09.12 @ 第 63 回 Cocoa 勉強会関⻄
呼び出され⽅を調べてみるジェネリック関数の
『難しい』ことだけは分かった! !
競合書、作ってます。
Xcode 5 徹底解説
VS
2014/04/28 -Xcode 5 完全攻略
2014/02/27 -
競合書、作ってました。
Xcode 5 徹底解説
KO
2014/04/28 - 2015/08/21Xcode 5 完全攻略
2014/02/27 -
絶版!
熊谷友宏EZ-NET http://ez-net.jp/ @es_kumagai
Xcode 5 徹底解説
IP Phone 音でダイヤル 音で再配達ゴッドいつもの電卓 with 割勘ウォッチ
MOSA
勉強会開催
#yidev 横浜 iPhone 開発者勉強会カジュアル Swift 勉強会 @ 青葉台
Swift 2.0 GM
Swift 2.0
▶ Protocol Extension ▶ Error Handling ▶ guard ▶ defer ▶ repeat-while ▶ pattern matching
新機能
▶ if-where ▶ for-where ▶ enum : String ▶ Type.init ▶ #available
http://www.slideshare.net/tomohirokumagai54/swift-20-cswift
Swift 2.0新機能
ジェネリックの活用の幅が広がったProtocol Extension
http://www.slideshare.net/tomohirokumagai54/wwdc21cafe
Swift 2.0Protocol Extension
extension CollectionType where Generator.Element : IntegerType {
var sum:Generator.Element { return self.reduce(0, combine: +) }
}
Protocol Extensionプロトコルに既定の実装を追加
ジェネリックで条件を指定
extension CollectionType where Generator.Element : IntegerType {
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 {
func action() -> String { return "A" } }
extension CollectionType where Generator.Element : ForwardIndexType {
func action() -> String { return "B" } }
Array<Int>どちらの実装が採用される?
Ambiguous
ジェネリックの呼び出され方
構造体と型指定
シンプルな構造体 S1
struct 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?
※ 状況による
func f(v:Any) {
}
func f(v:Any?) {
}
どの実装が採用される?構造体とオプショナル S1?
• f(Optional(s1))
• let opt = Optional(s1) • f(opt) • or • f(Optional<S1>(s1))
クラス
シンプルなクラス A1
class 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
func f(v:B1) {
}
func f(v:B2) {
}
// 該当なし?
どの実装が採用される?クラス継承
B1
A1
func f(v:A1) {
}
func f(v:A2) {
}
// 該当なし?
どの実装が採用される?クラス継承
B1
A1
func f(v:A1) {
}
func f(v:B1) {
}
// 該当なし?
どの実装が採用される?クラス継承
B1
A1
クラスを親で扱うとき
let v:A1 = B1()
クラスを親で扱うときB1
A1
func f(v:A1) {
}
func f(v:A2) {
}
// 該当なし?
どの実装が採用される?クラスを親で扱うとき
B1
A1
func f(v:B1) {
}
func f(v:B2) {
}
// 該当なし?
どの実装が採用される?クラスを親で扱うとき
B1
A1
func f(v:A1) {
}
func f(v:B1) {
}
// 該当なし?
どの実装が採用される?クラスを親で扱うとき
B1
A1
型指定とジェネリック指定
基本的なジェネリック
func f(v:Any) {
}
型直指定で Anyおさらい S1
func f(v:Any) {
}
型直指定で Any型指定とジェネリック S1
func f<T>(v:T) {
}
func f<T:Any>(v:T) {
}
func f(v:Any) {
}
func f<T>(v:T) {
}
// 該当なし?
どの実装が採用される?型指定とジェネリック S1
func f<T==S1>(v:T) {
}
// 該当なし?
どの実装が採用される?型指定とジェネリック S1
そもそも NG
プロトコル
構造体とプロトコル
protocol P1 { }
struct S1 : P1 { }
S1
P1
プロトコルを型で扱う
func f(v:P1) {
}
// 該当なし?
どの実装が採用される?プロトコルを型で指定
S1
P1
func f(v:P1) {
}
func f(v:S1) {
}
// 該当なし?
どの実装が採用される?プロトコルを型で指定
S1
P1
func f(v:P1) {
}
func f(v:Any) {
}
// 該当なし?
どの実装が採用される?プロトコルを型で指定
S1
P1
func f(v:P2) {
}
func f(v:Any) {
}
// 該当なし?
どの実装が採用される?プロトコルを型で指定
S1
P1
プロトコルをジェネリックで扱う
func f<T:P1>(v:T) {
}
// 該当なし?
どの実装が採用される?プロトコルを型で指定
S1
P1
func f<T:P1>(v:T) {
}
func f<T>(v:T) {
}
// 該当なし?
どの実装が採用される?プロトコルを型で指定
S1
P1
func f<T:P1>(v:T) {
}
func f<T>(v:T) {
}
func f(v:S1) {
}
どの実装が採用される?プロトコルを型で指定
S1
P1
func f<T:P1>(v:T) {
}
func f<T>(v:T) {
}
func f(v:P1) {
}
どの実装が採用される?プロトコルを型で指定
S1
P1
複数のプロトコル
複数のプロトコル
protocol P1 { }
protocol P2 { }
struct S1 : P1, P2 { }
S1
P1P2
func f(v:P1) {
}
func f(v:Any) {
}
// 該当なし?
どの実装が採用される?複数のプロトコル
S1
P1P2
func f(v:P2) {
}
func f(v:Any) {
}
// 該当なし?
どの実装が採用される?複数のプロトコル
S1
P1P2
func f(v:P1) {
}
func f(v:P2) {
}
func f(v:Any) {
}
どの実装が採用される?複数のプロトコル
S1
P1P2
Ambiguous
func f(v:P1) {
}
func f(v:P2) {
}
func f(v:Any) {
}
どの実装が採用される?複数のプロトコル
S1
P1P2
• f(s1 as P1)
• f(s1 as P2)
ジェネリックで複数プロトコル
func f<T:P1>(v:T) {
}
func f<T>(v:T) {
}
// 該当なし?
どの実装が採用される?複数のプロトコル
S1
P1P2
func f<T:P2>(v:T) {
}
func f<T>(v:T) {
}
// 該当なし?
どの実装が採用される?複数のプロトコル
S1
P1P2
func f<T:P1>(v:T) {
}
func f<T:P2>(v:T) {
}
func f(v:Any) {
}
どの実装が採用される?複数のプロトコル
S1
P1P2
Ambiguous
func f<T:P1>(v:T) {
}
func f<T:P2>(v:T) {
}
func f<T>(v:T) {
}
どの実装が採用される?複数のプロトコル
• f(s1 as P1)
• f(s1 as P2)?
S1
P1P2
こうならない!
func f<T:P1>(v:T) {
}
func f<T:P2>(v:T) {
}
func f<T>(v:T) {
}
どの実装が採用される?複数のプロトコル
• f(s1 as P2)
• f(s1 as P1)
S1
P1P2
func f<T:P1>(v:T) {
}
func f<T:P2>(v:T) {
}
func f(v:Any) {
}
どの実装が採用される?複数のプロトコル
S1
P1P2
func f<T:P1>(v:T) {
}
func f<T:P2>(v:T) {
}
func f(v:Any) {
}
どの実装が採用される?複数のプロトコル
S1
P1P2
プロトコル継承
プロトコル継承
protocol P1 { }
protocol Q2 { }
protocol P2 : Q2 { }
struct S1 : P1, P2 { }
S1
P1P2
Q2
ジェネリックで継承を扱う
func f<T:P1>(v:T) {
}
func f<T>(v:T) {
}
// 該当なし?
どの実装が採用される?プロトコル継承
S1
P1P2
Q2
func f<T:P2>(v:T) {
}
func f<T>(v:T) {
}
// 該当なし?
どの実装が採用される?プロトコル継承
S1
P1P2
Q2
func f<T:P1>(v:T) {
}
func f<T:P2>(v:T) {
}
func f(v:Any) {
}
どの実装が採用される?プロトコル継承
S1
P1P2
Q2
Ambiguous
func f<T:Q2>(v:T) {
}
// 該当なし?
どの実装が採用される?プロトコル継承
S1
P1P2
Q2
func f<T:Q2>(v:T) {
}
func f<T:P2>(v:T) {
}
// 該当なし?
どの実装が採用される?プロトコル継承
S1
P1P2
Q2
func f<T:P1>(v:T) {
}
func f<T:Q2>(v:T) {
}
func f(v:Any) {
}
どの実装が採用される?プロトコル継承
S1
P1P2
Q2
Ambiguous
じゃあ
クラスではどうなるのか …!
プロトコル継承
protocol P1 protocol P2 : Q2 protocol Q2 protocol R1 : Q2
class C1 : C2, P1, P2 class C2 : P1, R1
C1
P1P2
Q2C2
P1R1
Q2
クラス継承かつプロトコル継承
間に合いませんでした !
じゃあ
複数引数ではどうなるのか …!
複数引数の場合
間に合いませんでした ! !
ひとつだけ
func f<A>(v1:A, v2:A) {
}
func f<A, B>(v1:A, v2:B) {
}
// 該当なし?
どの実装が採用される?複数条件での制約
P1
P1v1
v2
じゃあ
プロトコル制約はどうなるのか …!
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) {
}
プロトコル制約想定する型の条件を複数指定
複数条件でのプロトコル制約
間に合いませんでした ! ! ! !
ひとつだけ
プロトコルが子を内包
protocol P1
protocol P {
typealias PA typealias PB
var v1:PA {get} var v2:PB {get} }
P
PB
PA
class C1 : P1
class Base : P {
var v1:C1 var v2:C1 }
func f<T:P1, U:P1>(v1:T, v2:U) {
}
func f<T:Any, U:Any>(v1:T, v2:U) {
}
// 該当なし?
どの実装が採用される?複数条件での制約
P1
P1v1
v2
func f<T:P1, U:P1>(v1:T, v2:U) {
}
func f<T:Any, U:Any>(v1:T, v2:U) {
}
// 該当なし?
どの実装が採用される?複数条件での制約
Q1
P1
P1
v1
v2
func f<T:P
where T.PA:P1, T.PB:P1>(v:T) {
}
func f<T:P
where T.PA:Any, T.PB:Any>(v:T) {
}
どの実装が採用される?複数条件での制約 Base
P1
P1PA
PB
P
func f<T:P
where T.PA:P1, T.PB:P1>(v:T) {
}
func f<T:P
where T.PA:Any, T.PB:Any>(v:T) {
}
どの実装が採用される?複数条件での制約 Base
Q1
P1
P1
PA
PB
P
func f<T:P
where T.PA == T.PB>(v:T) {
}
func f<T:P
where T.PA:Any, T.PB:Any>(v:T) {
}
どの実装が採用される?複数条件での制約 Base
P1
P1PA
PB
P
func f<T:P where T.PA:P1, T.PB:P1,
T.PA == T.PB>(v:T) {
}
func f<T:P
where T.PA:Any, T.PB:Any>(v:T) {
}
どの実装が採用される?複数条件での制約 Base
Q1
P1
P1
PA
PB
P
じゃあ
プロトコル拡張はどうなるのか …!
extension CollectionType where Generator.Element : IntegerType {
var sum:Generator.Element { return self.reduce(0, combine: +) }
}
プロトコル拡張プロトコルに既定の実装を追加
プロトコル拡張
間に合いませんでした ! ! ! ! !
とにかく混沌としている世界
構造体
クラス
クラス継承 プロトコル
プロトコル継承
型の直指定複数プロトコル
クラス継承とプロトコル
ジェネリックでの指定
型で縛る
プロトコル拡張
型の拡張
統べるのは至難の業かもしれない
to be continued