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

时间:2021-04-01 11:52:53

I'd like to use the Accelerate framework to extend [Float] and [Double] but each of these requires a different implementation.

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

I tried the obvious:

我试着显而易见的:

extension Array<Float> {
}

and get this error:

并得到这个错误:

"Constrained extension must be declared on the unspecialised generic type 'Array' with constraints specified by a 'where' clause"

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

Is it posible to extend generic types in Swift 2 in this way?

是否可以以这种方式扩展Swift 2中的泛型类型?

I've got the code working as expected now. Here's an example showing a summation using the Accelerate framework.

我已经让代码按照预期运行。这里有一个使用加速框架的求和示例。

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
    }
}

6 个解决方案

#1


95  

If you want to extend only array with specific type. You should extend _ArrayType protocol.

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

extension _ArrayType where Generator.Element == Int {

   func doSomething() {
       ... 
   }
}

If you extend Array you can only make sure your element is conformed some protocol else. i.e:

如果扩展数组,只能确保元素符合其他协议。即:

extension Array where Element: Equatable {

   func doSomething() {
       ... 
   }
}

Updated: With Swift 3.1 https://github.com/apple/swift/blob/master/CHANGELOG.md

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

extension Array where Element == Int {

   func doSomething() {
       ... 
   }
}

#2


27  

Swift 3 to the rescue!!

快来救我!!

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

#3


14  

How about

如何

extension CollectionType where Generator.Element == Double {

}

Or If you want a little bit more:

或者如果你想要更多一点:

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

Works with Double and Float or any other type that you conform to the protocols ArithmeticType and FloatLiteralConvertible. If you need to access specific indices of your array, change SequenceType to CollectionType as you cannot do this with a sequence.

可以使用Double和Float或任何您符合协议的其他类型。如果您需要访问数组的特定索引,请将SequenceType更改为CollectionType,因为您不能对序列进行此操作。

#4


4  

So I didn't read the question properly. FloatingPointType is an existing protocol that is implemented by Double, Float and CGFloat, so

所以我没有正确地阅读这个问题。FloatingPointType是一个现有的协议,由Double、Float和CGFloat实现

Yes. I did it only yesterday to add a function to SequenceType where the elements had to be Equatable. This is a modification to restrict the elements to Float

是的。就在昨天,我还为SequenceType添加了一个函数,其中的元素必须是可赋值的。这是一个限制元素为浮动的修改

You need to use a where clause. This is my function below.

你需要使用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]]

NB I couldn't make this work for an array but SequenceType is more general anyway.

NB我不能把它作为一个数组,但是SequenceType更通用。

#5


3  

If you only want to extend a specific Array you have to use a protocol for each type:

如果您只想扩展一个特定的数组,那么您必须为每种类型使用一个协议:

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
}

#6


3  

Swift 3 on Xcode 8.2

Xcode 8.2上的Swift 3

Just need to extend Sequence protocol and provide a where statement.

只需扩展序列协议并提供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)

#1


95  

If you want to extend only array with specific type. You should extend _ArrayType protocol.

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

extension _ArrayType where Generator.Element == Int {

   func doSomething() {
       ... 
   }
}

If you extend Array you can only make sure your element is conformed some protocol else. i.e:

如果扩展数组,只能确保元素符合其他协议。即:

extension Array where Element: Equatable {

   func doSomething() {
       ... 
   }
}

Updated: With Swift 3.1 https://github.com/apple/swift/blob/master/CHANGELOG.md

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

extension Array where Element == Int {

   func doSomething() {
       ... 
   }
}

#2


27  

Swift 3 to the rescue!!

快来救我!!

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

#3


14  

How about

如何

extension CollectionType where Generator.Element == Double {

}

Or If you want a little bit more:

或者如果你想要更多一点:

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

Works with Double and Float or any other type that you conform to the protocols ArithmeticType and FloatLiteralConvertible. If you need to access specific indices of your array, change SequenceType to CollectionType as you cannot do this with a sequence.

可以使用Double和Float或任何您符合协议的其他类型。如果您需要访问数组的特定索引,请将SequenceType更改为CollectionType,因为您不能对序列进行此操作。

#4


4  

So I didn't read the question properly. FloatingPointType is an existing protocol that is implemented by Double, Float and CGFloat, so

所以我没有正确地阅读这个问题。FloatingPointType是一个现有的协议,由Double、Float和CGFloat实现

Yes. I did it only yesterday to add a function to SequenceType where the elements had to be Equatable. This is a modification to restrict the elements to Float

是的。就在昨天,我还为SequenceType添加了一个函数,其中的元素必须是可赋值的。这是一个限制元素为浮动的修改

You need to use a where clause. This is my function below.

你需要使用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]]

NB I couldn't make this work for an array but SequenceType is more general anyway.

NB我不能把它作为一个数组,但是SequenceType更通用。

#5


3  

If you only want to extend a specific Array you have to use a protocol for each type:

如果您只想扩展一个特定的数组,那么您必须为每种类型使用一个协议:

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
}

#6


3  

Swift 3 on Xcode 8.2

Xcode 8.2上的Swift 3

Just need to extend Sequence protocol and provide a where statement.

只需扩展序列协议并提供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)