web-dev-qa-db-fra.com

Étendre les types de tableau en utilisant la clause where dans Swift

J'aimerais utiliser le cadre Accelerate pour étendre les fonctions [Float] et [Double], mais chacune nécessite une implémentation différente.

J'ai essayé l'évidence:

extension Array<Float> {
}

et obtenez cette erreur:

"L'extension contrainte doit être déclarée sur le type générique non spécifié 'Array' avec des contraintes spécifiées par une clause 'where'"

Est-il possible d’étendre les types génériques dans Swift 2 de cette façon?)?

Le code fonctionne comme prévu maintenant. Voici un exemple montrant une sommation à l'aide du cadre 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
    }
}
68
GScrivs

Si vous souhaitez étendre uniquement un tableau avec un type spécifique. Vous devez étendre le protocole _ArrayType.

extension _ArrayType where Generator.Element == Int {

   func doSomething() {
       ... 
   }
}

Si vous prolongez Array, vous ne pouvez vous assurer que votre élément est conforme à un autre protocole. c'est à dire:

extension Array where Element: Equatable {

   func doSomething() {
       ... 
   }
}

Mise à jour: avec Swift 3.1 https://github.com/Apple/Swift/blob/ master/CHANGELOG.md

extension Array where Element == Int {

   func doSomething() {
       ... 
   }
}
117
Huy Le

Swift 3 à la rescousse !!

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

Que diriez-vous

extension CollectionType where Generator.Element == Double {

}

Ou si vous voulez un peu plus:

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

Fonctionne avec Double et Float ou avec tout autre type que vous conformez aux protocoles ArithmeticType et FloatLiteralConvertible. Si vous avez besoin d'accéder à des index spécifiques de votre tableau, changez SequenceType en CollectionType car vous ne pouvez pas le faire avec une séquence.

15
Kametrixom

Donc, je n'ai pas lu la question correctement. FloatingPointType est un protocole existant implémenté par Double, Float et CGFloat, donc

Oui. Je l'ai fait hier seulement pour ajouter une fonction à SequenceType dans laquelle les éléments devaient être Equatable. Ceci est une modification pour restreindre les éléments à Float

Vous devez utiliser une clause where. Ceci est ma fonction ci-dessous.

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: je ne pouvais pas faire fonctionner ce travail pour un tableau, mais SequenceType est plus général de toute façon.

4
JeremyP

Swift 3 sur Xcode 8.2

Juste besoin d'étendre le protocole de séquence et de fournir une instruction 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)
4
Melvin John

Si vous voulez seulement étendre un Array spécifique, vous devez utiliser un protocole pour chaque 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
Qbyte