Is it possible to make an Array extension in Swift that is limited to one class?

Can I make an array extension that applies, for example, only to strings?

+6
source share
4 answers

Compared to Swift 2, this can now be achieved with protocol extensions that provide methods and properties for the corresponding types (optionally limited by additional restrictions).

A simple example: Define a method for all types matching before SequenceType (e.g. Array ), where the sequence element is String :

 extension SequenceType where Generator.Element == String { func joined() -> String { return "".join(self) } } let a = ["foo", "bar"].joined() print(a) // foobar 

The extension method cannot be defined for struct Array directly, but only for all types in accordance with some protocol (with additional restrictions). So I have to find the protocol that Array corresponds to and which provides all the necessary methods. In the above example, this is a SequenceType .

Another example (the option How to insert an element at the desired position in a sorted array in Swift? ):

 extension CollectionType where Generator.Element : Comparable, Index : RandomAccessIndexType { typealias T = Generator.Element func insertionIndexOf(elem: T) -> Index { var lo = self.startIndex var hi = self.endIndex while lo != hi { // mid = lo + (hi - 1 - lo)/2 let mid = lo.advancedBy(lo.distanceTo(hi.predecessor())/2) if self[mid] < elem { lo = mid + 1 } else if elem < self[mid] { hi = mid } else { return mid // found at position `mid` } } return lo // not found, would be inserted at position `lo` } } let ar = [1, 3, 5, 7] let pos = ar.insertionIndexOf(6) print(pos) // 3 

Here, the method is defined as an extension to CollectionType , because index access to the elements is required, and the elements must be Comparable .

+12
source

UPDATE: see Martin's answer below for Swift 2.0 updates. (I cannot delete this answer because it is accepted, if Doug can accept Martin's answer, I will delete it to avoid any confusion in the future.)


This has appeared several times on the forums, and the answer is no, you cannot do it today, but they understand that this is a problem, and they hope to improve it in the future. There are things that they would like to add to stdlib that also need this. This is why so many free functions are stdlib. Most of them are workarounds for this problem or problem without a default implementation (ie, Traits or mixins).

+5
source

The three wise men above have already answered this ;-), but I humbly propose a generalization of @ Martin's answer. We can target an arbitrary class using the protocol "marker", which is implemented only in the class that we want to configure. I.e. you donโ€™t need to look for a protocol, but it can create a trivial one for use in targeting the desired class.

 protocol TargetType {} extension Array:TargetType {} struct Foo { var name:String } extension CollectionType where Self:TargetType, Generator.Element == Foo { func byName() -> [Foo] { return sort { l, r in l.name < r.name } } } let foos:[Foo] = ["c", "b", "a"].map { s in Foo(name: s) } print(foos.byName()) 
+1
source

You still haven't used precedents, despite the many requests in the comments, so it's hard for you to understand what you need. But, as I said in the comment (and Rob said in response), you wonโ€™t get it literally; extensions do not work this way (at the moment).

As I said in a comment, what I would do is wrap an array in a structure. Now the structure protects and guarantees the type of the string, and we have encapsulation. Here is an example, although, of course, you must remember that you did not indicate what you really would like to do, so this may not be entirely satisfactory:

 struct StringArrayWrapper : Printable { private var arr : [String] var description : String { return self.arr.description } init(_ arr:[String]) { self.arr = arr } mutating func upcase() { self.arr = self.arr.map {$0.uppercaseString} } } 

And here's what to call it:

  let pepboys = ["Manny", "Moe", "Jack"] var saw = StringArrayWrapper(pepboys) saw.upcase() println(saw) 

Thus, we effectively isolated our array of strings in a world where we can arm it with functions that apply only to string arrays. If pepboys were not a string array, we could not wrap it in a StringArrayWrapper to begin with.

0
source

Source: https://habr.com/ru/post/979259/


All Articles