我试图赋予任何数字任意幂的能力(具体来说,2)。这似乎是使用协议(protocol)扩展的绝佳机会,而不是向 Float
、Double
、Int
等添加扩展。
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)
}
}
编译器显示“无法找到接受类型为“(Self)”的参数列表的类型“Double”的初始值设定项”。
有什么想法可以改变 raise:
来解决这个问题吗?
提前致谢。
最佳答案
这里有很多重叠的问题,可能无法很好地解决(即使解决了,结果也不会很好)。让我们来看看其中的一些。
protocol Raisable {
func raise(exponent : Self) -> Self
}
好的,我们已经遇到了第一个问题。考虑如果 Self
是 Int
。 Int(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
相互转换,这不是 promise 的,甚至不是可取的。例如,一个复数满足SignedNumberType
的所有要求。 ,将复数提升为实数指数是合理的,但是 pow
不是正确的功能。您确实需要使用差异化代码来处理这些情况。特别考虑 i^2
的情况,这是真实的,所以只是投影 i
到它的实数分量( 0
)上,然后进行平方,这将导致非常令人惊讶的结果。
extension Squarable {
func squared() -> Self {
return self.raise(2)
}
}
除了其他问题之外,这是非常非常慢的(比 self*self
或 self<<1
在适用的情况下慢几个数量级)。如果它显着提高了可读性,那并不是世界末日,但事实似乎并非如此。
一般来说,Swift 不鼓励采用“某个数字,我不在乎什么类型”的函数。大多数情况下,您需要编写代码来处理数字转换并考虑溢出、截断等情况。如果您想将所有内容提升为 Double
,您通常需要有意这样做,而不是通过协议(protocol)。
但是关于扩展,这里仍然有一些东西需要学习。我们当然可以创建一个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()
关于使用 `pow` 的 Swift 2 协议(protocol)扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31702831/