var x = jokes[arc4random_uniform(UInt32(jokes.count))]
このコード行でこのようなエラーが発生するのはなぜですか?
このコードを書くと
var x = jokes[Int(arc4random()%jokes.count)]
このエラーが表示されます
Int is not convertible to UInt32
var x = jokes[arc4random_uniform(UInt32(jokes.count))]
このコード行でこのようなエラーが発生するのはなぜですか?
このコードを書くと
var x = jokes[Int(arc4random()%jokes.count)]
このエラーが表示されます
Int is not convertible to UInt32
配列添字はInt
ではなくを取りますUInt32
。元に戻す必要があります:
let x = jokes[Int(arc4random_uniform(UInt32(jokes.count)))]
これが少し煩わしい場合は、それを処理する関数を作成することをお勧めします。
func randomValueLessThan(x: Int) -> Int {
return Int(arc4random_uniform(UInt32(x)))
}
または、Array を拡張して支援することもできます。
extension Array {
func uniformSelection() -> T {
return self[Int(arc4random_uniform(UInt32(self.count)))]
}
}
Int(arc4random()%jokes.count)
編集:間違って修正したくなるかもしれないので、ケースをもう少し深く掘り下げる価値があります。これは、Swift がそのように動作する理由を示しています。
あなたのバージョンから始めましょう
let n = Int(arc4random() % jokes.count)
// => Could not find an overload for 'init' that accepts the supplied arguments
それは少し混乱します。問題を単純化して見てみましょう
let n = arc4random() % jokes.count
// => Cannot invoke '%' with an argument list of type '(UInt32, Int)'
それはより明確になるはずです。arc4random
を返し、UInt32
をjokes.count()
返しますInt
。異なるタイプをモジュラスにすることはできません。それらを同じ場所に移動する必要があります。ええと、私たちは欲しいですInt
よね?簡単に思えます:
let n = Int(arc4random()) % jokes.count // WARNING!!!! Never ever do this!!!!
なぜ Apple はそれほど衒学的であり、私たちに手作業でそれを強制するのでしょうか? コンパイラはそれを自動的にキャストできませんでしたか? 上記のコードは 64 ビット プロセッサでは問題なく動作し、32 ビット プロセッサでは約半分の時間でクラッシュします。これは、 を呼び出すことで、値が常に範囲内にあることInt()
を約束しているためです。32 ビット プロセッサでは、これが 32 ビットの符号付き範囲です。ただし、32 ビットの符号なし範囲全体の値を返します。これには、. ブラム!(または、境界チェックをオフにすると、C で行うように数値が破棄されるだけであり、これは良くありません。)Int
arc4random
Int
Swift が整数変換にうるさいのはそのためです。変換するときは、安全な変換であることを完全に確認する必要があります。コンパイルするまで、それらを振りかけるだけではいけません。
とはいえ、もちろん modo を on に使用するべきではありませんarc4random
。しかし、それは別の質問です。
randomValueLessThan()
もう 1 つ補足として、数値のキャストにより、多くの無効な状況が生じる可能性があることに気付くでしょう。0 未満の数値を渡すと、クラッシュします (驚くべきことではありません)。より大きい数値を渡すと、UInt32.Max
クラッシュも発生します。これは少し驚くべきことですが、ほとんどのコードではほとんどありません。これのポイントは、これらのキャストを追加することによってrandomValueLessThan
、部分的な関数を作成したことです。入力範囲全体で定義されているわけではありません (「ドメイン」です)。「実生活」のプログラミングでは、私たちは常にそれを行っています。しかし、Swift は、型の安全性を破っているときにそれをより明確にすることで、私たちが噛まれるのをさらに少なくしようとしています。
uniformSelection
同様の問題があります。UInt32.Max
要素数が少ない配列に対してのみ定義されます。これらは無意味なまれなケースのように感じることがありますが、突然そうではなくなり、プログラムがクラッシュするまではそうです。(Array.subscript
配列の範囲外の値に対しては定義されていないため、部分関数でもあります。私は実際にAppleに、それArray.subscript
を説明するオプションを返すよう提案しました。彼らはおそらく私を無視するのが賢明でした.)