Frage

Im Anschluss an die Diskussionen hier auf SO ich mehrmals gelesen bereits die Bemerkung, dass wandelbar structs sind „böse“ (wie in der Antwort auf dieses Frage ).

Was ist das eigentliche Problem mit Veränderlichkeit und structs in C #?

War es hilfreich?

Lösung

Structs sind Werttypen, was bedeutet, sie kopiert werden, wenn sie herumgereicht werden.

Wenn Sie also eine Kopie ändern Sie diese Kopie ändern, nicht das Original und keine weiteren Kopien, die sich um sein könnte.

Wenn Sie Ihre Struktur ist unveränderlich dann alle automatischen Kopien von sich ergebende Wert übergeben wird, wird die gleiche sein.

Wenn Sie es ändern wollen, müssen Sie tun es bewusst durch eine neue Instanz der Struktur mit den geänderten Daten zu schaffen. (Keine Kopie)

Andere Tipps

Wo soll ich anfangen ;-p

Eric Lippert Blog ist immer gut für ein Angebot:

  

Dies ist ein weiterer Grund, warum wandelbar   Werttypen sind böse. Versuchen Sie, immer   machen Werttypen unveränderlich.

Erstens neigen Sie Änderungen zu verlieren, ganz einfach ... zum Beispiel, die Dinge aus einer Liste bekommen:

Foo foo = list[0];
foo.Name = "abc";

Was hat diese Veränderung? Nichts nützlich ...

Das gleiche mit den Eigenschaften:

myObj.SomeProperty.Size = 22; // the compiler spots this one

zwingt Sie zu tun:

Bar bar = myObj.SomeProperty;
bar.Size = 22;
myObj.SomeProperty = bar;

weniger kritisch, gibt es eine Größe Problem; veränderbare Objekte sind in der Regel mehrere Eigenschaften haben; doch wenn Sie eine Struktur mit zwei ints haben, ein string, ein DateTime und ein bool, können Sie sehr schnell brennen durch viel Speicher. Mit einer Klasse mehr Anrufer können einen Verweis auf die gleiche Instanz teilen (Referenzen sind klein).

würde ich nicht sagen böse aber Wandelbarkeit ist oft ein Zeichen von Übereifer auf Seiten des Programmierers ein Maximum an Funktionalität bereitzustellen. In Wirklichkeit ist dies oft nicht benötigt und das wiederum macht die Schnittstelle kleinen, einfacher zu bedienen und härter falsch zu verwenden (= robuste).

Ein Beispiel hierfür gelesen / schreiben und schreiben / schreiben Konflikte unter Rennbedingungen. Diese können einfach nicht in unveränderlichen Strukturen auftreten, da ein Schreib kein gültiger Betrieb ist.

Auch ich behaupten, dass Wandelbarkeit ist fast nie wirklich erforderlich , der Programmierer nur denkt , dass es könnte in der Zukunft sein. Zum Beispiel ist es einfach nicht sinnvoll, ein Datum zu ändern. Vielmehr erstellen Sie ein neues Datum der alte basiert. Dies ist ein preiswerter Betrieb, so dass Leistung ist nicht eine Überlegung.

Mutable structs sind nicht böse.

Sie sind absolut in Hochleistungs Umständen notwendig. Zum Beispiel, wenn Cache-Zeilen und oder Garbage Collection zu einem Engpass.

Ich würde die Verwendung einer unveränderlichen Struktur in diesen absolut gültigen Anwendungsfällen nicht als „böse“.

kann ich den Punkt sehen, dass C # 's Syntax nicht den Zugang eines Mitglieds eines Werttypen oder einen Referenztypen nicht helfen zu unterscheiden, so dass ich bin für zu unveränderlich structs, dass Unveränderlichkeit erzwingen , über wandelbar structs.

Doch statt einfach Kennzeichnung unveränderlich structs als „bösen“, würde ich Sie raten, die Sprache zu umarmen und zu befürworten hilfreicher und konstruktive Regel Daumen.

