Edited at

SwiftでRubyのInteger#timesを実装してみた

More than 5 years have passed since last update.

Swiftでは数値リテラルがオブジェクトとして扱えるので、Rubyっぽく数値にいろんなメソッドを定義することができる。そこで、簡単な#timesをSwiftで実装してみた。

extension Int {

func times(repeat: (Int) -> ()) {
for var index = 0; index < self; index++ {
repeat(index)
}
}
}

5.times { n in println("naoty \(n)") }
//=> naoty 0
//=> naoty 1
//=> naoty 2
//=> naoty 3
//=> naoty 4

きっと誰かがActiveSupportのような1.minutesみたいなExtensionを書くのでしょう(予言)。


せっかくなので、Swiftのクロージャの文法について軽く補足してみる。

まず、#timesメソッドは(Int) -> ()型の関数を引数にとる。このとき、以下のように書くことができる。

5.times({ (n: Int) -> () in

println("naoty \(n)")
})

in以下が十分に短い場合は一行に続けることもできる。

5.times({ (n: Int) -> () in println("naoty \(n)") })

ところで、#timesの定義で引数の関数の型は(Int) -> ()であると明示的に宣言しているので、型推論を利用できる。実際に引数に関数を渡すとき、その関数の型をわざわざ宣言する必要がない。そのため、以下のように書き直せる。

5.times({ n in println("naoty \(n)") })

もし、あるクロージャを関数の最後の引数として渡す場合、クロージャを()の外に追い出すことができる。なので、さらに以下のように書き直せる。

5.times() { n in println("naoty \(n)") }



追記

さらに、クロージャが関数の唯一の引数である場合は()を省略できるので、以下のように書き直せる。

5.times { n in println("naoty \(n)") }

ここまで来るとほとんどRubyと同じように書ける。