iBooks にある “The Swift Programming Language” の勉強メモ。Objective-C と C を普段書いている自分から、ちょっと馴染みがないものを特にまとめておきます。目次は こちら。
今回は、Methods に関して。
Methods
メソッドは、クラス・構造体・Enumeration に関連付けされた関数です。Swift では、構造体も Enumeration もメソッドを持つことができます。また、Objective-C のクラスメソッドと似たものとして、タイプメソッドもあります。
1. Instance Methods
メソッドの定義の方法は分かり易いと思います。クラス等のタイプ宣言時にそのまま関数を定義したように書きます。
1 2 3 4 5 6 7 8 9 10 | class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes: Int) { count += amount * numberOfTimes } } let counter = Counter() counter.incrementBy(5, numberOfTimes: 3) // counter value is now 15 |
メソッドの注意点として、まず、メソッド名は、最初の引数に関して、前置詞を付け、その引数に対して説明的にすると読みやすいです。この例では、incrementBy
です。メソッド定義時には、1 つ目の引数の名前をメソッドの中で使用するために指定していますが、メソッドを呼ぶ際には必要ありません。しかし、2 つ目の引数では external name をタイプしなければなりません。
これは関数をこのように定義した時と同じ挙動です。Objective-C に慣れていれば、コードを書く際には、分かりやすいと思います。
1 2 3 | func incrementBy(amount: Int, #numberOfTimes: Int) { count += amount * numberOfTimes } |
また、このように 1 つ目の引数に external name を付けたり、2 つ目の external name を省略することもできます。
1 2 3 4 5 6 7 8 9 | class Counter { var count: Int = 0 func incrementBy(a amount: Int, _ numberOfTimes: Int) { count += amount * numberOfTimes } } let counter = Counter() counter.incrementBy(a: 5, 3) |
メソッドの引数の名前とプロパティの名前が同じ場合には、self
キーワードを使用します。そうでない場合にも、self
を使用できますが、必要はありません。
1 2 3 4 5 6 7 8 9 10 11 | struct Point { var x = 0.0, y = 0.0 func isToTheRightOfX(x: Double) -> Bool { return self.x > x } } let somePoint = Point(x: 4.0, y: 5.0) if somePoint.isToTheRightOfX(1.0) { println("This point is to the right of the line where x == 1.0") } // prints "This point is to the right of the line where x == 1.0 |
2. 構造体と Enumeration の Instance Methods
構造体と Enumeration の Instance Methods は、プロパティの値をデフォルトでは、変更することができません。もし、プロパティの値をクラスのように変更したい場合には、mutating
キーワードを func
キーワードの前にタイプします。これにより、構造体と Enumeration においても、プロパティを変更することができるようになります。
1 2 3 4 5 6 7 8 9 10 11 12 | struct Point { var x = 0.0, y = 0.0 mutating func moveByX(deltaX: Double, y deltaY: Double) { x += deltaX y += deltaY } } var somePoint = Point(x: 1.0, y: 1.0) somePoint.moveByX(2.0, y: 3.0) println("The point is now at (\(somePoint.x), \(somePoint.y))") // prints "The point is now at (3.0, 4.0) |
mutating メソッドは、self
に全く新しいインスタンスを代入することもできます。
1 2 3 4 5 6 | struct Point { var x = 0.0, y = 0.0 mutating func moveByX(deltaX: Double, y deltaY: Double) { self = Point(x: x + deltaX, y: y + deltaY) } } |
これは上記でみた例と全く同じ結果を生みます。Enumeration ではこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | enum TriStateSwitch { case Off, Low, High mutating func next() { switch self { case Off: self = Low case Low: self = High case High: self = Off } } } var ovenLight = TriStateSwitch.Low ovenLight.next() // ovenLight is now equal to .High ovenLight.next() // ovenLight is now equal to .Off |
3. Type Methods
タイプメソッドは、Objective-C においてクラスメソッドと同じようなものです。インスタンスに、メソッドコールをするのではなく、タイプ自体 (クラス、構造体、Enumeration) に呼び出しを行います。クラスに対して、タイプメソッドを作成するには、class
キーワードを、構造体・Enumeration に対して、タイプメソッドを作成するには、static
キーワードを func の前に置きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 | class SomeClass { class func someTypeMethod() { println("Hi") } } SomeClass.someTypeMethod() struct SomeStruct { static func someTypeMethod() { println("Hi") } } SomeStruct.someTypeMethod() |
タイプメソッドの中では、そのタイプが持っている他のタイプメソッドやタイププロパティをタイプ名なしで呼び出すことができます。
1 2 3 4 5 6 | struct LevelTracker { static var highestUnlockedLevel = 1 static func unlockLevel(level: Int) { if level > highestUnlockedLevel { highestUnlockedLevel = level } } } |
本来、LevelTracker.highestUnlockedLevel
と書きタイププロパティを参照しますが、このタイプメソッドの中では、LevelTracker
というタイプ名を省略することができます。