Zum Beispiel: „structs sind Werttypen, die standardmäßig kopiert werden, müssen Sie eine Referenz, wenn Sie sie nicht kopieren wollen“ oder "versuchen, mit Nur-Lese-structs zuerst zu arbeiten" .

Structs mit öffentlichen veränderbaren Feldern oder Eigenschaften nicht böse ist.

Struct Methoden (im Unterschied von Immobilien-Setter), die „dieser“ etwas Böse mutiert, nur weil .net sie von Methoden nicht ein Mittel zur Unterscheidung, die nicht tun. Struct Methoden, die „das“ nicht mutieren aufrufbaren sollte auch auf read-only structs ohne dass defensive Kopieren. Methoden, die mutieren tun „dieser“ sollten gar nicht auf read-only structs aufrufbaren sein. Da .net nicht struct Methoden verbieten will, dass „dies“ aus nicht ändern auf read-only structs aufgerufen wird, wollen aber nicht erlauben structs schreibgeschützt mutiert werden, es defensiv Kopien structs in Read- nur Kontexte, wohl das schlimmste aus beiden Welten zu bekommen.

Trotz der Probleme mit der Handhabung von Selbst mutiert Methoden im schreibgeschützten Kontext jedoch wandelbar structs bieten oft Semantik weit überlegen wandelbar Klassentypen. Betrachten Sie die folgenden drei Verfahren Unterschriften:

struct PointyStruct {public int x,y,z;};
class PointyClass {public int x,y,z;};

void Method1(PointyStruct foo);
void Method2(ref PointyStruct foo);
void Method3(PointyClass foo);

Für jede Methode, die folgenden Fragen beantworten:

  1. Unter der Annahme, das Verfahren keinen „unsicheren“ Code nicht verwendet, könnte es foo ändern?
  2. Wenn keine außerhalb Verweise auf ‚foo‘ vorhanden sein, bevor die Methode aufgerufen wird, könnte eine Außenreferenz existieren nach?

Antworten:

  

Frage 1:
 Method1(): no (klare Absicht)
 Method2(): ja (klare Absicht)
 Method3(): ja (unsicher Absicht)
 Frage 2:
 Method1(): nein
 Method2(): no (es sei denn, unsicher)
 Method3(): yes

Method1 kann nicht foo ändern, und wird nie einen Verweis. Method2 bekommt einen kurzlebigen Bezug auf foo, die sie die Felder foo beliebig oft ändern können, in beliebiger Reihenfolge, bis er zurückkommt, aber es kann nicht, dass der Bezug bestehen bleiben. Vor Method2 zurück, es sei denn, es unsicher Code verwendet, jede und alle Kopien, die von seinem ‚foo‘ Bezug genommen worden sein könnten verschwunden sein. Method3, im Gegensatz zu Method2, bekommt einen promiscuously-teilbaren Bezug auf foo, und es ist nicht abzusehen, was es mit ihm tun könnte. Es ist vielleicht nicht foo überhaupt ändern, könnte es foo ändern und dann zurück, oder es könnte einen Hinweis gibt auf einem anderen Thread auf foo, die es in einer beliebigen Art und Weise an einem beliebigen späteren Zeitpunkt mutieren könnten. Der einzige Weg, zu begrenzen, was Method3 auf ein veränderbares Objekt der Klasse tun könnte darin bestanden wäre das veränderbare Objekt in einen Read-Only-Wrapper zu verkapseln, die hässlich und umständlich ist.

Arrays von Strukturen bieten wunderbare Semantik. Angesichts RectArray [500] vom Typ Rechteck, dann ist es klar und deutlich, wie z.B. Kopierelement 123 an das Element 456 und dann einige Zeit später eingestellt, die Breite des Elements 123 bis 555, ohne störendes Element 456. "RectArray [432] = RectArray [321]; ...; RectArray [123] .Width = 555;" . Zu wissen, dass Rechteck eine Struktur mit einem ganzzahligen Feld Breite genannt wird man alles, was man über die oben genannten Aussagen wissen muß sagen.

