0
var x = jokes[arc4random_uniform(UInt32(jokes.count))]

このコード行でこのようなエラーが発生するのはなぜですか?

このコードを書くと

var x = jokes[Int(arc4random()%jokes.count)]

このエラーが表示されます

Int is not convertible to UInt32
4

1 に答える 1

3

配列添字は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を返し、UInt32jokes.count()返しますInt。異なるタイプをモジュラスにすることはできません。それらを同じ場所に移動する必要があります。ええと、私たちは欲しいですIntよね?簡単に思えます:

let n = Int(arc4random()) % jokes.count   // WARNING!!!! Never ever do this!!!!

なぜ Apple はそれほど衒学的であり、私たちに手作業でそれを強制するのでしょうか? コンパイラはそれを自動的にキャストできませんでしたか? 上記のコードは 64 ビット プロセッサでは問題なく動作し、32 ビット プロセッサでは約半分の時間でクラッシュします。これは、 を呼び出すことで、値が常に範囲内にあることInt()を約束しているためです。32 ビット プロセッサでは、これが 32 ビットの符号付き範囲です。ただし、32 ビットの符号なし範囲全体の値を返します。これには、. ブラム!(または、境界チェックをオフにすると、C で行うように数値が破棄されるだけであり、これは良くありません。)Intarc4randomInt

Swift が整数変換にうるさいのはそのためです。変換するときは、安全な変換であることを完全に確認する必要があります。コンパイルするまで、それらを振りかけるだけではいけません。

とはいえ、もちろん modo を on に使用するべきではありませんarc4randomしかし、それは別の質問です。

randomValueLessThan()もう 1 つ補足として、数値のキャストにより、多くの無効な状況が生じる可能性があることに気付くでしょう。0 未満の数値を渡すと、クラッシュします (驚くべきことではありません)。より大きい数値を渡すと、UInt32.Maxクラッシュも発生します。これは少し驚くべきことですが、ほとんどのコードではほとんどありません。これのポイントは、これらのキャストを追加することによってrandomValueLessThan部分的な関数を作成したことです。入力範囲全体で定義されているわけではありません (「ドメイン」です)。「実生活」のプログラミングでは、私たちは常にそれを行っています。しかし、Swift は、型の安全性を破っているときにそれをより明確にすることで、私たちが噛まれるのをさらに少なくしようとしています。

uniformSelection同様の問題があります。UInt32.Max要素数が少ない配列に対してのみ定義されます。これらは無意味なまれなケースのように感じることがありますが、突然そうではなくなり、プログラムがクラッシュするまではそうです。(Array.subscript配列の範囲外の値に対しては定義されていないため、部分関数でもあります。私は実際にAppleに、それArray.subscriptを説明するオプションを返すよう提案しました。彼らはおそらく私を無視するのが賢明でした.)

于 2015-01-09T14:36:20.993 に答える