我有这个函数在bounds中返回一个整数:
func randomNumber<T: IntegerType>(min: T, max: T) -> T {
let n = max - min + 1
let u = UInt32(n) // Error: Cannot invoke 'init' with an argument of type 'T'
let r = arc4random_uniform(u)
return r + min
}
我不明白为什么这不起作用,因为UInt32
最顶端的协议是UnsignedIntegerType
,符合IntegerType
。
我必须将n
变为UInt32
因为arc4random_uniform()
将UInt32
作为参数
为什么不这样做?
答案 0 :(得分:3)
问题在于UInt32
没有init
采用任意IntegerType
。当然,它需要标准库中的每个定义的一个,但是如果某人实现了符合UInt128
的{{1}}会怎么样?即使您在IntegerType
中替换,在尝试将let u = UInt32(n.toIntMax())
添加到r
时也会遇到问题,因为再次没有min
的实现会添加任意+
UInt32
。考虑到溢出的可能性,这是有道理的 - 你知道IntegerType
永远不会返回arc4random_uniform(u)
大于UInt32
,但Swift不能。您需要比Int8.max
提供的更丰富的功能来编写具有正确的前置条件和后置条件的此函数的真正通用版本。
答案 1 :(得分:1)
您可以创建一个新的整数协议来接受任何UInt,并将UInt64限制为UInt32.max以符合arc4random_uniform限制,如下所示:
protocol Integer {
init(_ value:Int)
var integerValue: Int { get }
}
extension Int : Integer { var integerValue : Int { return self } }
extension UInt64 : Integer { var integerValue : Int { return Int(self) } }
extension UInt32 : Integer { var integerValue : Int { return Int(self) } }
extension UInt16 : Integer { var integerValue : Int { return Int(self) } }
extension UInt8 : Integer { var integerValue : Int { return Int(self) } }
extension UInt : Integer { var integerValue : Int { return Int(self) } }
func randomNumber(min: Integer, max: Integer) -> Int {
if min.integerValue >= max.integerValue { return 0 }
if max.integerValue-min.integerValue+1 > UInt32.max { return 0 }
return (min.integerValue + arc4random_uniform(UInt32(max.integerValue - min.integerValue + 1))).integerValue
}
randomNumber(UInt(10), UInt64(13))
randomNumber(UInt8(10), UInt32(13))
randomNumber(UInt16(10), UInt16(13))
randomNumber(UInt32(10), UInt8(13))
randomNumber(UInt64(10), UInt(13))
答案 2 :(得分:0)
您需要制作至少2个功能:一个用于SignedIntegerType
,一个用于UnsignedIntegerType
。
SignedIntegerType
具有类型强制函数:toIntMax()
和init(_: IntMax)
protocol _SignedIntegerType : _IntegerType, SignedNumberType {
/// Represent this number using Swift's widest native signed integer
/// type.
func toIntMax() -> IntMax
/// Convert from Swift's widest signed integer type, trapping on
/// overflow.
init(_: IntMax)
}
UnsignedIntegerType
也有类型强制函数:toUIntMax()
和init(_: UIntMax)
protocol _UnsignedIntegerType : _IntegerType {
/// Represent this number using Swift's widest native unsigned
/// integer type.
func toUIntMax() -> UIntMax
/// Convert from Swift's widest unsigned integer type, trapping on
/// overflow.
init(_: UIntMax)
}
使用这些功能,您可以:
func randomNumber<T: UnsignedIntegerType>(min: T, max: T) -> T {
let n = max - min + 1
let u = UInt32(n.toUIntMax())
let r = arc4random_uniform(u)
return T(r.toUIntMax()) + min
}
func randomNumber<T: SignedIntegerType>(min: T, max: T) -> T {
let n = max - min + 1
let u = UInt32(n.toIntMax())
let r = arc4random_uniform(u)
return T(r.toIntMax()) + min
}
但是,我们已经有了方便的numericCast
内置函数:
func numericCast<T : _UnsignedIntegerType, U : _SignedIntegerType>(x: T) -> U
func numericCast<T : _SignedIntegerType, U : _UnsignedIntegerType>(x: T) -> U
func numericCast<T : _UnsignedIntegerType, U : _UnsignedIntegerType>(x: T) -> U
func numericCast<T : _SignedIntegerType, U : _SignedIntegerType>(x: T) -> U
numericCast
可以简化您的实施:
func randomNumber<T: UnsignedIntegerType>(min: T, max: T) -> T {
return min + numericCast(arc4random_uniform(numericCast(max - min + 1)))
}
func randomNumber<T: SignedIntegerType>(min: T, max: T) -> T {
return min + numericCast(arc4random_uniform(numericCast(max - min + 1)))
}
内部numericCast
将T
转换为UInt32
,外部UInt32
将T
转换为{{1}}。
现在,这些函数具有完全相同的实现代码:)但我认为你无法将它们统一为一个函数。