Warum beschränkt die Konstante die Eigenschaft von einer Strukturinstanz, aber nicht von der Klasseninstanz?

8

Als ich versuchte, die ID Eigenschaft der byValueObj Instanz zu ändern, erhielt ich einen Fehler, der mir sagte, dass ich der Eigenschaft einer Konstante nicht zuweisen kann, obwohl die Eigenschaft eine Variable ist. Ich kann es jedoch in einer Klasseninstanz tun. Ich weiß irgendwie, dass es etwas mit dem Wert- und Referenzmechanismus zu tun hat. Aber ich habe kein sehr klares und richtiges Verständnis davon. Kann mir jemand das erklären? Danke.

%Vor%     
SLN 24.06.2016, 10:13
quelle

2 Antworten

11

Strukturen in Swift sind Werttypen - und semantisch gesehen Werte (dh 'Instanzen') von Werttypen) sind unveränderlich.

Eine Mutation eines Werttyps, sei es durch direkte Änderung des Werts einer Eigenschaft oder durch Verwendung einer mutating -Methode, entspricht der Zuweisung eines vollständig neuen -Wertes an die Variable hält es (plus irgendwelche Nebenwirkungen, die die Mutation ausgelöst haben). Daher muss die Variable, die es enthält, ein var sein. Und diese Semantik wird durch das Verhalten von Eigenschaftenbeobachtern rund um Werttypen, wie , hervorgehoben.

Was das bedeutet ist, dass Sie sich das vorstellen können:

%Vor%

wie folgt:

%Vor%

Und wie Sie deutlich sehen können - dieser Code ist illegal. Sie können fooCopy nicht zu foo zurückgeben, da es sich um eine let Konstante handelt. Daher können Sie die Eigenschaft eines Werttyps, der als let deklariert ist, nicht ändern und müssen ihn daher zu einem var machen.

(Es ist erwähnenswert, dass der Compiler dieses Palaver nicht wirklich durchläuft; es kann die Eigenschaften von Strukturen direkt verändern, was man an der erzeugte SIL . Dies ändert jedoch nicht die Semantik der Werttypen.)

Der Grund, warum Sie eine veränderbare Eigenschaft einer Instanz let constant class ändern können, liegt an der Tatsache, dass Klassen Referenztypen sind. Eine let -Konstante sicherzustellen, stellt nur sicher, dass die Referenz gleich bleibt. Das Mutieren ihrer Eigenschaften beeinflusst in keiner Weise Ihre Referenz auf sie - Sie beziehen sich immer noch auf den selben Speicherort im Speicher.

Sie können sich einen Bezugstyp wie einen Wegweiser vorstellen, daher Code wie folgt:

%Vor%

Sie können sich die Speicherdarstellung so vorstellen:

%Vor%

Und wenn Sie eine Eigenschaft mutieren:

%Vor%

Die Referenz ( referenceToFoo ) selbst ist nicht betroffen - Sie zeigen immer noch auf denselben Speicherort im Speicher. Es ist die Eigenschaft der zugrunde liegenden Instanz, die geändert wurde (dh die zugrunde liegende Instanz wurde mutiert):

%Vor%

Nur wenn Sie versuchen, einen neuen Verweis auf referenceToFoo zuzuweisen, gibt der Compiler Ihnen einen Fehler, wenn Sie versuchen, die Referenz selbst zu ändern:

%Vor%

Sie müssen daher referenceToFoo a var angeben, um diese Zuweisung legal zu machen.

    
Hamish 24.06.2016, 12:54
quelle
2

struct ist ein Werttyp. Wenn Sie sie bearbeiten, rufen Sie den Standard-Setter für die Eigenschaft auf, der nichts anderes als eine Mutationsmethode ist, die nichts anderes als eine statische Methode der Struktur ist, die self als erstes Argument hat wie inout , die die Methode zurückgibt (Swift für jetzt hat Curry-Syntax für nicht angewandte Methodenaufrufe, aber wird das ändern zu einem abgeflachten ). Nur als Randnotiz: Wenn die Methode nicht mutiert, wird sie nicht inout sein.

Weil inout arbeitet, indem kopiert ein - auskopiert , wird didSet aufgerufen, auch wenn sich nichts geändert hat.

  

"Wenn Sie eine Eigenschaft mit Beobachtern an eine Funktion als In-Out-Parameter übergeben, werden die Beobachter von" willSet "und" didSet "immer aufgerufen."   Auszug aus: Apple Inc. "Die schnelle Programmiersprache (Swift 3)." IBooks. Ссылка

Code, den ein var struct kopiert, wenn eine Eigenschaft mutiert ist:

%Vor%

Ruft das didSet auf, obwohl wir nur das Int in der Eigenschaft der Struktur mutiert haben.

Wenn es eine komplett neue Kopie wäre, dann würden Sie erwarten, dass die mutierte Struktur eine neue Kopie mit neuer Speicherzuweisung ist. Dies ist jedoch nicht der Fall in dem Beispiel, siehe Code unten.

%Vor%

Also wird die Struktur nicht kopiert. Aber weil es inout ist:

  

"Schreiben Sie Ihren Code unter Verwendung des Modells, das durch Kopieren-in-Kopie angegeben wird, ohne von der call-by-reference-Optimierung abhängig zu sein, so dass es sich korrekt mit oder ohne Optimierung verhält."   Auszug aus: Apple Inc. "Die schnelle Programmiersprache (Swift 3)." IBooks. Ссылка

Codebeispiel mit inout only:

%Vor%     
Binarian 03.10.2016 13:30
quelle

Tags und Links