2015-04-01 66 views
3

我有这个函数返回范围内的整数:我不明白为什么这是行不通的,因为UInt32最顶端的协议是IntegerType:无法调用“初始化”与类型的参数“T”

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 
} 

UnsignedIntegerType,符合IntegerType

我必须做出nUInt32因为arc4random_uniform()需要一个UInt32作为参数

为什么惯于这项工作?

回答

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转换TUInt32,外一个转换UInt32T

现在,这些函数具有完全相同的实现代码:)但我认为你不能将它们统一成一个函数。

3

问题是UInt32没有init需要任意IntegerType。当然,它需要标准库中的每一个定义的标准库,但如果某人实施符合IntegerTypeUInt128,该怎么办?即使您在let u = UInt32(n.toIntMax())中进行了替换,当您尝试将r添加到min时,您仍然会被卡住,因为再次没有执行+会将UInt32添加到任意IntegerType。考虑到溢出的可能性,这是有道理的 - 你知道arc4random_uniform(u)永远不会返回,比如说Int8.max,但是Swift不能。您需要比IntegerType提供的更丰富的功能来编写具有正确前置和后置条件的此功能的真正通用版本。

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)) 
相关问题