2015-08-04 3 views
55

Я хотел бы использовать фреймворк Accelerate для расширения [Float] и [Double], но для каждого из них требуется другая реализация.Расширение типов массивов с использованием предложения where в Swift

Я попытался очевидное:

extension Array<Float> { 
} 

и получить эту ошибку:

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

ли это Возможное расширить общие типы в 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 
    } 
} 

ответ

87

Если вы хотите расширить только массив с определенным типом. Вы должны расширить протокол _ArrayType.

extension _ArrayType where Generator.Element == Int { 

    func doSomething() { 
     ... 
    } 
} 

Если продлить Array вы можете только убедиться, что ваш элемент соответствовал какой-то протокол еще. то есть:

extension Array where Element: Equatable { 

    func doSomething() { 
     ... 
    } 
} 

Обновлено: С Swift 3.1https://github.com/apple/swift/blob/master/CHANGELOG.md

extension Array where Element == Int { 

    func doSomething() { 
     ... 
    } 
} 
+0

Это действительно помогло мне в несколько иной проблеме. Я переопределял Array и использовал contains (element), который не работал, пока я не ограничил расширение Element: Equatable. Чтобы узнать, что представляют собой различные ограничения (и какие методы они влияют) см. Также SequenceType: http://swiftdoc.org/v2.1/protocol/SequenceType/ –

+0

Я думаю, вы должны использовать 'SequenceType' вместо' _ArrayType' – Daniel

+8

ответ работает отлично с Swift 2.2, но _ArrayType исчез в Swift 3. Как нам это сделать сейчас? – Maiaux

14

Как насчет

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 

Работает с Double и Float или любым другим типом, которые вы соответствуете протоколам 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]] 

NB Я не мог сделать эту работу для массива, но SequenceType является более общим в любом случае.

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

Swift 3 на помощь !!

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

Это работает, но теперь у меня нет доступа к индексам для коллекции. Например, если я пишу 'self [0]' I get a "Не могу подстроить значение типа Self с индексом типа Int" error – Maiaux

+0

@Maiaux, потому что 'subscript' не является функцией и не поддерживает дженерики, поэтому я думаю, это не работает слишком хорошо. –

+0

Любое другое быстрое решение 3, поддерживающее индексы? – Maiaux

3

Swift 3 on Xcode 8.2

Просто нужно расширить протокол последовательности и предоставить оператор 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) 
Смежные вопросы