Swift 2 使用 `pow` 的协议扩展
Swift 2 Protocol extension using `pow`
我正在尝试赋予任何数字提升到任意幂(具体来说,2)的能力。这似乎是使用协议扩展而不是向 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)
}
}
编译器显示 "Cannot find initializer for type 'Double' that accepts an argument list of type '(Self)'".
有什么想法可以改变 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
或从 Double
转换,这是不被承诺的,甚至是不可取的。例如,一个复数满足 SignedNumberType
的所有要求,并且将复数提高到实指数是合理的,但是 pow
不是正确的函数。您确实需要使用差异化代码来处理这些情况。特别考虑 i^2
的情况,它是实数,因此只需将 i
投影到它的实数分量 (0
) 上,然后进行平方,这将导致非常令人惊讶的结果。
extension Squarable {
func squared() -> Self {
return self.raise(2)
}
}
除了其他问题,这非常非常慢(比 self*self
或 self<<1
慢几个数量级(在适用的情况下)。如果它显着提高了可读性,那还不是世界末日,但它似乎并没有。
一般来说,Swift不鼓励取"some number, I don't care what type."的函数,大多数情况下,需要自己写代码处理数值转换,还要考虑溢出、截断等情况。如果你想要将所有内容推广到 Double
,您通常需要有意识地这样做,而不是通过协议。
但是这里还有一些关于扩展的东西需要学习。我们当然可以轻松地创建一个 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()
我正在尝试赋予任何数字提升到任意幂(具体来说,2)的能力。这似乎是使用协议扩展而不是向 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)
}
}
编译器显示 "Cannot find initializer for type 'Double' that accepts an argument list of type '(Self)'".
有什么想法可以改变 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
或从 Double
转换,这是不被承诺的,甚至是不可取的。例如,一个复数满足 SignedNumberType
的所有要求,并且将复数提高到实指数是合理的,但是 pow
不是正确的函数。您确实需要使用差异化代码来处理这些情况。特别考虑 i^2
的情况,它是实数,因此只需将 i
投影到它的实数分量 (0
) 上,然后进行平方,这将导致非常令人惊讶的结果。
extension Squarable {
func squared() -> Self {
return self.raise(2)
}
}
除了其他问题,这非常非常慢(比 self*self
或 self<<1
慢几个数量级(在适用的情况下)。如果它显着提高了可读性,那还不是世界末日,但它似乎并没有。
一般来说,Swift不鼓励取"some number, I don't care what type."的函数,大多数情况下,需要自己写代码处理数值转换,还要考虑溢出、截断等情况。如果你想要将所有内容推广到 Double
,您通常需要有意识地这样做,而不是通过协议。
但是这里还有一些关于扩展的东西需要学习。我们当然可以轻松地创建一个 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()