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)))
}
或者您可以扩展数组来帮助:
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
返回aUInt32
,jokes.count()
返回aInt
。你不能把不同的类型模化。你得把他们带到同一个地方。好吧,我们想要一个Int
,对吧?似乎很容易:let n = Int(arc4random()) % jokes.count // WARNING!!!! Never ever do this!!!!
为什么苹果如此迂腐,强迫我们手工操作?编译器不能自动转换它吗?好吧,上面的代码在64位处理器上运行良好,在32位处理器上大约有一半时间崩溃。这是因为通过调用
Int()
,您可以保证值始终在Int
范围内。在32位处理器上,这是32位有符号范围。但是arc4random
返回整个32位无符号范围内的值,其中包括许多不适合Int
的数字。责怪!(或者如果您关闭了边界检查,那么它只会像在C中那样破坏您的数字,这是再好不过的了。)这就是为什么Swift对整数转换很挑剔。当你转换的时候,你必须绝对确定这是一个安全的转换。在它编译之前,你不应该把它们到处乱扔。
也就是说,你当然不应该在
arc4random
上使用模数。But that's a different question.另一方面,您会注意到
randomValueLessThan()
中的数值强制转换会创建许多可能的无效情况。如果你通过一个小于0的数字,你将崩溃(不过,这并不奇怪)。如果传递的数字大于UInt32.Max
,则也会崩溃,这稍微令人惊讶,但在大多数代码中是不太可能的。这一点是,通过添加这些类型转换,我们使randomValueLessThan
成为一个部分函数。它不是在所有输入范围内定义的(它是“域”)。在“现实生活”编程中,我们总是这样做,我们只是希望它永远不会咬到我们。但斯威夫特试图帮助我们被咬的更少,使它更明显时,你打破类型安全。uniformSelection
也有类似的问题。它只为元素少于UInt32.Max
的数组定义。这些有时感觉像是毫无意义的角落案例,它们是,直到突然它们不是,你的程序崩溃。(Array.subscript
也是一个部分函数,因为它未定义数组范围之外的值。我实际上建议苹果返回一个选项来解释这个问题。他们不理我可能是明智的。)关于ios - 找不到接受提供的参数的重载“init”,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27862475/