我们如何在 Swift 中创建一个对 Number 类型求和的通用数组扩展? [英] How can we create a generic Array Extension that sums Number types in Swift?
问题描述
Swift 允许您创建一个数组扩展,将整数与:
Swift lets you create an Array extension that sums Integer's with:
extension Array {
func sum() -> Int {
return self.map { $0 as Int }.reduce(0) { $0 + $1 }
}
}
现在可用于对 Int[]
求和,例如:
Which can now be used to sum Int[]
like:
[1,2,3].sum() //6
但是我们如何制作一个通用版本,同时支持对其他 Number 类型(如 Double[]
)求和?
But how can we make a generic version that supports summing other Number types like Double[]
as well?
[1.1,2.1,3.1].sum() //fails
<小时>
这个问题不是如何对数字求和,而是如何创建一个通用的数组扩展来做到这一点.
This question is NOT how to sum numbers, but how to create a generic Array Extension to do it.
如果它可以帮助任何人更接近解决方案,这是我能得到的最接近的:
This is the closest I've been able to get if it helps anyone get closer to the solution:
您可以创建一个协议来完成我们需要做的事情,即:
You can create a protocol that can fulfills what we need to do, i.e:
protocol Addable {
func +(lhs: Self, rhs: Self) -> Self
init()
}
然后扩展我们想要支持的符合上述协议的每个类型:
Then extend each of the types we want to support that conforms to the above protocol:
extension Int : Addable {
}
extension Double : Addable {
}
然后添加具有该约束的扩展:
And then add an extension with that constraint:
extension Array {
func sum<T : Addable>(min:T) -> T
{
return self.map { $0 as T }.reduce(min) { $0 + $1 }
}
}
现在可以用于我们为支持协议而扩展的数字,即:
Which can now be used against numbers that we've extended to support the protocol, i.e:
[1,2,3].sum(0) //6
[1.1,2.1,3.1].sum(0.0) //6.3
不幸的是,我无法在不提供参数的情况下使其工作,即:
Unfortunately I haven't been able to get it working without having to supply an argument, i.e:
func sum<T : Addable>(x:T...) -> T?
{
return self.map { $0 as T }.reduce(T()) { $0 + $1 }
}
修改后的方法仍然使用 1 个参数:
The modified method still works with 1 argument:
[1,2,3].sum(0) //6
但是在不带参数的情况下调用它时无法解析该方法,即:
But is unable to resolve the method when calling it with no arguments, i.e:
[1,2,3].sum() //Could not find member 'sum'
将 Integer
添加到方法签名也无助于方法解析:
Adding Integer
to the method signature also doesn't help method resolution:
func sum<T where T : Integer, T: Addable>() -> T?
{
return self.map { $0 as T }.reduce(T()) { $0 + $1 }
}
但希望这能帮助其他人更接近解决方案.
But hopefully this will help others come closer to the solution.
来自@GabrielePetronella 的回答,如果我们在呼叫站点上明确指定类型,则看起来我们可以调用上述方法,例如:
From @GabrielePetronella answer, it looks like we can call the above method if we explicitly specify the type on the call-site like:
let i:Int = [1,2,3].sum()
let d:Double = [1.1,2.2,3.3].sum()
推荐答案
从 Swift 2 开始,可以使用协议扩展来做到这一点.(请参阅 Swift 编程语言:协议想要查询更多的信息).
As of Swift 2 it's possible to do this using protocol extensions. (See The Swift Programming Language: Protocols for more information).
首先是Addable
协议:
protocol Addable: IntegerLiteralConvertible {
func + (lhs: Self, rhs: Self) -> Self
}
extension Int : Addable {}
extension Double: Addable {}
// ...
接下来,扩展 SequenceType
以添加 Addable
元素的序列:
Next, extend SequenceType
to add sequences of Addable
elements:
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"
这篇关于我们如何在 Swift 中创建一个对 Number 类型求和的通用数组扩展?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!