在Swift中数组的通用扩展

时间:2021-04-15 21:34:49

To be very frank, I am totally new to learn Extension creation and usage.

坦率地说,我对扩展创建和使用完全陌生。

I wanted to create a category (Extension in swift 3.0) which can be used throughout an application to perform repeated operations for Array.

我想创建一个类别(在swift 3.0中扩展),它可以在整个应用程序中用于对数组执行重复操作。

Sample Link 1

样本链接1

This is what I have seen and understand while doing research, I wanted to create an extension with various methods which should be generic, and not on the basis of datatype needed to create separate extensions.

这是我在做研究时所看到和理解的,我想用各种方法创建一个扩展,这些方法应该是通用的,而不是基于创建单独扩展所需的数据类型。

Here in above example, we will need to create single extension if we will go for particular datatype wise extension. I wanted to have a guidance if any way is there to create the generic category (Extension in swift).

在上面的示例中,如果要使用特定的数据类型扩展,我们将需要创建单个扩展。我想要有一个指导,如果有任何方法来创建通用类别(扩展的swift)。

  1. extension _ArrayType where Generator.Element == Int
  2. 扩展_ArrayType,发电机。元素= = Int
  3. extension Array where Element: Equatable
  4. 元素:Equatable的扩展数组
  5. extension Array where Element == Int
  6. 元素== Int的扩展数组
  7. extension _ArrayType where Generator.Element == Float
  8. 扩展_ArrayType,发电机。= =浮动元素
  9. extension SequenceType where Self.Generator.Element: FloatingPointType
  10. 扩展SequenceType Self.Generator的地方。元素:FloatingPointType
  11. extension Array where Element: DoubleValue
  12. 元素:DoubleValue的扩展数组
  13. extension Sequence where Iterator.Element == String
  14. 扩展序列迭代器的地方。字符串元素= =

,etc...

等……

Sample Link 2

样本链接2

Note : In short, we can consider that I want to perform actions based on Array in single extension instead of just creating the single extension for each of the datatypes as per above requirement.

注意:简而言之,我们可以考虑在单个扩展中基于数组执行操作,而不是根据上面的需求为每个数据类型创建单个扩展。

2 个解决方案

#1


9  

As mentioned in the comments, one way to accomplish this is to create your own protocol that the types you want to cover adopt (in the comments someone called it Content, used below for this example) (from first source):

正如在评论中提到的,实现这一点的一种方法是创建您希望涵盖的类型所采用的自己的协议(在下面有人称之为Content的评论中,本例使用的是Content)(来自first source):

protocol Content {
    var hash: String { get }
}
extension Array where Element : Content {

