我们如何在 Swift 中创建一个对 Number 类型求和的通用数组扩展? [英] How can we create a generic Array Extension that sums Number types in Swift?

查看:28
本文介绍了我们如何在 Swift 中创建一个对 Number 类型求和的通用数组扩展?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