Das Veränderbarkeitsattribut wird in einem Speicher (Konstante oder Variable) und nicht in einem Typ markiert. Sie können sich vorstellen, dass struct zwei Modi hat: veränderlich und unveränderlich . Wenn Sie einem unveränderlichen Speicher einen Strukturwert zuweisen (wir nennen ihn let
oder eine Konstante in Swift), wird der Wert unveränderlich und Sie können keinen Status im Wert ändern. (einschließlich des Aufrufs einer mutierenden Methode)
Wenn der Wert einem veränderlichen Speicher zugewiesen ist (wir nennen ihn var
oder eine Variable in Swift), können Sie den Status ändern, und das Aufrufen der Mutationsmethode ist zulässig.
Außerdem haben Klassen diesen unveränderlichen / veränderlichen Modus nicht. IMO, dies liegt daran, dass Klassen normalerweise verwendet werden, um referenzierbare Entitäten darzustellen . Und referenzierbare Entitäten sind normalerweise veränderbar, da es sehr schwierig ist, Referenzdiagramme von Entitäten auf unveränderliche Weise mit angemessener Leistung zu erstellen und zu verwalten. Sie können diese Funktion später hinzufügen, aber zumindest jetzt nicht.
Für Objective-C-Programmierer sind veränderbare / unveränderliche Konzepte sehr vertraut. In Objective-C hatten wir zwei getrennte Klassen für jedes Konzept, aber in Swift können Sie dies mit einer Struktur tun. Halbe Arbeit.
Für C / C ++ - Programmierer ist dies ebenfalls ein sehr bekanntes Konzept. Dies ist genau das, was const
Schlüsselwörter in C / C ++ tun.
Auch der unveränderliche Wert kann sehr schön optimiert werden. Theoretisch kann der Swift-Compiler (oder LLVM) eine Kopierelision für übergebene Werte durchführen let
, genau wie in C ++. Wenn Sie unveränderliche Strukturen mit Bedacht verwenden, übertrifft sie neu gezählte Klassen.
Aktualisieren
Da @Joseph behauptete, dies biete keinen Grund , füge ich etwas mehr hinzu.
Strukturen haben zwei Arten von Methoden. einfache und mutierende Methoden. Eine einfache Methode impliziert eine unveränderliche (oder nicht mutierende) Methode . Diese Trennung dient nur zur Unterstützung der unveränderlichen Semantik. Ein Objekt im unveränderlichen Modus sollte seinen Status überhaupt nicht ändern.
Dann müssen unveränderliche Methoden diese semantische Unveränderlichkeit gewährleisten . Das heißt, es sollte keinen internen Wert ändern. Der Compiler verbietet daher alle Statusänderungen von sich selbst in einer unveränderlichen Methode. Im Gegensatz dazu können Mutationsmethoden Zustände ändern.
Und dann haben Sie vielleicht eine Frage, warum unveränderlich die Standardeinstellung ist? Das liegt daran, dass es sehr schwierig ist, den zukünftigen Zustand mutierender Werte vorherzusagen, und dies wird normalerweise zur Hauptursache für Kopfschmerzen und Fehler. Viele Menschen waren sich einig, dass die Lösung veränderbare Dinge vermeidet und dann unveränderlich standardmäßig jahrzehntelang in den Sprachen der C / C ++ - Familie und ihren Ableitungen ganz oben auf der Wunschliste stand.
Weitere Informationen finden Sie unter rein funktionaler Stil . Wie auch immer, wir brauchen immer noch veränderbare Dinge, weil unveränderliche Dinge einige Schwächen haben und die Diskussion darüber nicht zum Thema zu gehören scheint.
Ich hoffe das hilft.
const
der Methode explizit ein hinzufügen , wenn Sie möchten, dass sie eine 'const this' hat und für konstante Instanzen zulässig ist (normale Methoden können nicht verwendet werden, wenn die Instanz const ist). Swift macht dasselbe mit dem entgegengesetzten Standard: Eine Methode hat standardmäßig eine 'const this' und Sie markieren sie anders, wenn sie für konstante Instanzen verboten werden muss.Eine Struktur ist eine Aggregation von Feldern. Wenn eine bestimmte Strukturinstanz veränderbar ist, sind ihre Felder veränderbar. Wenn eine Instanz unveränderlich ist, sind ihre Felder unveränderlich. Ein Strukturtyp muss daher für die Möglichkeit vorbereitet werden, dass die Felder einer bestimmten Instanz veränderlich oder unveränderlich sein können.
Damit eine Strukturmethode die Felder der zugrunde liegenden Struktur mutieren kann, müssen diese Felder veränderbar sein. Wenn eine Methode, die Felder der zugrunde liegenden Struktur mutiert, für eine unveränderliche Struktur aufgerufen wird, würde sie versuchen, unveränderliche Felder zu mutieren. Da daraus nichts Gutes werden konnte, muss eine solche Anrufung verboten werden.
Um dies zu erreichen, unterteilt Swift Strukturmethoden in zwei Kategorien: diejenigen, die die zugrunde liegende Struktur ändern und daher möglicherweise nur für veränderbare Strukturinstanzen aufgerufen werden, und diejenigen, die die zugrunde liegende Struktur nicht ändern und daher sowohl für veränderbare als auch unveränderliche Instanzen aufrufbar sein sollten . Die letztere Verwendung ist wahrscheinlich die häufigere und daher die Standardeinstellung.
Im Vergleich dazu bietet .NET derzeit (noch!) Keine Möglichkeit, Strukturmethoden, die die Struktur ändern, von solchen zu unterscheiden, die dies nicht tun. Wenn Sie stattdessen eine Strukturmethode für eine unveränderliche Strukturinstanz aufrufen, erstellt der Compiler eine veränderbare Kopie der Strukturinstanz, lässt die Methode damit tun, was sie will, und verwirft die Kopie, wenn die Methode fertig ist. Dies hat zur Folge, dass der Compiler gezwungen wird, Zeit mit dem Kopieren der Struktur zu verschwenden, unabhängig davon, ob die Methode sie ändert oder nicht, obwohl das Hinzufügen des Kopiervorgangs fast nie semantisch inkorrekten Code in semantisch korrekten Code umwandelt. Es wird lediglich dazu führen, dass Code, der auf eine Weise semantisch falsch ist (Ändern eines "unveränderlichen" Werts), auf andere Weise falsch ist (Code kann glauben, dass er eine Struktur ändert). aber die versuchten Änderungen verwerfen). Durch das Zulassen, dass Strukturmethoden angeben, ob sie die zugrunde liegende Struktur ändern, kann die Notwendigkeit eines nutzlosen Kopiervorgangs beseitigt werden, und es wird auch sichergestellt, dass versuchte fehlerhafte Verwendung gekennzeichnet wird.
quelle
Achtung: Laienbedingungen voraus.
Diese Erklärung ist auf der kleinsten Codeebene nicht streng korrekt. Es wurde jedoch von einem Mann überprüft, der tatsächlich an Swift arbeitet, und er sagte, es sei gut genug als grundlegende Erklärung.
Deshalb möchte ich versuchen, die Frage nach dem "Warum" einfach und direkt zu beantworten.
Um genau zu sein: Warum müssen wir Strukturfunktionen so markieren,
mutating
als könnten wir Strukturparameter ändern, ohne Schlüsselwörter zu ändern?Das große Ganze hat also viel mit der Philosophie zu tun, die Swift schnell hält .
Man könnte es sich wie das Problem vorstellen, tatsächliche physische Adressen zu verwalten. Wenn Sie Ihre Adresse ändern und viele Personen Ihre aktuelle Adresse haben, müssen Sie alle benachrichtigen, dass Sie umgezogen sind. Aber wenn niemand Ihre aktuelle Adresse hat, können Sie einfach umziehen, wohin Sie wollen, und niemand muss es wissen.
In dieser Situation ist Swift wie die Post. Wenn sich viele Menschen mit vielen Kontakten viel bewegen, hat dies einen sehr hohen Overhead. Für die Bearbeitung all dieser Benachrichtigungen muss eine große Anzahl von Mitarbeitern bezahlt werden, und der Vorgang nimmt viel Zeit und Mühe in Anspruch. Deshalb ist Swifts idealer Zustand, dass jeder in seiner Stadt so wenig Kontakte wie möglich hat. Dann braucht es kein großes Personal, um Adressänderungen zu handhaben, und alles andere kann schneller und besser erledigt werden.
Dies ist auch der Grund, warum Swift-Leute alle von Werttypen im Vergleich zu Referenztypen schwärmen. Referenztypen bilden von Natur aus überall "Kontakte", und Werttypen benötigen normalerweise nicht mehr als ein Paar. Werttypen sind "Swift" -er.
Also zurück zum kleinen Bild :
structs
. Strukturen sind in Swift eine große Sache, da sie die meisten Aufgaben von Objekten ausführen können, aber sie sind Werttypen.Setzen wir die physikalische Adressanalogie fort, indem wir uns eine vorstellen
misterStruct
, in der wir lebensomeObjectVille
. Die Analogie wird hier ein wenig verwirrt, aber ich denke, es ist immer noch hilfreich.Um
struct
alsomisterStruct
das Ändern einer Variablen auf a zu modellieren , haben wir beispielsweise grünes Haar und erhalten den Befehl, auf blaues Haar umzuschalten. Die Analogie wird, wie ich bereits sagte, verwirrt, aber irgendwie passiert, dass anstatt diemisterStruct
Haare zu wechseln , die alte Person auszieht und eine neue Person mit blauen Haaren einzieht und diese neue Person beginnt, sich selbst anzurufenmisterStruct
. Niemand muss eine Benachrichtigung über eine Adressänderung erhalten, aber wenn sich jemand diese Adresse ansieht, sieht er einen Mann mit blauen Haaren.Lassen Sie uns nun modellieren, was passiert, wenn Sie eine Funktion auf a aufrufen
struct
. In diesem Fall ist esmisterStruct
so, als würde man eine Bestellung wie erhaltenchangeYourHairBlue()
. Also gibt die Post die Anweisung:misterStruct
"Ändere deine Haare in Blau und sag mir, wenn du fertig bist."Wenn er der gleichen Routine wie zuvor folgt und das tut, was er getan hat, als die Variable direkt geändert wurde,
misterStruct
wird er aus seinem eigenen Haus ausziehen und eine neue Person mit blauen Haaren hinzuziehen. Aber das ist das Problem.Der Befehl lautete: "Ändere deine Haare in Blau und sag mir, wann du fertig bist", aber es ist der Grüne, der diesen Befehl erhalten hat. Nachdem der Blaue eingezogen ist, muss noch eine Benachrichtigung "Job abgeschlossen" zurückgesendet werden. Aber der Blaue weiß nichts davon.
[Um diese Analogie wirklich zu etwas Schrecklichem zu machen, passierte dem grünhaarigen Mann technisch gesehen, dass er nach seinem Auszug sofort Selbstmord begangen hat. Also er niemanden mitteilen kann , dass die Aufgabe abgeschlossen ist entweder! ]]
Um dieses Problem zu vermeiden , muss Swift nur in solchen Fällen direkt zum Haus unter dieser Adresse gehen und tatsächlich die Haare des aktuellen Bewohners wechseln . Das ist ein ganz anderer Prozess als nur einen neuen Mann einzusenden.
Und deshalb möchte Swift, dass wir das
mutating
Schlüsselwort verwenden!Das Endergebnis sieht für alles, was sich auf die Struktur beziehen muss, gleich aus: Der Bewohner des Hauses hat jetzt blaue Haare. Aber die Prozesse, um dies zu erreichen, sind tatsächlich völlig anders. Es sieht so aus, als würde es dasselbe tun, aber es macht etwas ganz anderes. Es macht etwas, was Swift-Strukturen im Allgemeinen niemals tun.
Um dem armen Compiler ein wenig Hilfe zu geben und ihn nicht dazu zu bringen, herauszufinden, ob eine Funktion die für jede einzelne Strukturfunktion selbst mutiert
struct
oder nicht , werden wir gebeten, Mitleid zu haben und dasmutating
Schlüsselwort zu verwenden.Im Wesentlichen müssen wir alle unseren Beitrag leisten, damit Swift schnell bleibt. :) :)
BEARBEITEN:
Hey Dude / Dudette, die mich herabgestimmt hat, ich habe meine Antwort einfach komplett neu geschrieben. Wenn es besser zu Ihnen passt, werden Sie dann die Ablehnung entfernen?
quelle
Schnelle Strukturen können entweder als Konstanten (via
let
) oder als Variablen (viavar
) instanziiert werden.Betrachten Sie Swifts
Array
Struktur (ja, es ist eine Struktur).Warum funktionierte der Anhang nicht mit den Planetennamen? Weil Anhängen mit dem
mutating
Schlüsselwort markiert ist . Und daplanetNames
mit deklariert wurdelet
, sind alle so gekennzeichneten Methoden tabu.In Ihrem Beispiel kann der Compiler feststellen, dass Sie die Struktur ändern, indem Sie einer oder mehreren ihrer Eigenschaften außerhalb von eine zuweisen
init
. Wenn Sie Ihren Code ein wenig ändern, werden Sie das sehenx
undy
sind außerhalb der Struktur nicht immer zugänglich. Beachten Sie dielet
in der ersten Zeile.quelle
Betrachten Sie eine Analogie zu C ++. Eine struct-Methode in Swift ist
mutating
/ not-mutating
analog zu einer Methode in C ++, die non-const
/ istconst
. Eineconst
in C ++ markierte Methode kann die Struktur ebenfalls nicht mutieren.In C ++ können Sie auch "eine Variable von außerhalb der Struktur ändern" - allerdings nur, wenn Sie eine
const
Variable ohne Struktur haben. Wenn Sie eineconst
Strukturvariable haben, können Sie keine Variable zuweisen und auch keine Nichtmethode aufrufenconst
. Ebenso können Sie in Swift eine Eigenschaft einer Struktur nur ändern, wenn die Strukturvariable keine Konstante ist. Wenn Sie eine Strukturkonstante haben, können Sie keiner Eigenschaft zuweisen und auch keinemutating
Methode aufrufen .quelle
Ich habe mich das Gleiche gefragt, als ich angefangen habe, Swift zu lernen, und jede dieser Antworten, obwohl ich vielleicht einige Erkenntnisse hinzufüge, ist für sich genommen etwas wortreich und verwirrend. Ich denke, die Antwort auf Ihre Frage ist eigentlich ziemlich einfach ...
Die in Ihrer Struktur definierte Mutationsmethode möchte die Berechtigung, jede einzelne Instanz von sich selbst zu ändern, die in Zukunft jemals erstellt wird. Was ist, wenn eine dieser Instanzen einer unveränderlichen Konstante mit zugewiesen wird
let
? Oh oh. Um Sie vor sich selbst zu schützen (und um den Editor und den Compiler wissen zu lassen, was Sie versuchen ), müssen Sie explizit angeben, wenn Sie einer Instanzmethode diese Art von Leistung verleihen möchten.Im Gegensatz dazu wird die Einstellung einer Eigenschaft von außerhalb Ihrer Struktur auf eine bekannte Instanz dieser Struktur angewendet. Wenn es einer Konstante zugewiesen ist, informiert Sie Xcode, sobald Sie den Methodenaufruf eingegeben haben.
Dies ist eines der Dinge, die ich an Swift liebe, wenn ich anfange, es mehr zu verwenden - ich werde beim Tippen auf Fehler aufmerksam gemacht. Sicher übertrifft die Fehlerbehebung bei obskuren JavaScript-Fehlern!
quelle
SWIFT: Verwendung der Mutationsfunktion in Strukturen
Schnelle Programmierer haben Structs so entwickelt, dass die Eigenschaften innerhalb von Struct-Methoden nicht geändert werden können. Überprüfen Sie beispielsweise den unten angegebenen Code
Bei der Ausführung des obigen Codes wird eine Fehlermeldung angezeigt, da wir versuchen, der Immobilienpopulation der Strukturstadt einen neuen Wert zuzuweisen. Standardmäßig können Structs-Eigenschaften nicht innerhalb ihrer eigenen Methoden mutiert werden. So haben Apple-Entwickler es erstellt, sodass die Strukturen standardmäßig statisch sind.
Wie lösen wir das? Was ist die Alternative?
Mutierendes Schlüsselwort:
Durch das Deklarieren der Funktion als Mutation innerhalb von Struct können wir Eigenschaften in Structs ändern. Zeile Nr. 5 des obigen Codes ändert sich wie folgt:
Jetzt können wir den Wert der neuen Population der Immobilienpopulation im Rahmen der Methode zuweisen .
Hinweis :
Wenn wir let anstelle von var für Struct-Objekte verwenden, können wir den Wert von Eigenschaften nicht mutieren. Dies ist auch der Grund, warum beim Versuch, die Mutationsfunktion mit der let-Instanz aufzurufen, eine Fehlermeldung angezeigt wird. Daher ist es besser, var zu verwenden, wenn Sie den Wert einer Eigenschaft ändern.
Würde gerne Ihre Kommentare und Gedanken hören… ..
quelle