Kann ich eine Array-Erweiterung erstellen, die z. B. nur für Strings gilt?Ist es möglich, eine Array-Erweiterung in Swift zu machen, die auf eine Klasse beschränkt ist?
Antwort
Ab Swift 2, das jetzt mit Protokollerweiterungen werden kann , erreicht, die zu konformen Typen Verfahren und Eigentum Implementierungen (gegebenenfalls mit zusätzlichen Einschränkungen eingeschränkt).
Ein einfaches Beispiel: Definieren ein Verfahren für alle Arten konformen zu SequenceType
(wie Array
), wo das Sequenzelement ist ein String
:
extension SequenceType where Generator.Element == String {
func joined() -> String {
return "".join(self)
}
}
let a = ["foo", "bar"].joined()
print(a) // foobar
Die Erweiterungsmethode nicht direkt für struct Array
definiert werden kann, aber nur, für alle Typen konform zu einigen Protokoll (mit optionalen Einschränkungen). So muss man ein Protokoll finden, dem Array
entspricht und das alle notwendigen Methoden bereitstellt. Im obigen Beispiel ist das SequenceType
.
Ein anderes Beispiel (eine Variation von How do I insert an element at the correct position into 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
Hier wird das Verfahren als eine Erweiterung CollectionType
definiert ist, weil Subskript Zugriff auf die Elemente benötigt wird, und die Elemente werden Comparable
sein erforderlich.
Sie können 'Index == Int' zu' Index: RandomAccessIndexType' mit einigen kleineren Änderungen, z. 'startIndex' anstelle von' 0', 'endIndex.predecessor()', 'let mid = lo.advancedBy (lo.distanceTo (hi)/2)' plus einen vorzeitigen Bail-On 'isEmpty'. Würde bedeuten, dass es zum Beispiel mit 'String.UTF16View' arbeiten würde, das zufällig, aber nicht ganz indiziert ist. –
@AirspeedVelocity: Fertig :) –
UPDATE: Bitte lesen Sie Martins Antwort unten für Swift 2.0 Updates. (Ich kann diese Antwort nicht löschen, da es akzeptiert wird, wenn Doug kann Martins Antwort akzeptieren, ich werde diese eine löschen zukünftige Verwirrung zu vermeiden.)
Dies hat mehrere Male in den Foren kommen, und Die Antwort ist nein, das kannst du heute nicht tun, aber sie verstehen, dass es ein Problem ist und sie hoffen, dass es in Zukunft verbessert wird. Es gibt Dinge, die sie zur stdlib hinzufügen möchten, die das auch brauchen. Deshalb gibt es so viele kostenlose Funktionen wie stdlib. Die meisten von ihnen sind Work-arounds für entweder dieses Problem oder das Problem "keine Standardimplementierung" (d. H. "Merkmale" oder "Mixins").
Danke, es schien wie eine seltsame Unterlassung. Wird meine Daumen drücken. –
Möchte diesen für 2.0 bearbeiten, insb. wie Dupes sich darauf beziehen. –
Sie haben trotz vieler Anfragen in Kommentaren immer noch keinen Anwendungsfall angegeben, daher ist es schwer zu wissen, wonach Sie suchen. Aber, wie ich bereits in einem Kommentar gesagt habe (und Rob hat in einer Antwort gesagt), werden Sie es nicht wörtlich bekommen; Erweiterungen funktionieren auf diese Weise nicht (im Moment).
Wie ich in einem Kommentar sagte, was ich tun würde, ist das Array in eine Struktur zu wickeln. Jetzt schützt und schützt die Struktur den Typ der Zeichenfolge und wir haben eine Kapselung. Hier ist ein Beispiel, obwohl man natürlich im Auge behalten muß, dass Sie keinen Hinweis auf die Art der Sache gegeben haben würden Sie wirklich zu tun, so dass dies möglicherweise nicht direkt befriedigend:
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}
}
}
Und hier ist, wie zu nennen:
let pepboys = ["Manny", "Moe", "Jack"]
var saw = StringArrayWrapper(pepboys)
saw.upcase()
println(saw)
So haben wir unser String-Array in eine Welt effektiv isoliert, wo wir es mit Funktionen bewaffnen können, die nur für String-Arrays anwenden. Wenn pepboys
kein Zeichenfolgenarray wäre, hätten wir es nicht zuerst in einen StringArrayWrapper einschließen können.
Wenn das Array wahrscheinlich groß ist, ist eine Klasse möglicherweise besser als eine Struktur, so dass Ihnen Pass-by-Reference garantiert ist. Aus diesem Grund hänge ich oft große Arrays in Klassen, so dass man sie nicht kopieren muss. – matt
Swift verwendet Copy-on-Write für Pass-by-Value, daher sollten in den meisten Fällen keine großen Kosten bei der Übergabe großer Arrays entstehen. Wenn Sie große Kosten finden, sollten Sie ein Radar öffnen. Apple hat ausdrücklich darauf hingewiesen, dass Sie aus Leistungsgründen nicht versuchen sollten, dem Kopieren auszuweichen. Siehe den Hinweis am Ende von https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html –
@RobNapier Die Eigenschaft hier ist eine 'var' und das Beispiel geht davon aus, dass dies der Fall ist geschrieben werden. – matt
Dies wurde bereits von den drei Weisen oben beantwortet ;-), aber ich biete demütig eine Verallgemeinerung von @ Martins Antwort an. Wir können eine beliebige Klasse tarnen, indem wir das Protokoll "marker" verwenden, das nur für die Klasse implementiert ist, auf die wir zielen wollen. Ie. man muss nicht finden ein Protokoll per se, aber kann ein triviales für die Verwendung in der Ausrichtung der gewünschten Klasse erstellen.
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. Ist es möglich, eine Google/Yahoo/Bing-Suche durchzuführen, die auf die Metadaten "description" beschränkt ist?
- 2. Ist es möglich, eine Klasse in Java zu klonen?
- 3. Ist es möglich, in TFS eine "Geschichte zerstören" zu machen?
- 4. Ist es möglich, eine "Freund-Klasse" in C++ zu erstellen?
- 5. Ist es möglich, eine Abfrage wie diese zu machen?
- 6. Ist es möglich, eine MD-Taste kleiner zu machen?
- 7. Javascript - Ist es möglich, eine Schleife mit Funktionen zu machen?
- 8. Ist es möglich, eine Unterabfrage mit Sequelize.js zu machen?
- 9. Swift: ist es möglich,
- 10. Warum ist es möglich, eine generische Klasse zu generieren?
- 11. Ist es möglich, eine Variable für eine bestimmte iOS-Version in Swift zu definieren? Auf Klassenebene
- 12. Ist es möglich, eine Klasse mit einer Zeichenfolge zu instanziieren?
- 13. Es ist möglich, SpeechRecognizer schneller zu machen?
- 14. Ist es möglich, eine private Klasse zu haben?
- 15. Ist es möglich, eine ListViewGroup zu erstellen
- 16. Ist es möglich, Schriftarten skalierbar zu machen?
- 17. In Scala ist es für eine Eigenschaft möglich, eine Klasse zu erweitern, die Parameter benötigt?
- 18. ist es möglich, eine Core-Klasse in WordPress
- 19. Ist es möglich, eine Klasse Paket-private für Testzwecke
- 20. Ist es möglich, eine FLA über die Befehlszeile zu veröffentlichen?
- 21. Ist es für eine Klasse möglich, ein Parameterpaket verfügbar zu machen?
- 22. Ist es möglich, [XmlAttribute] als Standard für eine Klasse festzulegen?
- 23. Ist es möglich, anonyme Klasse ohne äußere Klasse zu serialisieren?
- 24. Ist es eine gute Idee, eine Python-Klasse zu hashen?
- 25. Ist es möglich, eingebettete Generika in Swift zu konstruieren?
- 26. Swift: ist es richtig, allen UINavigationControllern eine benutzerdefinierte Klasse zuzuweisen?
- 27. Ist es möglich, Berechtigungen Dateien in Swift
- 28. Ist es möglich, eine App auf live.com zu hosten?
- 29. Ist es möglich, einen Zeiger auf eine Referenz zu definieren?
- 30. Warum ist es möglich, auf eine Rx zu warten?
Nicht sicher, was Sie meinen - können Sie mehr über Ihre Absicht sagen? Vielleicht ein Beispiel? – dpassage
@ dpassage Sie können Dinge mit der Anforderung erweitern, dass die erweiterten Klassen ein Protokoll einhalten (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html), ich bin neugierig wenn Sie es weiter auf eine Klasse beschränken können, so dass meine Erweiterung in Swift nur für String-Arrays gilt. –
Aber beschreiben Sie, was Sie eine solche Erweiterung zu _do_ wollen. Geht es nur um eine Funktion? Definieren Sie dann eine globale generische Funktion. Geben Sie einen tatsächlichen Anwendungsfall für das, was Sie erreichen möchten. – matt