Extend array types using the where clause in Swift

I would like to use the Accelerate framework to extend [Float] and [Double], but each of them requires a different implementation.

I tried the obvious:

extension Array<Float> { } 

and get this error:

"A restricted extension must be declared on a non-specialized generic type 'Array' with the restrictions specified in the 'where' clause

Is it possible to distribute generic types in Swift 2 this way?

The code now works for me as expected. Here is an example of summing using the Accelerate view.

 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 } } 
+53
generics swift swift2 swift-extensions
Aug 04 '15 at 10:04
source share
6 answers

If you want to expand only an array with a specific type. You must extend the _ArrayType protocol.

 extension _ArrayType where Generator.Element == Int { func doSomething() { ... } } 

If you extend Array , you can only make sure that your element conforms to a different protocol. i.e:

 extension Array where Element: Equatable { func doSomething() { ... } } 

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

 extension Array where Element == Int { func doSomething() { ... } } 
+83
Jan 08 '16 at 8:20
source share

Swift 3 to the rescue!

 extension Collection where Iterator.Element == Int { // `Collection` can be `Sequence`, etc } 
+26
Sep 28 '16 at 23:06
source share

What about

 extension CollectionType where Generator.Element == Double { } 

Or if you want a little 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 complies with the ArithmeticType and FloatLiteralConvertible . If you need to access specific indices of your array, change SequenceType to CollectionType since you cannot do this with a sequence.

+14
Aug 04 '15 at 10:30
source share

So, I did not read the question correctly. FloatingPointType is an existing protocol implemented by Double, Float and CGFloat, therefore

Yes. I did this just yesterday to add a function to SequenceType where the elements were supposed to be Equatable . This is a modification to restrict elements on Float

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

 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 could not do this job for an array, but SequenceType is more general anyway.

+4
Aug 04 '15 at 10:36
source share

If you want to extend only Array , you need 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 } 
+3
Aug 04 '15 at 10:42 on
source share

Swift 3 on Xcode 8.2

You just need to extend the Sequence protocol and provide a where statement.

 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
Feb 23 '17 at 19:42 on
source share



All Articles