IntegerType:无法使用 'T' 类型的参数调用 'init'
IntegerType: Cannot invoke 'init' with an argument of type 'T'
我有这个函数 returns 范围内的整数:
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
作为参数
为什么这行不通?
麻烦的是UInt32
没有init
可以任意取IntegerType
。当然,它需要标准库中的每一个定义,但是如果有人实现了一个符合 IntegerType
的 UInt128
怎么办?即使您在 let u = UInt32(n.toIntMax())
中进行了替换,您在尝试将 r
添加到 min
时也会被卡住,因为再一次,没有 +
的实现可以添加a UInt32
到任意 IntegerType
。考虑到溢出的可能性,这是有道理的——你知道 arc4random_uniform(u)
永远不会 return UInt32
大于 Int8.max
,但是 Swift 不能。您需要比 IntegerType
提供的更丰富的功能来编写此函数的真正通用版本,该版本具有正确的前置条件和 post 条件。
您可以创建一个新的整数协议来接受任何 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 个函数:一个用于 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
。
现在,这些函数具有完全相同的实现代码:)但我认为您不能将它们统一为一个函数。
我有这个函数 returns 范围内的整数:
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
作为参数
为什么这行不通?
麻烦的是UInt32
没有init
可以任意取IntegerType
。当然,它需要标准库中的每一个定义,但是如果有人实现了一个符合 IntegerType
的 UInt128
怎么办?即使您在 let u = UInt32(n.toIntMax())
中进行了替换,您在尝试将 r
添加到 min
时也会被卡住,因为再一次,没有 +
的实现可以添加a UInt32
到任意 IntegerType
。考虑到溢出的可能性,这是有道理的——你知道 arc4random_uniform(u)
永远不会 return UInt32
大于 Int8.max
,但是 Swift 不能。您需要比 IntegerType
提供的更丰富的功能来编写此函数的真正通用版本,该版本具有正确的前置条件和 post 条件。
您可以创建一个新的整数协议来接受任何 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 个函数:一个用于 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
。
现在,这些函数具有完全相同的实现代码:)但我认为您不能将它们统一为一个函数。