A Swift Tourその5– Protocols and Extensions、Generics
Swiftの言語仕様である「The Swift Programming Language」に沿って、学んでいきます。
Protocols and Extensions / プロトコルと拡張
プロトコルの宣言には protocol を使います。
他の言語でいうところのインターフェースです。
Objective−Cの言葉を引き継いでいますね。
protocol ExampleProtocol { var simpleDescription: String { get } mutating func adjust() }
クラスも列挙型も構造体もプロトコルを継承することができます。
class SimpleClass: ExampleProtocol { var simpleDescription: String = "A very simple class." var anotherProperty: Int = 69105 func adjust() { simpleDescription += " Now 100% adjusted." } } var a = SimpleClass() a.adjust() let aDescription = a.simpleDescription // "A very simple class. Now 100% adjusted." struct SimpleStructure: ExampleProtocol { var simpleDescription: String = "A simple structure" mutating func adjust() { simpleDescription += " (adjusted)" } } var b = SimpleStructure() b.adjust() let bDescription = b.simpleDescription // "A simple structure (adjusted)"
SimpleStructure の定義の中にもありますが、構造体に変更を加えるときは mutating というキーワードをつけます。クラスには必要ありません。
ある型に機能を拡張するときは、extension を使います。
ライブラリとフレームワークにあるクラスの機能も変更できます。
extension Int: ExampleProtocol { var simpleDescription: String { return "The number \(self)" } mutating func adjust() { self += 42 } } 7.simpleDescription // "The number 7"
プロトコルは型名と使うことができます。例えば、型は違うが同じプロトコルであるオブジェクトのコレクションをつくるとき、プロトコル名を指定してコレクションをつくります。
ただし、プロトコルの外部に定義されたメソッドは利用できません。
let protocolValue: ExampleProtocol = a protocolValue.simpleDescription protocolValue.anotherProperty // プロトコルにないメソッドなのでコンパイルエラーになる
protocolValue は実行時は SimpleClass型ですが、コンパイラは ExampleProtocol型として扱います。
Generics / ジェネリクス
ジェネリクスな関数や型をつくるときは、かぎかっこ(<>)内に型名を書きます。
func repeat<ItemType>(item: ItemType, times: Int) -> [ItemType] { var result = [ItemType]() for i in 0..<times { result.append(item) } return result } repeat("knock", 4) // ["knock", "knock", "knock", "knock"]
クラス、列挙型、構造体も関数やメソッドと同じようにジェネリクスを使用できます。
// Reimplement the Swift standard library's optional type enum OptionalValue<T> { case None case Some(T) } var possibleInteger: OptionalValue<Int> = .None possibleInteger = .Some(100)
プロトコルを実装する、2つの型が同じである、ある特定のスーパークスらを持つ必要がある、等の条件がある場合には、型名の後に where を使って条件を指定します。
func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> Bool { for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { return true } } } return false } anyCommonElements([1, 2, 3], [3])
単純な条件の場合は、where を省略して、コロンの後にプロトコル名やクラス名を書くこともできます。
例えば、<T: Equatable> は <T where T: Equatable> と同じことです。
「The Swift Programming Language」で使用されているコードはplaygroundとしてダウンロードして、XCodeで開くことができます。
https://developer.apple.com/library/ios/swift_tour