Nehmen wir nun an RectClass eine Klasse mit den gleichen Feldern wie Rechteck war und man wollte die gleichen Operationen auf einem RectClassArray [500] vom Typ RectClass tun. Vielleicht wird das Array soll 500 vorinitialisiert unveränderliche Verweise auf halten, um RectClass Objekte Veränderliche. in diesem Fall wäre der richtige Code so etwas wie "RectClassArray [321] .SetBounds (RectClassArray [456]); ...; RectClassArray [321] .X = 555;" sein. Vielleicht wird das Array angenommene Instanzen zu halten, die nicht ändern werden, so dass der richtige Code würde mehr sein wie „RectClassArray [321] = RectClassArray [456]; ...; RectClassArray [321] = Neue RectClass (RectClassArray [321 ]); RectClassArray [321] .X = 555;“ Um zu wissen, was man tun soll, müßte man viel mehr sowohl über RectClass wissen (zum Beispiel hat er eine Kopie Konstruktor unterstützen, eine Kopie-von-Methode, etc.) und die beabsichtigten Verwendung des Arrays. Nirgendwo in der Nähe alssauber wie eine Struktur verwendet wird.

Um sicher zu sein, gibt es leider keine schöne Art und Weise für jede Container-Klasse anders als ein Array, das die saubere Semantik einer Struktur Array zu bieten. Die besten könnte man tun, wenn man eine Sammlung wollte mit beispielsweise indiziert werden ein String ist, würde wahrscheinlich ein generisches „ActOnItem“ Verfahren zu bieten, auf die eine Zeichenfolge für den Index akzeptieren würde, ein allgemeinen Parameter und Delegierter, die als Referenz übergeben werden würden sowohl die generischen Parameter und den Sammelpunkt. Das wäre fast die gleiche Semantik wie struct Arrays erlauben, aber es sei denn, die vb.net und C # Menschen eine nette Syntax bieten pursuaded werden kann, wird der Code geht klobig aussehende sein, auch wenn es einigermaßen Leistung ist (Übergabe eines generischen Parameter würde ermöglichen die Verwendung eines statischen Delegierten und würde keine Notwendigkeit vermeiden alle temporären Klasseninstanzen erstellen).

Ich persönlich bin im Hass Eric Lippert et al pikiert. spucken in Bezug auf wandelbaren Werttypen. Sie bieten viel sauberer Semantik als die promiskuitiv Referenztypen, die alle über den Ort verwendet werden. Trotz einige der Einschränkungen mit Unterstützung der .net für Werttypen gibt es viele Fälle, in denen wandelbaren Werttypen sind eine bessere Passform als jede andere Art von Einheit.

Werttypen stellt grundsätzlich unveränderlich Konzepte. Fx, es macht keinen Sinn, einen mathematischen Wert zu haben wie eine ganze Zahl, Vektor usw. und dann in der Lage sein, ihn zu ändern. Das wäre wie die Bedeutung eines Wertes neu zu definieren. Statt einen Werttyp zu ändern, ist es sinnvoller einen anderen eindeutigen Wert zuzuweisen. Denken Sie an die Tatsache, dass Werttypen durch einen Vergleich aller Werte seiner Eigenschaften verglichen werden. Der Punkt ist, dass, wenn die Eigenschaften gleich sind, dann ist es die gleiche universelle Darstellung dieses Wertes.

Wie Konrad erwähnt es keinen Sinn macht, ein Datum entweder zu ändern, da der Wert darstellt, dass einzigartiger Zeitpunkt und nicht eine Instanz eines Zeitobjekts, das jede Staat oder Kontextabhängigkeit hat.

hofft, dass dies keinen Sinn macht für Sie. Es ist mehr über das Konzept Sie versuchen, mit Werttypen als praktische Details zu erfassen, um sicher zu sein.

Es gibt noch ein paar Sonderfälle, die unpredictible Verhalten von Programmierern Sicht führen könnte. Hier einige von ihnen.

  1. Immutable Werttypen und Nur-Lese-Felder

