Функция Swift pow () не принимает двойников в качестве аргументов
Я создал этот 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
в качестве ограничения типа для генераторов left
и right
, потому что из моего понимания эта диаграмма показывает, что она в основном включает все типы чисел.
Чтобы использовать функцию pow
, я должен понизить left
и right
до Double
, что я и сделал, используя оператор as
. Это не самый безопасный подход, но это к тому же точка.
При реализации функции таким образом 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
принимает два Double
s в качестве параметров, так почему же он жалуется на это?
2 ответа:
Почему он жалуется на это?Потому что pow возвращается
Double
. ИDouble
не тождественноT
. Сообщение об ошибке вводит в заблуждение, но оно означает "не удается найтиpow
, который принимает(Double, Double)
и возвращаетT
тип"
Я думаю, что вы неправильно поняли "бросок" в 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)
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<T:IntegerLiteralConvertible>(_ val:T)
.pow()
, вы должны преобразоватьT
вDouble
для Аргументов и преобразоватьDouble
вT
для возвращаемого значения. И для этого нет простого решения.
Спасибо @ Martin R. это исходит из единственного вопроса, который я опубликовал до сих пор в 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