Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Swift中创建一个对数字类型求和的通用数组扩展?_Swift - Fatal编程技术网

如何在Swift中创建一个对数字类型求和的通用数组扩展?

如何在Swift中创建一个对数字类型求和的通用数组扩展?,swift,Swift,Swift允许您创建一个数组扩展名,该扩展名将整数与: extension Array { func sum() -> Int { return self.map { $0 as Int }.reduce(0) { $0 + $1 } } } 现在可用于求和Int[]如下: [1,2,3].sum() //6 但是,我们如何制作一个通用版本来支持对其他类型的数字进行求和,比如Double[] [1.1,2.1,3.1].sum() //fails 这

Swift允许您创建一个数组扩展名,该扩展名将整数与:

extension Array {
    func sum() -> Int {
        return self.map { $0 as Int }.reduce(0) { $0 + $1 }
    }
}
现在可用于求和
Int[]
如下:

[1,2,3].sum() //6
但是,我们如何制作一个通用版本来支持对其他类型的数字进行求和,比如
Double[]

[1.1,2.1,3.1].sum() //fails

这个问题不是如何求和,而是如何创建一个通用数组扩展


越来越近 如果它能帮助任何人更接近解决方案,这是我所能得到的最接近的结果:

您可以创建一个能够满足我们需要的协议,即:

protocol Addable {
    func +(lhs: Self, rhs: Self) -> Self
    init()
}
然后扩展我们要支持的符合上述协议的每种类型:

extension Int : Addable {
}

extension Double : Addable {
}
protocol Addable: IntegerLiteralConvertible {
    func + (lhs: Self, rhs: Self) -> Self
}

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 }
    }
}
不幸的是,我无法在不提供参数的情况下使其工作,即:

func sum<T : Addable>(x:T...) -> T?
{
    return self.map { $0 as T }.reduce(T()) { $0 + $1 }
}
但是在没有参数的情况下调用该方法时无法解析该方法,即:

[1,2,3].sum() //Could not find member 'sum'
向方法签名添加
Integer
也无助于方法解析:

func sum<T where T : Integer, T: Addable>() -> T?
{
    return self.map { $0 as T }.reduce(T()) { $0 + $1 }
}

下面是一个愚蠢的实现:

extension Array {
    func sum(arr:Array<Int>) -> Int {
        return arr.reduce(0, {(e1:Int, e2:Int) -> Int in return e1 + e2})
    }
    func sum(arr:Array<Double>) -> Double {
        return arr.reduce(0, {(e1:Double, e2:Double) -> Double in return e1 + e2})
    }
}
扩展数组{
func sum(arr:Array)->Int{
返回arr.reduce(0,{(e1:Int,e2:Int)->返回e1+e2}中的Int)
}
func sum(arr:Array)->Double{
返回arr.reduce(0,{(e1:Double,e2:Double)->返回e1+e2}中的Double)
}
}

这很愚蠢,因为你必须说
arr.sum(arr)
。换句话说,它不是封装的;它是一个“自由”函数
sum
,恰好隐藏在数组中。因此,我未能解决您真正想要解决的问题。

根据我对swift语法的理解,a不能与泛型参数一起使用,只能与泛型参数一起使用。因此,只能与具体类型一起使用。

我认为我找到了一种合理的方法,从您建议的实现中借鉴了一些想法并从中开始。 基本上我们想要的是有表示幺半群的类型类

换言之,我们需要:

  • 结合函数
  • 标识值(即零)
这里有一个建议的解决方案,它围绕swift类型的系统限制工作

首先,我们友好的
Addable
typeclass

protocol Addable {
    class func add(lhs: Self, _ rhs: Self) -> Self
    class func zero() -> Self
}
现在让我们让
Int
实现它

extension Int: Addable {
    static func add(lhs: Int, _ rhs: Int) -> Int {
        return lhs + rhs
    }

    static func zero() -> Int {
        return 0
    }
}
到目前为止还不错。现在我们有了构建通用“求和函数”所需的所有部分:

extension Array {
    func sum<T : Addable>() -> T {
        return self.map { $0 as T }.reduce(T.zero()) { T.add($0, $1) }
    }
}
由于类型系统的限制,您需要显式强制转换结果类型,因为编译器本身无法将
Addable
解析为
Int

所以你不能只做:

let result = [1,2,3].sum()
我认为这是这种方法的一个可以忍受的缺点

当然,这是完全通用的,它可以用于任何类,任何类型的幺半群。 我没有使用默认的
+
操作符,而是定义了一个
add
函数,原因是它允许任何类型实现
可添加的
类型类。如果您使用
+
,那么类型没有定义
+
操作符,那么您需要在全局范围内实现这样的操作符,我有点不喜欢

无论如何,如果您需要将
Int
String
都设置为“可倍增”,那么下面是它的工作方式,因为
*
是为
Int
定义的,而不是为“String”定义的

protocol Multipliable {
    func *(lhs: Self, rhs: Self) -> Self
    class func m_zero() -> Self
}

