在Swift中使用where子句扩展数组类型


71

我想使用Accelerate框架来扩展[Float]和[Double],但是每一个都需要不同的实现。

我尝试了明显的方法:

extension Array<Float> {
}

并得到这个错误:

“必须在具有'where'子句指定约束的非专用泛型'Array'上声明受约束的扩展”

这样在Swift 2中扩展泛型类型是否可行?

我的代码现在按预期工作了。这是显示使用Accelerate框架求和的示例。

extension _ArrayType where Generator.Element == Float {

    func quickSum() -> Float {
        var result: Float = 0
        if var x = self as? [Float] {
            vDSP_sve(&x, 1, &result, vDSP_Length(x.count))
        }
        return result
    }
}

extension _ArrayType where Generator.Element == Double {

    func quickSum() -> Double {
        var result: Double = 0
        if var x = self as? [Double] {
            vDSP_sveD(&x, 1, &result, vDSP_Length(x.count))
        }
        return result
    }
}

Answers:


128

如果只想扩展特定类型的数组。您应该扩展_ArrayType协议。

extension _ArrayType where Generator.Element == Int {

   func doSomething() {
       ... 
   }
}

如果扩展Array,则只能确保您的元素符合其他协议。即:

extension Array where Element: Equatable {

   func doSomething() {
       ... 
   }
}

更新:使用Swift 3.1 https://github.com/apple/swift/blob/master/CHANGELOG.md

extension Array where Element == Int {

   func doSomething() {
       ... 
   }
}

这确实帮助我解决了一个稍微不同的问题。我在重写Array并使用contains(element),直到我将扩展限制为Ele​​ment:Equatable时才起作用。要查看不同的约束是什么(以及它们会影响哪些方法),另请参见SequenceType:swiftdoc.org/v2.1/protocol/SequenceType
David James

我认为您应该使用SequenceType而不是_ArrayType
Daniel

8
答案与Swift 2.2完美配合,但是_ArrayType在Swift 3中消失了。我们现在应该怎么做?
Maiaux

@Maiaux请参阅下面的答案。
Ben Lu

15
在swift 3.1中,extension Array where Element == Int给出错误错误:同类型要求使通用参数'Element'非通用扩展Array其中Element == Int,给我建议
Rohit Parsana

28

斯威夫特3营救!!

extension Collection where Iterator.Element == Int {
    // `Collection` can be `Sequence`, etc
}

1
这可行,但是现在我无权访问该集合的下标。例如,如果我写,则会self[0]收到“无法为索引类型为Int的Self类型下标”错误
Maiaux

@Maiaux因为subscript不是函数,并且不支持泛型,所以我猜这不太好。
Ben Lu

还有其他支持下标的Swift 3解决方案吗?
Maiaux

15

怎么样

extension CollectionType where Generator.Element == Double {

}

或者,如果您想要更多一点:

protocol ArithmeticType {
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
}

extension Double : ArithmeticType {}
extension Float : ArithmeticType {}

extension SequenceType where Generator.Element : protocol<FloatLiteralConvertible, ArithmeticType> {
    var sum : Generator.Element {
        return reduce(0.0, combine: +)
    }

    var product : Generator.Element {
        return reduce(1.0, combine: *)
    }
}


stride(from: 1.0, through: 10.0, by: 1.0).sum   // 55
[1.5, 2.0, 3.5, 4.0, 5.5].product               // 231

适用于DoubleFloat或您符合协议ArithmeticType和的任何其他类型FloatLiteralConvertible。如果您需要访问数组的特定索引,请更改SequenceType为,CollectionType因为您无法使用序列执行此操作。


4

所以我没有正确阅读问题。 FloatingPointType是Double,Float和CGFloat实现的现有协议,因此

是。我只是昨天才添加一个函数到SequenceType,其中元素必须是Equatable。这是将元素限制为Float

您需要使用where子句。这是我下面的功能。

public extension SequenceType where Self.Generator.Element: FloatingPointType
{
    public func splitAt(separator: Generator.Element) -> [[Generator.Element]]
    {
        var ret: [[Generator.Element]] = []
        var thisPart: [Generator.Element] = []

        for element in self
        {
            if element == separator
            {
                ret.append(thisPart)
                thisPart = []
            }
            else
            {
                thisPart.append(element)
            }
        }
        ret.append(thisPart)
        return ret
    }
}

[Float(1), Float(2), Float(3), Float(4)].splitAt(Float(2))
// returns [[1],[3, 4]]
[Double(1), Double(2), Double(3), Double(4)].splitAt(Double(3))
// returns [[1, 2],[4]]

注意:我无法对数组使用此功能,但SequenceType还是更通用。


4

Xcode 8.2上的Swift 3

只需要扩展Sequence协议并提供where语句即可。

let someString = "1, 2, 3, 4, 5, 6, 7, 8"

extension String {        
  func toArrayOfElements() -> [String] {
    return self.components(separatedBy: ", ")
  }        
}

extension Sequence where Iterator.Element == String {        
  func toInt() -> [Int] {            
    return self.map {
      Int($0)!
    }
  }        
}

let arrayOfStrings = someString.toArrayOfElements()    
print(arrayOfStrings)

let arrayOfInts = arrayOfStrings.toInt()    
print(arrayOfInts)

3

如果只想扩展特定的内容Array,则必须为每种类型使用协议:

protocol DoubleValue {
    var value: Double { get }
}
extension Double: DoubleValue {
    var value: Double { return self }
}
extension Array where Element: DoubleValue {
    // use the value property
}

// the same for Float
protocol FloatValue {
    var value: Float { get }
}

extension Float: FloatValue {
    var value: Float { return self }
}
extension Array where Element: FloatValue {
    // use the value property
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.