まあよくありますよね皆さんも多分、例えば「0 から 256 までの乱数を作りたい」とかいう要望。
一応公式で教えてるやり方ですと arc4random_uniform(_: UInt32)
と言う方法を使えとのことですが毎回毎回これやるのだるいじゃん?だってこいつだけ基本欲しいの Int
型だけどこいつだけ引数も戻り値も UInt32
じゃん?毎回毎回こいつのために型変換するの面倒いしそれにこれは 0 から uniform
される数字までの値しか生成されないから逆に言うと 0 からでないランダム数が欲しいときだとさらに面倒い記述が求められるから超絶にだるい。というわけで extension
で楽に作る方法を実装してみます:
//普通に distanceTo を使うからこの方法やめる
//extension Range where Element: IntegerType {
extension Range {
//普通に distanceTo を使うからこの方法やめる
//var distance: Element {
// return self.endIndex - self.startIndex
//}
var distance: Element.Distance {
return self.startIndex.distanceTo(self.endIndex)
}
}
extension Int {
static var random = {(range: Range<Int>) -> Int in
let distance = {(distance: Int) -> UInt32 in
guard distance <= Int(UInt32.max) else {
return UInt32.max
}
return UInt32(distance)
}(range.distance)
let randomUInt = arc4random_uniform(distance)
return Int(randomUInt) + range.startIndex
}
}
let a = Int.random(-127 ..< 128)
let b = Int.random(-127 ..< 128)
説明は…要りますかね?まあ分からないことあったらコメントで教えてください
とりあえず一つだけ多分ちょっとわからない人が多そうなのは extension Range where Element: IntergerType
のところかな?ここは要するに Range
の要素の型を IntegerType
に限定するジェネリックスエクステンションです。本当なら別に限定する必要はないはずだったんだけどまさか実は Swift では -
って演算子はジェネリックス対応ではなかったとは…
そして使い方も上記のコードで分かるとおり Int.random(範囲)
で作れば OK です。上記のサンプルコードだと a
と b
の -127 ..< 128
までの範囲の乱数を二つ作ってることになります。Range
型なので非常に簡単に範囲指定ができちゃうからソースコードも結構読みやすいではないかと。
ただ当然ですが一つ気をつけないといけないのは Range<Int>
の distance
プロパティーは endIndex - startIndex
で作ってるので、例えば Int.min ..< Int.max
の Range
の distance
を求めるとオーバーフローでクラッシュします。