    func filterWithId(id : String) -> [Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}

It seems, though, that the original question is mainly asking about generic extensions for arrays, which one comment says are not possible but 100% are possible in Swift (it's a big Swift feature, actually) (from second source).

不过,最初的问题似乎主要是关于数组的泛型扩展,有一条评论说这是不可能的,但在Swift中100%是可能的(实际上,这是Swift的一个重要特性)(来自第二源)。

For example, if you want to define a specific extension method for Ints only, you can do that:

例如,如果您想为int定义一个特定的扩展方法,您可以这样做:

extension Sequence where Iterator.Element == Int {
    var sum: Int {
        return reduce(0, +)
    }
}

It seems like the question's original requirements are extension methods that could be agnostic to data type and therefore should be kept in common. If I understand correctly, seems though that these data types in general have some conformance to Equatable and/or Hashable, which is the minimum requirement for this kind of generic-stuff to work. With this element conformance, though, this is possible as such:

这个问题的原始需求似乎是可与数据类型无关的扩展方法,因此应该保持一致。如果我理解正确的话,看起来这些数据类型一般都符合Equatable和/或Hashable,这是这类泛型工作的最低要求。但是,有了这个元素的一致性,这是可能的:

extension Sequence where Iterator.Element is Equatable {
    func extensionMethodName<T: Equatable>(_ input: [T], singleElement: T) -> [T] {
        // T is now a generic array of equatable items. You can implement whatever extension logic you need with these. 
        // I added different ways of passing in and returning this generic type, but the only thing that is likely going to be consistent is the `<T: Equatable>` which is Swift standard syntax for declaring generic type parameters for a method.
    }
}

The Swift syntax changes quickly, and what's here can quickly go out of date, but this guide is kept fairly up-to-date by Apple and shows the most up to date syntax for Generics used above ^.

斯威夫特语法变化很快,这里很快就会过时,但本指南是保持相当最新的苹果和显示了仿制药的最新语法上面使用^。

My answer pulls from a couple * questions/answers, used for example/syntax above ^. Source: (SO Source) (SO Source 2)

我的答案将从几个*问题/答案,例如使用以上^ /语法。资料来源:(来源)(来源二)

In summary, all the methods above can be combined, for a fully custom extension solution that has both generic functions/vars for all your Array types, while still having type-specific extension overrides.

综上所述,对于一个完全定制的扩展解决方案,可以将上面的所有方法组合在一起,该解决方案具有所有数组类型的通用函数/vars,同时仍然具有特定类型的扩展覆盖。

#2


7  

In where clause, you specify "If the Element type has these rules, consider this extension".

在where子句中,您指定“如果元素类型具有这些规则,请考虑此扩展”。

You don't need to implement all of the methods in all extensions.

您不需要在所有扩展中实现所有的方法。

For example:

例如:

  • You want to extend Array<Element> to generally have method foo(_:Element):

    要扩展数组 ,使其具有方法foo(_:Element):

    extension Array {
        func foo(bar: Element) { /*your code goes here */ }
    }
    
  • You want to extend Array<Element> where Element did implement Equatable (which includes Int,Double and ... or any structs/classes you've marked as Equatable):

    您希望扩展数组 ,其中元素实现了Equatable(其中包括Int、Double和……)或任何你标记为可等同的结构体/类):

    extension Array where Element: Equatable {
        func find(value: Element) -> Bool { 
            return index(of: value) != nil
        }
    }
    
  • You want to extend Sequence in cases that Element is Numeric, have get-only variable sum:

    如果元素是数值的,你想要扩展序列,有get-only变量和:

    extension Sequence where Element: Numeric {
        var sum: Element { 
            return reduce(0, +)
        }
    }
    
  • You want to extend Collection<Collection<Element: Equatable>> to have a method to compare to 2D Collections:

    您希望扩展Collection >,使其具有与2D Collections进行比较的方法:

    extension Collection
        where Iterator.Element: Collection, 
        Iterator.Element.Iterator.Element: Equatable {
    
        func compare(to: Self) -> Bool {
            let flattenSelf = self.reduce([], +)
            let flattenTo = to.reduce([], +)
    
            return flattenSelf.count == flattenTo.count &&
                zip(flattenSelf, flattenTo).reduce(true) { $0 && $1.0 == $1.1 }
        }
    }
    

You don't need to extend Array or collection to have methods like sort, find, etc... Most of these methods are already extended inside the compiler if your Element: Equatable or Element: Comparable. using map, filter and reduce you can achieve more complex structures with not much of a code.

您不需要扩展数组或集合来获得排序、查找等方法。如果您的元素:Equatable或元素:Comparable,那么大多数这些方法都已经在编译器中进行了扩展。使用map、filter和reduce,您可以实现更复杂的结构,而不需要太多代码。

#1


9  

As mentioned in the comments, one way to accomplish this is to create your own protocol that the types you want to cover adopt (in the comments someone called it Content, used below for this example) (from first source):

正如在评论中提到的,实现这一点的一种方法是创建您希望涵盖的类型所采用的自己的协议(在下面有人称之为Content的评论中,本例使用的是Content)(来自first source):

protocol Content {
    var hash: String { get }
}
extension Array where Element : Content {

    func filterWithId(id : String) -> [Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}

It seems, though, that the original question is mainly asking about generic extensions for arrays, which one comment says are not possible but 100% are possible in Swift (it's a big Swift feature, actually) (from second source).

不过,最初的问题似乎主要是关于数组的泛型扩展,有一条评论说这是不可能的,但在Swift中100%是可能的(实际上,这是Swift的一个重要特性)(来自第二源)。

For example, if you want to define a specific extension method for Ints only, you can do that:

例如,如果您想为int定义一个特定的扩展方法,您可以这样做:

extension Sequence where Iterator.Element == Int {
    var sum: Int {
        return reduce(0, +)
    }
}

It seems like the question's original requirements are extension methods that could be agnostic to data type and therefore should be kept in common. If I understand correctly, seems though that these data types in general have some conformance to Equatable and/or Hashable, which is the minimum requirement for this kind of generic-stuff to work. With this element conformance, though, this is possible as such:

这个问题的原始需求似乎是可与数据类型无关的扩展方法,因此应该保持一致。如果我理解正确的话,看起来这些数据类型一般都符合Equatable和/或Hashable,这是这类泛型工作的最低要求。但是,有了这个元素的一致性,这是可能的:

extension Sequence where Iterator.Element is Equatable {
    func extensionMethodName<T: Equatable>(_ input: [T], singleElement: T) -> [T] {
        // T is now a generic array of equatable items. You can implement whatever extension logic you need with these. 
        // I added different ways of passing in and returning this generic type, but the only thing that is likely going to be consistent is the `<T: Equatable>` which is Swift standard syntax for declaring generic type parameters for a method.
    }
}

The Swift syntax changes quickly, and what's here can quickly go out of date, but this guide is kept fairly up-to-date by Apple and shows the most up to date syntax for Generics used above ^.

斯威夫特语法变化很快,这里很快就会过时,但本指南是保持相当最新的苹果和显示了仿制药的最新语法上面使用^。

My answer pulls from a couple * questions/answers, used for example/syntax above ^. Source: (SO Source) (SO Source 2)

我的答案将从几个*问题/答案,例如使用以上^ /语法。资料来源:(来源)(来源二)

In summary, all the methods above can be combined, for a fully custom extension solution that has both generic functions/vars for all your Array types, while still having type-specific extension overrides.

综上所述,对于一个完全定制的扩展解决方案,可以将上面的所有方法组合在一起,该解决方案具有所有数组类型的通用函数/vars,同时仍然具有特定类型的扩展覆盖。

#2


7  

In where clause, you specify "If the Element type has these rules, consider this extension".

在where子句中,您指定“如果元素类型具有这些规则,请考虑此扩展”。

You don't need to implement all of the methods in all extensions.

您不需要在所有扩展中实现所有的方法。

For example:

例如:

  • You want to extend Array<Element> to generally have method foo(_:Element):

    要扩展数组 ,使其具有方法foo(_:Element):

    extension Array {
        func foo(bar: Element) { /*your code goes here */ }
    }
    
  • You want to extend Array<Element> where Element did implement Equatable (which includes Int,Double and ... or any structs/classes you've marked as Equatable):

    您希望扩展数组 ,其中元素实现了Equatable(其中包括Int、Double和……)或任何你标记为可等同的结构体/类):

    extension Array where Element: Equatable {
        func find(value: Element) -> Bool { 
            return index(of: value) != nil
        }
    }
    
  • You want to extend Sequence in cases that Element is Numeric, have get-only variable sum:

    如果元素是数值的,你想要扩展序列,有get-only变量和:

    extension Sequence where Element: Numeric {
        var sum: Element { 
            return reduce(0, +)
        }
    }
    
  • You want to extend Collection<Collection<Element: Equatable>> to have a method to compare to 2D Collections:

    您希望扩展Collection >,使其具有与2D Collections进行比较的方法:

    extension Collection
        where Iterator.Element: Collection, 
        Iterator.Element.Iterator.Element: Equatable {
    
        func compare(to: Self) -> Bool {
            let flattenSelf = self.reduce([], +)
            let flattenTo = to.reduce([], +)
    
            return flattenSelf.count == flattenTo.count &&
                zip(flattenSelf, flattenTo).reduce(true) { $0 && $1.0 == $1.1 }
        }
    }
    

You don't need to extend Array or collection to have methods like sort, find, etc... Most of these methods are already extended inside the compiler if your Element: Equatable or Element: Comparable. using map, filter and reduce you can achieve more complex structures with not much of a code.

您不需要扩展数组或集合来获得排序、查找等方法。如果您的元素:Equatable或元素:Comparable,那么大多数这些方法都已经在编译器中进行了扩展。使用map、filter和reduce,您可以实现更复杂的结构,而不需要太多代码。