2016-11-02 21 views
0

私は乱数を生成するには、この拡張メソッドを使用していた。Swift3ランダム拡張メソッド

func Rand(_ range: Range<UInt32>) -> Int { 
     return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound + 1)) 
    } 

は、私はB/Cそれはナンセンスではなかったそれが好き、あなたはこのようにそれを呼ばれる:

let test = Rand(1...5) //generates a random number between 1 and 5 

は、だから私は

Swift3になりましエラーを受信して​​います..私は正直に物事がスウィフトで非常に複雑である必要は理由を知りませんが、私は脱線します
No '...' candidates produce the expected contextual result type 'Range<UInt32>' 

これが何を意味するのか、またはじめてどのように私の素晴らしいランド機能が再び働くのか分かりますか?私はxと思う... yはもはや範囲またはxを作成しない... yは明示的にUInt32として定義する必要がありますか?物事をもっと簡単にするためのアドバイスはありますか?

ありがとう、ありがとうございます!

答えて

3

  • "x" ..< "y"Range<T>
  • "x" ... "y"ClosedRange<T>
  • 1 ..< 5CountableRange<T>
  • 1 ... 5
  • CountableClosedRange<T>

..<...がオーバーロードされている演算子ように要素がstridable(ランダム・アクセス・イテレータである場合、例えば数字とポインタ)、Countable Rangeが返されます。しかし、これらの演算子は、型チェッカーを満たすためにプレーンレンジを返すことができます。

RangeとClosedRangeは異なる構造であるため、相互に暗黙的に変換することはできません。

あなたはランドがClosedRangeを受け入れるだけでなく、レンジしたい場合、あなたはそれをオーバーロードする必要があります。

// accepts Rand(0 ..< 5) 
func Rand(_ range: Range<UInt32>) -> Int { 
    return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound)) 
} 

// accepts Rand(1 ... 5) 
func Rand(_ range: ClosedRange<UInt32>) -> Int { 
    return Int(range.lowerBound + arc4random_uniform(range.upperBound + 1 - range.lowerBound)) 
} 
0

あなたはそれがあなたの主なユースケースであればIntを使用するRand()を書き換えることができます:

func Rand(_ range: Range<Int>) -> Int { 
    let distance = UInt32(range.upperBound - range.lowerBound) 
    return range.lowerBound + Int(arc4random_uniform(distance + 1)) 
} 

それともkennytmが指摘するように、使用Rand(1..<6) 4つのレンジ構造があるスウィフト3では

4

素敵な溶液が(メーリングリストSWIFTユーザーでHow to be DRY on ranges and closed ranges?に基づく)Generic Range Algorithms に提示されています。

それはCountableRangeCountableClosedRange 両方がコレクション、と実際にRandomAccessCollectionであるという事実を使用しています。

だから両方受け付ける単一(ジェネリック)関数を定義し、オープンで 整数を閉鎖することができる範囲:

func rand<C: RandomAccessCollection>(_ coll: C) -> C.Iterator.Element { 
    precondition(coll.count > 0, "Cannot select random element from empty collection") 
    let offset = arc4random_uniform(numericCast(coll.count)) 
    let idx = coll.index(coll.startIndex, offsetBy: numericCast(offset)) 
    return coll[idx] 
} 

rand(1...5) // random number between 1 and 5 
rand(2..<10) // random number between 2 and 9 

も:

:プロトコル拡張法としてあるいは

rand(["a", "b", "c", "d"]) // random element from the array 

extension RandomAccessCollection { 

    func rand() -> Iterator.Element { 
     precondition(count > 0, "Cannot select random element from empty collection") 
     let offset = arc4random_uniform(numericCast(count)) 
     let idx = index(startIndex, offsetBy: numericCast(offset)) 
     return self[idx] 
    } 
} 

(1...5).rand() 
(2..<10).rand() 
["a", "b", "c", "d"].rand() 
+0

'rand'関数がcollectioだけを受け入れるように制限する方法はありますか? 'Int'のn? – rmaddy

+1

@rmaddy: 'func rand (_ coll:C) - > C.Iterator.Elementここで、C.Iterator.Element == Int'はフリー関数、または' extension RandomAccessCollectionはIterator.Element ==拡張メソッドのためのInt。 –