func *(lhs: String, rhs: String) -> String {
    return rhs + lhs
}
extension String: Multipliable {
    static func m_zero() -> String {
        return ""
    }
}
extension Int: Multipliable {
    static func m_zero() -> Int {
        return 1
    }
}

extension Array {
    func mult<T: Multipliable>() -> T {
        return self.map { $0 as T }.reduce(T.m_zero()) { $0 * $1 }
    }
}

let y: String = ["hello", " ", "world"].mult()
协议可复用{
func*(左:自,右:自)->Self
类func m_zero()->Self
}
func*(左:字符串,右:字符串)->String{
返回右+左
}
扩展字符串:可乘法{
静态函数m_zero()->字符串{
返回“”
}
}
扩展名Int:可乘法{
静态函数m_zero()->Int{
返回1
}
}
扩展阵列{
func mult()->T{
返回self.map{$0作为T}.reduce(T.m_zero()){$0*$1}
}
}
让y:String=[“你好”,“世界”]。mult()
现在,
String
数组可以使用方法
mult
来执行反向串联(这只是一个愚蠢的例子),实现使用新定义的
*
操作符
String
,然而,
Int
继续使用它通常的
*
操作符,我们只需要为幺半群定义一个零


对于代码清洁,我更喜欢将整个typeclass实现放在
扩展
范围内,但我想这是一个品味问题。

从Swift 2开始,使用协议扩展就可以做到这一点。(有关更多信息,请参阅)

首先,可添加的
协议:

extension Int : Addable {
}

extension Double : Addable {
}
protocol Addable: IntegerLiteralConvertible {
    func + (lhs: Self, rhs: Self) -> Self
}

extension Int   : Addable {}
extension Double: Addable {}
// ...
接下来,扩展
SequenceType
以添加
Addable
元素的序列:

extension SequenceType where Generator.Element: Addable {
    var sum: Generator.Element {
        return reduce(0, combine: +)
    }
}
extension Array where Element: Addable {
    func sum() -> Element {
        return self.reduce(Element.zero, 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 1.x中先前的答案,它是可行的,只需付出最小的努力:

import Foundation

protocol Addable {
    func +(lhs: Self, rhs: Self) -> Self
    init(_: Int)
    init()
}

extension Int : Addable {}
extension Int8 : Addable {}
extension Int16 : Addable {}
extension Int32 : Addable {}
extension Int64 : Addable {}

extension UInt : Addable {}
extension UInt8 : Addable {}
extension UInt16 : Addable {}
extension UInt32 : Addable {}
extension UInt64 : Addable {}

extension Double : Addable {}
extension Float : Addable {}
extension Float80 : Addable {}

// NSNumber is a messy, fat class for ObjC to box non-NSObject values
// Bit is weird

extension Array {
    func sum<T : Addable>(min: T = T(0)) -> T {
        return map { $0 as! T }.reduce(min) { $0 + $1 }
    }
}
<代码>导入基础 协议可添加{ func+(左:自,右:自)->Self 初始化 init() } 扩展名Int:Addable{} 扩展名Int8:可添加{} 扩展名Int16:可添加{} 扩展名Int32:可添加{} 扩展名Int64:可添加{} 扩展UInt:可添加{} 扩展UInt8:可添加{} 扩展UInt16:可添加{} 扩展UInt32:可添加{} 扩展UInt64:可添加{} 双扩展名:可添加{} 扩展浮点:可添加{} 扩展浮点80:可添加{} //NSNumber是一个凌乱的、胖的类,用于ObjC框装非NSObject值 //比特很奇怪 扩展阵列{ 函数和(最小值:T=T(0))->T{ 返回映射{$0as!T}.reduce(min){$0+$1} } }
在这里:


其他地方使用的Swift 2计划进行重大改进,包括异常处理、承诺和更好的通用元编程。

在Swift 2中,您可以这样解决它:

将加法的幺半群定义为协议

protocol Addable {
    init()
    func +(lhs: Self, rhs: Self) -> Self
    static var zero: Self { get }
}
extension Addable {
    static var zero: Self { return Self() }
}
除了其他解决方案外,这还使用标准初始值设定项显式定义了零元素

然后将Int和Double声明为可添加:

extension Int: Addable {}
extension Double: Addable {}
现在可以为所有数组定义sum()方法
protocol Addable {
    init()
    func +(lhs: Self, rhs: Self) -> Self
    static var zero: Self { get }
}
extension Addable {
    static var zero: Self { return Self() }
}
extension Int: Addable {}
extension Double: Addable {}
extension Array where Element: Addable {
    func sum() -> Element {
        return self.reduce(Element.zero, combine: +)
    }
}
extension Numeric where Self: Comparable {

    /// Limits a numerical value.
    ///
    /// - Parameter range: The range the value is limited to be in.
    /// - Returns: The numerical value clipped to the range.
    func limit(to range: ClosedRange<Self>) -> Self {
        if self < range.lowerBound {
            return range.lowerBound
        } else if self > range.upperBound {
            return range.upperBound
        } else {
            return self
        }
    }
}