2015-02-24 258 views
1

我建立這個infix operator ^^作爲替代使用pow功能:Swift的POW()函數將不接受兼作參數

infix operator ^^ { associativity left precedence 155 } 
func ^^ <T: IntegerLiteralConvertible>(left: T, right: T) -> T { 
    return pow(left as Double, right as Double) 
} 

我用IntegerLiteralConvertible協議作爲用於泛型leftright類型約束,因爲從我的理解this diagramm表明,它基本上包含了所有的數字類型。

爲了使用pow功能我不得不垂頭喪氣leftrightDouble雖然,這我沒有使用as操作。這不是最安全的方法,但除此之外。

在實現功能this way迅速告訴我:

<stdin>:4:12: error: cannot invoke 'pow' with an argument list of type '(Double, Double)' 
return pow(left as Double, right as Double) 
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

現在據我知道pow需要兩個Double S作爲參數,那麼,爲什麼抱怨嗎?

回答

2

why is it complaining about this?

因爲pow返回Double。並且DoubleT不相同。該錯誤消息是誤導性的,但它的意思是「無法找到pow接受(Double, Double)並返回T型」


我認爲你是在斯威夫特誤解「中投」。在Swift中as不會轉換數字類型。

let intVal:Int = 12 
let doubleVal:Double = intVal as Double 
//       ^[!] error: 'Int' is not convertible to 'Double' 

而且如果操作數的類型不是在編譯時預測的,無效的鑄造導致運行時錯誤:

func foo<T: IntegerLiteralConvertible>(x: T) { 
    x as Double // <-- Execution was interrupted 
} 
foo(12 as Int) 

相反,我們必須明確地「轉換」他們。查看文檔:Numeric Type Conversion

let intVal:Int = 12 
let doubleVal:Double = Double(intVal) 

這僅是因爲Doubleinit(_ v: Int)初始化。下面的代碼無法編譯:

func foo<T: IntegerLiteralConvertible>(x: T) { 
    Double(x) 
// ^~~~~~~~~ [!] error: cannot invoke 'init' with an argument of type 'T' 
} 

因爲Double沒有init<T:IntegerLiteralConvertible>(_ val:T)初始化。

所以,如果你想使用pow(),你必須轉換到TDouble參數,並將其轉換DoubleT返回值。對此沒有簡單的解決方案。

3

感謝@馬丁R.這是唯一的question我已發佈迄今S.O.

import Cocoa 

協議

protocol Fraction { init(_ value:Double) ; var asDouble : Double { get } } 
protocol Text  { init(_ value:String) ; var asString : String { get } } 

擴展

extension String : Text  { var asString : String { return self } } 

extension Double : Fraction { var asDouble : Double { return self   } } 
extension Float : Fraction { var asDouble : Double { return Double(self) } } 
extension CGFloat : Fraction { var asDouble : Double { return Double(self) } } 

管道符^^

infix operator ^^ { associativity left precedence 170 } 
func ^^<T:IntegerType, U:IntegerType> (var base:T, var power:U) -> T { 
    if power < 0 { return 0 } 
    var result: T = 1 
    if power > 0 { 
     if power % 2 == 1 { result *= base } 
     power /= 2 
    } 
    while power > 0 { 
     base *= base 
     if power % 2 == 1 { result *= base } 
     power /= 2 
    } 
    return result 
} 
func ^^<T:Fraction, U:Fraction> (base: T, power: U) -> T { 
    return T(pow(base.asDouble, power.asDouble)) 
} 
func ^^<T:Text, U:IntegerType> (base:T, var power:U) -> T { 
    if power <= 0 { return "" as T } 
    if power == 1 { return base as T } 
    return power > 1 ? {var result = ""; for x in 1...power { result+=base.asString };return result as T}() : "" as T 
} 
func ^^<T:Text, U:Text> (base:T, var power:U) -> T { 
    return "" as T 
} 

測試

println(1 ^^ -1)    // "0"  Int 
println(1 ^^ 0)    // "1"  Int 
println(1 ^^ 1)    // "1"  Int 
println(1 ^^ 2)    // "1"  Int 

println(2 ^^ -1)    // "0"   Int 
println(2 ^^ 0)    // "1"   Int 
println(2 ^^ 1)    // "2"   Int 
println(2 ^^ 2)    // "4"   Int 
println(2 ^^ 8)    // "256"   Int 
println(2 ^^ 16)    // "65536"  Int 
println(2 ^^ 32)    // "4294967296" Int 

println(2 ^^ 62)    // "4611686018427387904" 

println(UInt(2) ^^ 8)   // "256"  UInt 
println(UInt64(2) ^^ 8)  // "256"  UInt64 
+1

多數民衆贊成在類型安全再次感謝@馬丁R – 2015-02-24 19:10:17

+0

http://stackoverflow.com/questions/26794282/how-do-i-make-my-operator-work-with-double-and-int – 2015-02-24 19:15:02

+0

我上來了什麼-投票? – 2015-02-24 19:36:28