【问题标题】:Swift's pow() function won't accept Doubles as argumentsSwift 的 pow() 函数不接受双精度数作为参数
【发布时间】:2015-04-26 11:43:16
【问题描述】:

我创建了这个infix operator ^^ 来替代使用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 函数,我必须将leftright 向下转换为Double,我使用as 操作符来做到这一点。这不是最安全的方法,但这不是重点。

在实现功能时this way swift告诉我:

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

现在据我所知pow 需要两个Doubles 作为参数,那它为什么抱怨这个呢?

【问题讨论】:

  • 2019 年您好! .现在,我在 Foundation for pow 中看到了这个声明:public func pow(_ x: Decimal, _ y: Int) -&gt; Decimal

标签: swift generics pow downcast type-constraints


【解决方案1】:

为什么抱怨这个?

因为 pow 返回 Double。并且DoubleT 不同。错误信息具有误导性,但它的意思是“找不到接受(Double, Double) 并返回T 类型的pow


我认为您误解了 Swift 中的“演员”。在 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)

这仅是因为 Double 具有 init(_ v: Int) 初始化程序。以下代码无法编译:

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

因为Double 没有init&lt;T:IntegerLiteralConvertible&gt;(_ val:T) 初始化器。

因此,如果要使用pow(),则必须将T 转换为Double 作为参数,并将Double 转换为T 作为返回值。对此没有简单的解决方案。

【讨论】:

    【解决方案2】:

    感谢@Martin R。这来自我迄今为止在 S.O. 发布的唯一 question

    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
    

    【讨论】:

    • 您不是在寻找紧凑/优雅的解决方案。您正在寻找一种简单的解决方案并避免实施这种情况下所需的协议。如果您查看我的第二个解决方案,您可以测试 base 是否属于类型并避免使用协议。您在那里有足够的信息来选择一条使其类型安全的路径,或者只是使用您更优雅的方式将您的操作员限制在某些类型,而不是做实际需要做的事情。需要。
    • 没有。在过去,我刚刚接触过我以前不知道的 swift 部分,这简化了整个问题。这就是我在这里等待的。
    • 很抱歉告诉你,你会白等。看看我的问题是什么时候发布的。
    猜你喜欢
    • 1970-01-01
    • 2020-03-31
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多