我希望能够做到这样的事情。
let float1: Float = 1.0
let float2: Float = 2.0
let float3 = f1.add(f2) // Float of value 3.0
let cgFloat1: CGFloat = 1.0
let cgFloat2: CGFloat = 2.0
let cgFloat3 = cgFloat1.add(cgFloat2) // CGFloat of value 3.0
let number1 = NSNumber(float: 1.0)
let number2 = NSNumber(float: 2.0)
let number3 = number1.add(number2) // NSNumber of value 3.0
如何创建一个允许我在任意结构或类上实现add
的协议?
我发现使用Swift非常困难。
答案 0 :(得分:4)
第一步是描述协议中的内容:
protocol Addable {
func add(other : Self) -> Self
}
然后你可以让其他类型符合它:
extension Int : Addable {
func add(other : Int) -> Int {
return self + other
}
}
当然这意味着必须为要添加此add方法的每种类型编写相同的代码。我们可以通过使用协议扩展来提供默认实现,从而做得更好。但我们不能只为Addable实现扩展,编译器会抱怨"二进制运算符+不能应用于两个自操作符"。这是因为该协议可以通过没有定义+运算符的类型来实现。所以我们需要使用' where'子句将扩展名限制为定义+运算符的类型。这意味着我们需要另一个协议,它需要+运算符。可悲的是,斯威夫特并没有提供一个,所以我们需要自己制作:
protocol DefinesPlusOperator {
func +( lhs : Self, rhs : Self ) -> Self
}
现在我们可以将此协议添加到我们所有的类型中:
extension Int : DefinesPlusOperator {}
extension Float : DefinesPlusOperator {}
extension CGFloat : DefinesPlusOperator {}
请注意,我们不需要在此处提供实现,这些类型已经具有+运算符,因此我们可以声明它们符合此协议,而无需提供实现。
有了这个,我们可以为符合Addable和DefinesPlusOperator协议的所有类型提供默认实现:
extension Addable where Self : DefinesPlusOperator {
func add(other : Self) -> Self {
return self + other
}
}
同样,我们必须扩展我们的类型以符合这个协议:
extension Int : Addable {}
....
这里我们不必提供实现,因为我们在协议扩展中有默认实现。
我们也可以声明类型同时符合这两个协议:
extension Double : DefinesPlusOperator, Addable {}
离开NSNumber。这是最难的情况。它没有提供+运算符,因此我们不能将它与DefinesPlusOperator默认实现一起使用。我们必须创建自己的实现:
extension NSNumber : Addable {
func add( other : NSNumber ) -> Self {
return self.dynamicType.init(integer: integerValue + other.integerValue)
}
}
这看起来有点奇怪,但它必须与此类似,因为NSNumber不是最终类,因此它可以是子类,并且协议必须适用于所有子类以及基类。使用self.dynamicType.init创建结果实例可确保我们返回与调用add时完全相同的NSNumber子类。
不幸的是,这会在运行时崩溃,因为NSNumber的实现方式是类集群。 init(integer :)初始化程序在所有具体的NSNumber子类上都不可用。
我们仍然可以为NSNumber添加一个add方法,但我们无法使其符合该Addable协议。但这也不是那么容易,因为NSNumber可以包含不同类型的值(布尔值,整数,浮点数,NSDecimalNumber)。因此,如果我们像这样实施它,我们就会丢失信息:
extension NSNumber {
func add(other : NSNumber) -> NSNumber {
return NSNumber(integer: integerValue + other.integerValue)
}
}
我对NSNumber的处理建议是在收到它时立即将它转换为正确的Swift类型,如果我们必须将其转换为Objective-C API,则只将其转换回来。