// Simple mutable structure. 
// Method IncrementI mutates current state.
struct Mutable
{
    public Mutable(int i) : this() 
    {
        I = i;
    }

    public void IncrementI() { I++; }

    public int I {get; private set;}
}

// Simple class that contains Mutable structure
// as readonly field
class SomeClass 
{
    public readonly Mutable mutable = new Mutable(5);
}

// Simple class that contains Mutable structure
// as ordinary (non-readonly) field
class AnotherClass 
{
    public Mutable mutable = new Mutable(5);
}

class Program
{
    void Main()
    {
        // Case 1. Mutable readonly field
        var someClass = new SomeClass();
        someClass.mutable.IncrementI();
        // still 5, not 6, because SomeClass.mutable field is readonly
        // and compiler creates temporary copy every time when you trying to
        // access this field
        Console.WriteLine(someClass.mutable.I);

        // Case 2. Mutable ordinary field
        var anotherClass = new AnotherClass();
        anotherClass.mutable.IncrementI();

        //Prints 6, because AnotherClass.mutable field is not readonly
        Console.WriteLine(anotherClass.mutable.I);
    }
}

  1. Mutable Werttypen und Array

Nehmen wir an eine Reihe von unserer Mutable Struktur haben und wir rufen IncrementI Methode für das erste Element des Arrays. Welches Verhalten erwarten Sie von diesem Anruf? Sollte es Arrays Wert oder nur eine Kopie ändern?

Mutable[] arrayOfMutables = new Mutable[1];
arrayOfMutables[0] = new Mutable(5);

// Now we actually accessing reference to the first element
// without making any additional copy
arrayOfMutables[0].IncrementI();

//Prints 6!!
Console.WriteLine(arrayOfMutables[0].I);

// Every array implements IList<T> interface
IList<Mutable> listOfMutables = arrayOfMutables;

// But accessing values through this interface lead
// to different behavior: IList indexer returns a copy
// instead of an managed reference
listOfMutables[0].IncrementI(); // Should change I to 7

// Nope! we still have 6, because previous line of code
// mutate a copy instead of a list value
Console.WriteLine(listOfMutables[0].I);

So wandelbar structs ist nicht böse, solange Sie und der Rest der Mannschaft klar zu verstehen, was Sie tun. Aber es gibt zu viele Ecke Fälle, in denen das Verhalten des Programms wäre anders von einem erwartet, dass auf subtile hart führen könnte zu produzieren und harte Fehler zu verstehen.

Wenn Sie schon einmal in einer Sprache wie C / C ++ programmiert haben, structs sind fein wie wandelbar zu verwenden. geben sie nicht nur mit ref, um und es gibt nichts, was schief gehen kann. Das einzige Problem, das ich finden sind die Einschränkungen des C # -Compiler und dass in einigen Fällen, ich bin nicht in der Lage, die dumme Sache zu zwingen, einen Verweis auf die Struktur zu verwenden, statt einer Kopie (wie wenn eine Struktur Teil einer C # Klasse ).

So wandelbar structs nicht böse sind, hat C # gemacht sie böse. Ich benutze wandelbar structs in C ++ die ganze Zeit, und sie sind sehr bequem und intuitiv. Im Gegensatz dazu hat C # mich gemacht, weil der Weg zu vollständig structs als Mitglieder von Klassen verlassen sie Objekte behandeln. Ihre Bequemlichkeit hat uns unsere Kosten.

Stellen Sie sich eine Reihe von 1.000.000 structs haben. Jede Struktur eine Eigenkapital mit Sachen wie bid_price darstellt, OFFER_PRICE (vielleicht Dezimalstellen) und so weiter, das von C # / VB erstellt wird.

Stellen Sie sich vor, dass Array wird in einem Speicherblock in dem nicht verwalteten Heap erstellt, so dass einige andere native Code-Thread gleichzeitig in der Lage, das Array zugreifen (vielleicht einige High-perf Code tun math).

