Swiftを調べていて一番感動したのがこのFeature。既存のクラスにたいていExtensionという仕組みを使うと自分なりに拡張することができる。
struct SampleStruct {
var v: Int = 0
init(v: Int) {
self.v = v
}
}
extension SampleStruct {
mutating func mulFactor(factor: Int) {
v *= factor
}
}
既存のstruct
SampleStructとその拡張を用意する。
そうするとmulFactorはクライアントコードから呼び出すことができる。
var s: SampleStruct = SampleStruct(v: 5)
s.mulFactor(10)
println(s.v) // -> 50
今回はSampleStruct本体を自分で定義したから別に面白くないけれど、これが他人の書いたクラスだったらどうだろう。例えばInt
extension Int {
func repetition(task: () -> ()) {
for i in 0..self {
task()
}
}
}
こんな拡張を書いてあげるとこれはInt
のメソッドとして使うことができる。
100.repetition({ println("Hello, World")})
// Hello, World
// Hello, World
// Hello, World
// Hello, World
// ... 100個続く
Swiftでは評価部分だけのClosureは丸括弧を省いていいので以下のようにも書ける。
100.repetition{
println("Hello, World")
}
制御構造のようにも見える。ExtensionとClosureを使えばScalaのように自由にDSLも書ける!
ちなみにひとつハマったのは
Class
に対してはmutating
宣言されたExtensionを書くことができない。先ほどの例だとこんか感じ。
class SampleClass { // <-- ここがクラス
var v: Int = 0
init(v: Int) {
self.v = v
}
}
extension SampleClass {
mutating func mulFactor(factor: Int) { // <-- ここでコンパイラに怒られる
v *= factor
}
}
'mutating'
isn't valid on methods in classes...
とか言われるのでダメっぽい。