【问题标题】:Extend array types using where clause in Swift在 Swift 中使用 where 子句扩展数组类型
【发布时间】:2015-08-04 10:04:55
【问题描述】:

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

我尝试了显而易见的:

extension Array<Float> {
}

并得到这个错误:

"约束扩展必须在非特化泛型上声明 类型 'Array' 具有由 'where' 子句指定的约束"

是否可以通过这种方式在 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
    }
}

【问题讨论】:

    标签: swift generics swift2 swift-extensions


    【解决方案1】:

    如果您只想扩展特定类型的数组。你应该扩展 _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) ,直到我将扩展限制为 Element : Equatable 才起作用。要查看不同的约束是什么(以及它们影响的方法),另请参阅 SequenceType:swiftdoc.org/v2.1/protocol/SequenceType
    • 我认为你应该使用SequenceType 而不是_ArrayType
    • 答案在 Swift 2.2 上完美运行,但是 _ArrayType 在 Swift 3 中消失了,我们现在应该怎么做呢?
    • @Maiaux 请参阅下面的答案。
    • 在 swift 3.1 中,extension Array where Element == Int 给出错误 错误:相同类型要求使泛型参数 'Element' 非泛型扩展 Array where Element == Int,给我建议
    【解决方案2】:

    Swift 3 来救援!!

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

    【讨论】:

    • 这可行,但现在我无法访问该集合的下标。例如,如果我写 self[0] 我得到一个“不能用 Int 类型的索引下标 Self 类型的值”错误
    • @Maiaux 因为subscript 不是函数并且不支持泛型,所以我猜这不太好用。
    • 还有其他支持下标的 swift 3 解决方案吗?
    【解决方案3】:

    怎么样

    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 或您符合协议ArithmeticTypeFloatLiteralConvertible 的任何其他类型。如果您需要访问数组的特定索引,请将 SequenceType 更改为 CollectionType,因为您无法使用序列执行此操作。

    【讨论】:

      【解决方案4】:

      如果您只想扩展特定的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
      }
      

      【讨论】:

        【解决方案5】:

        所以我没有正确阅读问题。 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 更通用。

        【讨论】:

          【解决方案6】:

          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)
          

          【讨论】:

            【解决方案7】:

            这对我有用。我正在使用Swift 5

            extension Array where Iterator.Element == Float {
            }
            

            【讨论】:

              【解决方案8】:

              这就是我使用 Swift 5 的方法:

              extension Array where ArrayLiteralElement == Float {
              
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-08-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-07-24
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多