Stellen Sie sich den C # / VB-Code zu einem Markt-Feed von Preisänderungen zuhört, kann dieser Code hat ein Element des Arrays zuzugreifen (für welche auch immer Sicherheit) und dann einig Preisfeld ändern (s).

Stellen Sie sich Dutzende oder sogar Hunderttausende von Mal pro Sekunde durchgeführt werden.

Nun läßt Gesicht Fakten in diesem Fall wir wollen wirklich diese structs wandelbar zu sein, müssen sie sein, weil sie von einem anderen nativen Code gemeinsam genutzt werden, um Kopien zu schaffen würde nicht helfen; sie sein müssen, weil bei diesen Geschwindigkeiten eine Kopie von rund 120 Byte Struktur macht Irrsinn ist, vor allem, wenn ein Update tatsächlich nur ein Byte oder zwei auswirken kann.

Hugo

Wenn Sie bleiben, was structs sind für (in C #, Visual Basic 6, Pascal / Delphi, C ++ Strukturtyp (oder Klassen), wenn sie nicht als Zeiger verwendet werden), werden Sie feststellen, dass eine Struktur ist nicht mehr als a Verbindung Variable . Das bedeutet:. Sie sie als gepackte Menge von Variablen, unter einem gemeinsamen Namen behandeln (ein Datensatz Variable, die Sie Mitglieder aus Referenz)

Ich weiß, dass eine Menge Leute zu OOP verwendeten tief verwirren würde, aber das ist nicht Grund genug, um solche Dinge zu sagen, von Natur aus böse sind, wenn richtig eingesetzt. Einige Strukturen sind inmutable wie sie beabsichtigen, (dies ist der Fall von Pythons namedtuple ist), aber es ist ein anderes Paradigma zu betrachten.

Ja: structs beinhaltet eine Menge Speicher, aber es wird nicht genau mehr Speicher sein, indem Sie:

point.x = point.x + 1

im Vergleich zu:

point = Point(point.x + 1, point.y)

Der Speicherverbrauch wird mindestens die gleiche oder sogar mehr im inmutable Fall sein (obwohl dieser Fall nur vorübergehend sein würde, für die aktuellen Stapel, abhängig von der Sprache).

Aber schließlich Strukturen sind Strukturen , keine Objekte. In POO ist die wichtigste Eigenschaft eines Objekts ihrer Identität , die meiste Zeit ist nicht mehr als die Speicheradresse. Struct steht für Datenstruktur (nicht ein richtiges Objekt, und so haben sie keine Identität sowieso) und Daten geändert werden können. In anderen Sprachen, Datensatz (anstelle von struct , wie es der Fall für Pascal ist) ist das Wort und hält den gleichen Zweck: nur einen Datensatz Variable, sollte gelesen werden von Dateien, verändert und kippte in Dateien (das ist die Hauptanwendung und in vielen Sprachen, können Sie sogar ein Datenabgleich im Datensatz definieren, während die für richtig genannt Objekte nicht unbedingt der Fall ist).

ein gutes Beispiel will? Structs werden verwendet, um Dateien leicht zu lesen. Python hat href="https://docs.python.org/2/library/struct.html"> weil, da es objektorientiert ist und keine Unterstützung für structs, musste es implementieren sie in einer anderen Art und Weise, die etwas hässlich ist. Sprachen structs Implementierung haben diese Funktion ... eingebaut. Versuchen Sie, ein Bitmap-Header mit einer geeigneten Struktur in Sprachen wie Pascal oder C. Lesung wird es leicht sein (wenn die Struktur richtig aufgebaut und ausgerichtet ist, in Pascal würden Sie keinen Datensatz-basierten Zugriff verwenden, aber Funktionen beliebiger Binärdaten zu lesen). Also, für Dateien und direkt (lokal) Speicherzugriff sind structs besser als Objekte. Für heute sind wir zu JSON und XML, verwendet und so vergessen wir die Verwendung von Binärdateien (und als Nebenwirkung, die Verwendung von Strukturen). Aber ja: sie existieren, und haben einen Zweck

.

Sie sind nicht böse. nutzen sie nur für den richtigen Zweck.

Wenn Sie in Bezug auf die Hämmer denken, werden Sie Schrauben Nägel zu behandeln, Schrauben zu finden sind härter in der Wand zu stürzen, und es wird Schrauben Fehler sein, und sie werden die Bösen sein.

Wenn etwas mutiert werden kann, erhält sie ein Gefühl der Identität.

struct Person {
    public string name; // mutable
    public Point position = new Point(0, 0); // mutable

    public Person(string name, Point position) { ... }
}

Person eric = new Person("Eric Lippert", new Point(4, 2));

Da Person wandelbar ist, ist es natürlicher, darüber nachzudenken, Erics Position zu ändern als Eric Klonen, Bewegen des Klon, und die Zerstörung der ursprünglichen . Beide Operationen gelingen würde, in den Inhalt des eric.position ändern, aber man ist intuitiver als die andere. Ebenso ist es intuitives Eric passiert um (als Referenz) für Methoden, ihn zu ändern. Giving ein Verfahren ein Klon von Eric ist fast immer überraschend sein würde. Wer mutieren Person wollen muß daran denken, für eine Referenz zu bitten, Person oder sie werden das Falsche tun.

Wenn Sie den Typ unveränderlich machen, geht das Problem weg; wenn ich nicht eric ändern kann, macht es für mich keinen Unterschied, ob ich eric oder einen Klon von eric erhalten. Allgemeiner gesagt, ist eine Art von Wert zu übergeben sicher, wenn alle ihre beobachtbaren Zustand Mitglieder gehalten, die entweder:

  • unveränderlich
  • Referenztypen
  • sicher von Wert zu übergeben

Wenn diese Bedingungen erfüllt sind, dann ein veränderlicher Werttyp verhält sich wie ein Referenztyp, da eine flache Kopie noch der Empfänger ermöglicht, die Originaldaten zu verändern.

Die Anschaulichkeit eines unveränderlichen Person hängt davon ab, was Sie versuchen, obwohl zu tun. Wenn Person repräsentiert nur einen Satz von Daten über eine Person, gibt es nichts unintuitive darüber; Person Variablen wirklich abstrakt Werte repräsentieren , keine Objekte. (In diesem Fall wäre es wahrscheinlich besser geeignet sein, es zu PersonData umbenennen.) Wenn Person tatsächlich einer Person selbst modelliert, die Idee der ständig zu schaffen und Klone bewegen albern ist, auch wenn Sie die Falle zu denken Sie vermieden haben‘ Re die ursprünglichen modifizieren. In diesem Fall wäre es wahrscheinlich natürlicher sein, einfach einen Referenztyp machen Person (das heißt, eine Klasse).

Zugegeben, als funktionale Programmierung uns gelehrt hat, gibt es Vorteile zu machen alles unveränderlich (niemand zu einer Referenz heimlich festhalten kann, ihn eric und mutiert), aber da das in OOP nicht idiomatischen ist es gehe noch nicht intuitiv sein jemand anderes mit Ihrem Code zu arbeiten.

Persönlich, wenn ich Code aussehen folgende sieht ziemlich klobig zu mir:

data.value.set (data.value.get () + 1);

anstatt einfach

data.value ++; oder data.value = data.value + 1;

Datenkapselung ist nützlich, wenn eine Klasse um vorbei und Sie wollen, dass der Wert, um sicherzustellen, in einer kontrollierten Art und Weise modifiziert wird. Allerdings, wenn Sie öffentliches Set und bekommen Funktionen haben, die wenig mehr tun, als den Wert zu setzen, was auch immer übergeben wird, wie ist dies eine Verbesserung gegenüber einfach um eine öffentliche Datenstruktur vorbei?

Wenn ich eine private Struktur innerhalb einer Klasse zu erstellen, habe ich diese Struktur eine Reihe von Variablen in eine Gruppe zu organisieren. Ich möchte in der Lage, diese Struktur innerhalb der Klassenbereich zu ändern, nicht erhalten Kopien dieser Struktur und neue Instanzen erstellen.

Für mich eine gültige Verwendung von Strukturen benutzt werden, öffentliche Variablen zu organisieren, wenn ich Zugriffskontrolle will ich eine Klasse verwenden würde.

Es gibt einige Probleme mit Herrn Eric Lippert Beispiel. Es ist gekünstelt, den Punkt zu veranschaulichen, dass structs kopiert und wie das könnte ein Problem sein, wenn Sie nicht vorsichtig sind. Mit Blick auf das Beispiel, das ich es als Folge einer schlechten Programmierung Gewohnheit sehen und nicht wirklich ein Problem mit entweder Struktur oder der Klasse.

  1. Eine Struktur soll nur öffentliche Mitglieder haben und sollte keine Verkapselung erfordern. Ist dies der Fall, dann sollte es wirklich eine Art / Klasse sein. Sie wirklich nicht zwei Konstrukte müssen die gleiche Sache sagen.

  2. Wenn Sie Klasse umschließt eine Struktur haben, würden Sie eine Methode in der Klasse aufrufen um das Element struct zu mutieren. Dies ist, was ich als gute Programmier Gewohnheit tun würde.

Eine ordnungsgemäße Umsetzung wäre wie folgt.

struct Mutable {
public int x;
}

class Test {
    private Mutable m = new Mutable();
    public int mutate()
    { 
        m.x = m.x + 1;
        return m.x;
    }
  }
  static void Main(string[] args) {
        Test t = new Test();
        System.Console.WriteLine(t.mutate());
        System.Console.WriteLine(t.mutate());
        System.Console.WriteLine(t.mutate());
    }

Es sieht aus wie es ein Problem mit der Programmierung Gewohnheit ist wie mit Struktur selbst zu einem Problem gegenüber. Structs soll wandelbar sein, das ist die Idee und Absicht.

Das Ergebnis der Änderungen voila verhält sich wie erwartet:

1 2 3 Drücken Sie eine beliebige Taste, um fortzufahren . . .

Es gibt viele Vorteile und Nachteile zu wandelbar Daten. Der Millionen-Dollar-Nachteil wird Aliasing. Wenn der gleiche Wert wird an mehreren Stellen verwendet wird, und einer von ihnen ändert es, dann wird es erscheinen auf magische Weise zu den anderen Orten zu haben sich geändert, die es verwenden. Dies hängt damit zusammen, aber nicht mit ihnen identisch Rennbedingungen.

Der Millionen-Dollar-Vorteil ist, Modularität, manchmal. Veränderliche Zustand können Sie erlauben zu verbergen Informationen aus Code zu ändern, die nicht über sie wissen muss.

Die Kunst des Interpreter geht in diese Kompromisse im Detail und gibt einige Beispiele.

Ich glaube nicht, dass sie böse sind, wenn richtig eingesetzt. Ich würde es nicht in meinem Produktionscode setzen, aber ich würde für so etwas wie strukturierten Unit-Tests Mocks, wo die Lebensdauer einer Struktur relativ klein ist.

das Eric Beispiel verwenden, vielleicht Sie eine zweite Instanz dieses Eric erstellen möchten, aber Anpassungen vornehmen, so dass die Art Ihres Tests ist (dh Vervielfältigung, dann zu ändern). Es spielt keine Rolle, was mit der ersten Instanz von Eric passiert, wenn wir nur Eric2 für den Rest des Testskript verwenden, es sei denn, Sie verwenden ihn als Test Vergleich planen.

Dies würde für die Prüfung meist nützlich sein oder Legacy-Code geändert wird, wie seicht ein bestimmtes Objekt definiert (der Punkt der structs), aber durch eine unveränderliche Struktur aufweisen, das verhindert, es ist Nutzung annoyingly.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top