使用`pow`

时间:2015-07-29 14:04:59

标签: swift protocols

我试图赋予任何数字提升到任意权力的能力(具体来说,2)。这似乎是使用协议扩展而不是向FloatDoubleInt等添加扩展程序的绝佳机会。

protocol Raisable {
    func raise(exponent : Self) -> Self
}

extension Raisable where Self : SignedNumberType {
    func raise(exponent : Double) -> Self {
        return Self(pow(Double(self), exponent))
    }
}

protocol Squarable : Raisable {
    func squared() -> Self
}

extension Squarable {
    func squared() -> Self {
        return self.raise(2)
    }
}

编译器显示"找不到类型' Double'的初始值设定项。接受类型'(自我)'"。

的参数列表

我有什么想法可以改变raise:来解决这个问题吗?

提前致谢。

1 个答案:

答案 0 :(得分:4)

这里有很多重叠的问题可能无法很好地解决(即使你这样做,结果也不会很好)。让我们来看看其中一些。

protocol Raisable {
    func raise(exponent : Self) -> Self
}

好的,我们已经遇到了第一个问题。考虑Self是否为IntInt(2).raise(-1)的结果是什么?它应该是0.5,但这不是整数。你打算圆到1吗?这与您为Double编写的代码完全不同。

extension Raisable where Self : SignedNumberType {
    func raise(exponent : Double) -> Self {
        return Self(pow(Double(self), exponent))
    }
}

这要求每个可能的SignedNumberType可以转换为Double,而不是承诺,甚至是可取的。SignedNumberType。例如,复数满足pow的所有要求,将复数提高到实数指数是合理的,但i^2不是正确的函数。您确实需要使用差异化代码来处理这些情况。特别考虑i的情况,这是真实的,所以只需将0投影到其真实组件(extension Squarable { func squared() -> Self { return self.raise(2) } } )上,然后进行平方,这将导致非常令人惊讶的结果。

self*self

除了其他问题之外,这非常非常缓慢(在适用的情况下比self<<1Double慢几个数量级)。如果能够显着提高可读性,那就不是世界的终点,但它似乎并不是真的。

一般来说,Swift并不鼓励采用“一些数字,我不关心什么类型”的功能。在大多数情况下,您需要编写代码来处理数字转换,并考虑溢出,截断等情况。如果要将所有内容提升到squared(),通常需要有意识地执行此操作,而不是通过协议。

但是这里还有一些关于扩展的知识。我们当然可以轻松地创建protocol Multipliable { func *(lhs: Self, rhs: Self) -> Self } extension Multipliable { func squared() -> Self { return self * self } } extension Int: Multipliable {} extension Double: Multipliable {} 2.squared() (2.1).squared() 方法并将其附加到各种类型。例如:

#!/bin/bash

# CHANGE THESE FOR YOUR APP
app_package="com.example"
dir_app_name="MySysApp"
MAIN_ACTIVITY="SysAppMainActivity"

ADB="adb" # how you execute adb
ADB_SH="$ADB shell" # this script assumes using `adb root`. for `adb su` see `Caveats`

path_sysapp="/system/priv-app" # assuming the app is priviledged
apk_host="./app/build/outputs/apk/app-debug.apk"
apk_name=$dir_app_name".apk"
apk_target_dir="$path_sysapp/$dir_app_name"
apk_target_sys="$apk_target_dir/$apk_name"

# Delete previous APK
rm -f $apk_host

# Compile the APK: you can adapt this for production build, flavors, etc.
./gradlew assembleDebug || exit -1 # exit on failure

# Install APK: using adb root
$ADB root 2> /dev/null
$ADB remount # mount system
$ADB push $apk_host $apk_target_sys

# Give permissions
$ADB_SH "chmod 755 $apk_target_dir"
$ADB_SH "chmod 644 $apk_target_sys"

#Unmount system
$ADB_SH "mount -o remount,ro /"

# Stop the app
$ADB shell "am force-stop $app_package"

# Re execute the app
$ADB shell "am start -n \"$app_package/$app_package.$MAIN_ACTIVITY\" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER"