Wie kann ich Swifts erweitern Array<T>
oder T[]
mit benutzerdefinierten Funktionsprogrammen tippen?
Das Durchsuchen der API-Dokumente von Swift zeigt, dass Array-Methoden eine Erweiterung von T[]
z.
extension T[] : ArrayType {
//...
init()
var count: Int { get }
var capacity: Int { get }
var isEmpty: Bool { get }
func copy() -> T[]
}
Beim Kopieren und Einfügen derselben Quelle und beim Ausprobieren von Variationen wie:
extension T[] : ArrayType {
func foo(){}
}
extension T[] {
func foo(){}
}
Es kann nicht mit dem Fehler erstellt werden:
Der Nenntyp
T[]
kann nicht erweitert werden
Die Verwendung der vollständigen Typdefinition schlägt fehl mit Use of undefined type 'T'
, dh:
extension Array<T> {
func foo(){}
}
Und es scheitert auch mit Array<T : Any>
und Array<String>
.
Mit Curiously Swift kann ich ein untypisiertes Array erweitern mit:
extension Array {
func each(fn: (Any) -> ()) {
for i in self {
fn(i)
}
}
}
Womit ich anrufen kann:
[1,2,3].each(println)
Ich kann jedoch keine richtige generische Typerweiterung erstellen, da der Typ verloren zu gehen scheint, wenn er durch die Methode fließt, z. B. wenn versucht wird, den integrierten Filter von Swift durch Folgendes zu ersetzen :
extension Array {
func find<T>(fn: (T) -> Bool) -> T[] {
var to = T[]()
for x in self {
let t = x as T
if fn(t) {
to += t
}
}
return to
}
}
Der Compiler behandelt es jedoch als untypisiert, wobei der Aufruf der Erweiterung weiterhin möglich ist mit:
["A","B","C"].find { $0 > "A" }
Und wenn Sie mit einem Debugger durchgehen, wird angezeigt, dass der Typ ist, Swift.String
aber es ist ein Build-Fehler, wenn Sie versuchen, wie ein String darauf zuzugreifen, ohne ihn String
zuerst zu übertragen, dh:
["A","B","C"].find { ($0 as String).compare("A") > 0 }
Weiß jemand, wie man eine typisierte Erweiterungsmethode richtig erstellt, die sich wie die integrierten Erweiterungen verhält?
extension T[]
Bit wird angezeigt, wenn Sie bei gedrückter Befehlstaste auf den Array-Typ in XCode klicken, aber keine Möglichkeit sehen, ihn ohne Fehler zu implementieren.<T>
aus der Methodensignatur .Antworten:
Für die Erweiterung typisierter Arrays um Klassen funktioniert das Folgende für mich (Swift 2.2 ). Beispiel: Sortieren eines typisierten Arrays:
Der Versuch, dies mit einer Struktur oder Typealias zu tun , führt zu einem Fehler:
Update :
So erweitern Sie typisierten Arrays mit nicht-Klassen verwenden Sie die folgende Vorgehensweise:
In Swift 3 wurden einige Typen umbenannt:
quelle
[Iterator.Element]
?Nach einer Weile, in der verschiedene Dinge ausprobiert wurden, scheint die Lösung Folgendes
<T>
aus der Signatur zu entfernen :Was jetzt wie vorgesehen ohne Buildfehler funktioniert:
quelle
filter
Funktion:let x = ["A","B","C","X”].filter { $0.compare("A") > 0 }
filter
ist funktional äquivalent zu Ihremfind
, dh das Ergebnis der Funktion ist das gleiche. Wenn Ihr Filterverschluss Nebenwirkungen hat, werden Ihnen die Ergebnisse möglicherweise nicht gefallen.filter
.filter
,map
undreduce
Funktionen stammen, sind Funktionen für ihre Rückgabewerte ausgeführt. Im Gegensatz dazu ist dieeach
oben definierte Funktion ein Beispiel für eine Funktion, die wegen ihrer Nebenwirkung ausgeführt wird, da sie nichts zurückgibt. Ich denke, wir können uns darauf einigen, dass die aktuelle Swift-Implementierung nicht ideal ist und die Dokumentation nichts über ihre Laufzeitmerkmale aussagt.Erweitern Sie alle Typen:
Erweitern Sie einige Typen:
Erweitern Sie einen bestimmten Typ:
quelle
Ich hatte ein ähnliches Problem - wollte das allgemeine Array mit einer swap () -Methode erweitern, die ein Argument des gleichen Typs wie das Array annehmen sollte. Aber wie geben Sie den generischen Typ an? Ich fand durch Versuch und Irrtum heraus, dass das Folgende funktionierte:
Der Schlüssel dazu war das Wort "Element". Beachten Sie, dass ich diesen Typ nirgendwo definiert habe, er scheint automatisch im Kontext der Array-Erweiterung zu existieren und verweist auf den Typ der Array-Elemente.
Ich bin nicht 100% sicher, was dort vor sich geht, aber ich denke, das liegt wahrscheinlich daran, dass 'Element' ein zugeordneter Typ des Arrays ist (siehe 'Zugehörige Typen' hier https://developer.apple.com/library/ios/documentation /Swift/Conceptual/Swift_Programming_Language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-ID189 )
In der Array-Strukturreferenz ( https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Array_Structure/index.html#//apple_ref/swift) kann ich jedoch keine Referenz dazu sehen / struct / s: Sa ) ... also bin ich mir immer noch ein bisschen unsicher.
quelle
Array
ist ein generischer Typ:Array<Element>
(siehe swiftdoc.org/v2.1/type/Array ),Element
ist ein Platzhalter für den enthaltenen Typ. Zum Beispiel:var myArray = [Foo]()
bedeutet, dassmyArray
nur Typ enthalten wirdFoo
.Foo
In diesem Fall wird der generische Platzhalter "zugeordnet"Element
. Wenn Sie das allgemeine Verhalten von Array (über die Erweiterung) ändern möchten, verwenden Sie den generischen PlatzhalterElement
und keinen konkreten Typ (wie Foo).Verwenden von Swift 2.2 : Beim Versuch, Duplikate aus einem Array von Zeichenfolgen zu entfernen, ist ein ähnliches Problem aufgetreten. Ich konnte der Array-Klasse eine Erweiterung hinzufügen, die genau das tut, was ich wollte.
Durch Hinzufügen dieser beiden Methoden zur Array-Klasse kann ich eine der beiden Methoden in einem Array aufrufen und Duplikate erfolgreich entfernen. Beachten Sie, dass die Elemente im Array dem Hashable-Protokoll entsprechen müssen. Jetzt kann ich das machen:
quelle
let deDuped = Set(dupes)
, was Sie in einer zerstörungsfreien Methode zurückgeben könnten, die aufgerufen wirdtoSet
, solange Sie mit derWenn Sie mehr über das Erweitern von Arrays und andere Arten von eingebauten Klassen erfahren möchten, überprüfen Sie den Code in diesem Github-Repo unter https://github.com/ankurp/Cent
Ab Xcode 6.1 lautet die Syntax zum Erweitern von Arrays wie folgt
quelle
Ich habe mir die Swift 2-Standardbibliotheksheader angesehen, und hier ist der Prototyp für die Filterfunktion, der es ziemlich offensichtlich macht, wie Sie Ihre eigenen rollen.
Es handelt sich nicht um eine Erweiterung von Array, sondern um CollectionType. Daher gilt dieselbe Methode für andere Sammlungstypen. @noescape bedeutet, dass der übergebene Block den Bereich der Filterfunktion nicht verlässt, was einige Optimierungen ermöglicht. Selbst mit einem Großbuchstaben S ist die Klasse, die wir erweitern. Self.Generator ist ein Iterator, der die Objekte in der Sammlung durchläuft, und Self.Generator.Element ist der Typ der Objekte, z. B. für ein Array [Int?]. Self.Generator.Element wäre Int?.
Alles in allem kann diese Filtermethode auf jeden CollectionType angewendet werden. Sie benötigt einen Filterblock, der ein Element der Collection übernimmt und einen Bool zurückgibt, und ein Array des ursprünglichen Typs. Wenn ich dies zusammenstelle, ist hier eine Methode, die ich nützlich finde: Sie kombiniert Map und Filter, indem sie einen Block verwendet, der ein Auflistungselement einem optionalen Wert zuordnet, und ein Array dieser optionalen Werte zurückgibt, die nicht Null sind.
quelle
quelle
( Swift 2.x )
Sie können das Array auch so erweitern, dass es einem Protokoll entspricht, das Blue-Rpints für generische Typmethoden enthält, z. B. ein Protokoll, das Ihre benutzerdefinierten funktionalen Dienstprogramme für alle generischen Array-Elemente enthält, die einer Typbeschränkung entsprechen, z. B. Protokoll
MyTypes
. Der Vorteil dieses Ansatzes besteht darin, dass Sie Funktionen mit generischen Array-Argumenten schreiben können, mit der Einschränkung, dass diese Array-Argumente Ihrem Protokoll für benutzerdefinierte Funktionsdienstprogramme entsprechen müssen, zMyFunctionalUtils
. B. Protokoll .Sie können dieses Verhalten entweder implizit erhalten, indem Sie die Array-Elemente auf "Typ" beschränken
MyTypes
, oder - wie ich in der unten beschriebenen Methode zeigen werde - ganz klar und explizit, indem Sie den Header Ihrer generischen Array-Funktionen diese Eingabearrays direkt anzeigen lassen entsprichtMyFunctionalUtils
.Wir beginnen mit Protokollen
MyTypes
zur Verwendung als Typeinschränkung. die Typen erweitern Sie dieses Protokoll in Ihrem Generika passen wollen (Beispiel erstreckt sich unter GrundtypenInt
undDouble
sowie einen benutzerdefinierten TypMyCustomType
)Protokoll
MyFunctionalUtils
(enthält Blaupausen unserer zusätzlichen Dienstprogramme für generische Array-Funktionen) und danach die Erweiterung von Array umMyFunctionalUtils
; Implementierung von Blaupausenverfahren:Schließlich Tests und zwei Beispiele, die eine Funktion zeigen, die generische Arrays mit den folgenden Fällen verwendet
Zeigen der impliziten Behauptung, dass die Array-Parameter dem Protokoll 'MyFunctionalUtils' entsprechen, über einen Typ, der die Arrays-Elemente auf 'MyTypes' (Funktion
bar1
) beschränkt.Es wird explizit angezeigt, dass die Array-Parameter dem Protokoll 'MyFunctionalUtils' (Funktion
bar2
) entsprechen.Der Test und die Beispiele folgen:
quelle
quelle
$0 as! Double
) kämpfen gegen das Typensystem von Swift und vereiteln meiner Meinung nach auch den Zweck der OP-Frage. Auf diese Weise verlieren Sie jegliches Potenzial für Compiler-Optimierungen für die Berechnungen, die Sie tatsächlich durchführen möchten, und Sie verschmutzen den Namespace des Arrays mit bedeutungslosen Funktionen (warum sollten Sie .calculateMedian () in einem Array von UIViews sehen wollen, oder von irgendetwas anderem als Double?). Es gibt einen besseren Weg.extension CollectionType where Generator.Element == Double {}