2015-04-01 94 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)) 
相關問題