Swift可让您创建一个将Integer与之相加的Array扩展:
extension Array { func sum() -> Int { return self.map { $0 as Int }.reduce(0) { $0 + $1 } } }
现在可以用来总结Int[]如下:
Int[]
[1,2,3].sum() //6
但是我们如何制作一个通用的版本,该版本也支持对其他Number类型进行求和Double[]?
Double[]
[1.1,2.1,3.1].sum() //fails
这个问题 不是如何对数字求和 ,而是如何 创建通用数组扩展 来实现。
如果可以帮助任何人更接近解决方案,这是我能够获得的最接近的结果:
您可以创建一个可以满足我们需要做的协议,即:
protocol Addable { func +(lhs: Self, rhs: Self) -> Self init() }
然后扩展我们想要支持的符合上述协议的每种类型:
extension Int : Addable { } extension Double : Addable { }
然后添加具有该约束的扩展:
extension Array { func sum<T : Addable>(min:T) -> T { return self.map { $0 as T }.reduce(min) { $0 + $1 } } }
现在可以将其用于我们为支持该协议而扩展的数字,即:
[1,2,3].sum(0) //6 [1.1,2.1,3.1].sum(0.0) //6.3
不幸的是,我不得不在不提供参数的情况下使它运行,即:
func sum<T : Addable>(x:T...) -> T? { return self.map { $0 as T }.reduce(T()) { $0 + $1 } }
修改后的方法仍然可以使用1个参数:
[1,2,3].sum(0) //6
但是在不带参数的情况下无法解析该方法,即:
[1,2,3].sum() //Could not find member 'sum'
添加Integer到方法签名也无助于方法解析:
Integer
func sum<T where T : Integer, T: Addable>() -> T? { return self.map { $0 as T }.reduce(T()) { $0 + $1 } }
但是希望这将帮助其他人更接近解决方案。
从@GabrielePetronella答案来看,如果我们在调用站点上明确指定类型,则可以调用上述方法:
let i:Int = [1,2,3].sum() let d:Double = [1.1,2.2,3.3].sum()
从Swift 2开始,可以使用协议扩展来做到这一点。(有关更多信息,请参见Swift编程语言:协议)。
首先,该Addable协议:
Addable
protocol Addable: IntegerLiteralConvertible { func + (lhs: Self, rhs: Self) -> Self } extension Int : Addable {} extension Double: Addable {} // ...
接下来,扩展SequenceType以添加Addable元素序列:
SequenceType
extension SequenceType where Generator.Element: Addable { var sum: Generator.Element { return reduce(0, combine: +) } }
用法:
let ints = [0, 1, 2, 3] print(ints.sum) // Prints: "6" let doubles = [0.0, 1.0, 2.0, 3.0] print(doubles.sum) // Prints: "6.0"