用于返回接收者类型(符合协议(protocol))的协议(protocol)的 Swift 二元运算符

标签 swift swift2 binary-operators dynamictype

对于 Friday Fun,我想以可互换的格式对 Angles 进行建模。我不确定我是否以最 Swift 惯用的方式完成了它,但我正在学习。所以我有一个 Angle 协议(protocol),然后是 3 种不同的结构类型(弧度、度数和旋转),它们都符合 Angle 协议(protocol)。我希望能够添加/减去它们,但诀窍是,我希望 lhs 参数指示返回类型。例如:

Degrees(180) + Rotations(0.25) --> Degrees(270)

Rotations(0.25) + Radians(M_PI) -> Rotations(0.75)

我希望我能做类似的事情

func + (lhs:Angle, rhs:Angle) -> Angle {
    return lhs.dynamicType(rawRadians: lhs.rawRadians + rhs.rawRadians)
}

Angle 协议(protocol)需要一个 var rawRadians:CGFloat { get } 以及一个 init(rawRadians:CGFloat)

我可以使用类似 Smalltalk 的双重分派(dispatch)方法来做到这一点,但我认为大多数情况下都有更适合 Swift 的方法(尤其是需要较少代码的方法,双重分派(dispatch)需要大量样板代码)。

最佳答案

你只需要一个通用的添加:

func +<A: Angle>(lhs: A, rhs: Angle) -> A {
    return A(rawRadians: lhs.rawRadians + rhs.rawRadians)
}

这样加法将返回 lhs 上的任何类型。

一般来说,如果您使用 dynamicType ,你可能正在与 Swift 战斗。 Swift 更多地依赖于泛型和协议(protocol)(即编译时的静态类型信息)而不是动态调度(即运行时的动态类型信息)。

在这段代码中,如您所说,A是“某种类型,符合 Angle,在编译时确定”的占位符。所以在你的第一个例子中:

Degrees(180) + Rotations(0.25) --> Degrees(270)

这实际上调用了一个专门的函数 +<Degrees> .还有这个:

Rotations(0.25) + Radians(M_PI) -> Rotations(0.75)

调用一个(逻辑上)不同的函数 +<Rotations> .编译器可能会选择将这些函数优化为单个函数,但逻辑上它们是独立的函数,在编译时创建。它基本上是编写 addDegrees(Degrees, Angle) 的快捷方式和 addRotations(Rotations, Angle)手工制作。

现在,关于一个接受两个角度并返回的函数的问题……好吧,什么?如果你想返回 Angle在这种情况下,这很简单,并且与您的原始签名完全匹配:

func +(lhs: Angle, rhs: Angle) -> Angle {
    return Radians(rawRadians: lhs.rawRadians + rhs.rawRadians)
}

“但是......”你是说,“返回 Radians 。”不,它没有。它返回 Angle .你可以在上面做任何你想做的“类似角度”的事情。实现细节本应是不透明的。如果您关心底层数据结构是 Radians ,您几乎可以肯定做错了什么。

好吧,有一种情况,了解这一点可能会有用,那就是如果你根据你的方式打印出来。因此,如果用户为您提供学位信息作为开始,那么您希望以度为单位打印所有内容(使用您未提及的 description 方法)。也许在那种特殊情况下值得这样做。如果你愿意,你的原始代码非常接近:

func +(lhs: Angle, rhs: Angle) -> Angle {
    return lhs.dynamicType.init(rawRadians: lhs.rawRadians + rhs.rawRadians)
}

但重要的是要了解这与您要求“使用 lhs 参数来指示返回类型”的要求不符。这导致 lhs 参数指示返回实现。返回的类型总是Angle .如果要更改返回类型,则需要使用泛型。

关于用于返回接收者类型(符合协议(protocol))的协议(protocol)的 Swift 二元运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32788148/

相关文章:

ios - Swift 2 从 url 变量加载图像错误

swift - Swift 中的一步对象创建和属性初始化?

swift - 将枚举类型的值与关联值进行比较时出现编译器错误?

python - Numpy 中没有用于结构化数组的二元运算符?

c++ - 无法将迭代器分配给二元函数中的常量输入 vector

ios - 使用 Swift 将更多数据传递到 UISearchController

ios - Swift:使控制按钮不随相机移动

ios - 从 NSAttributedString 获取文本 block

ios - 使用 TableViewController 创建双委托(delegate)

swift - 'Use of self in method call before super.init initializes self',无法通过方法调用初始化属性