Erkennen, wann ein const-Objekt in Dart an eine Funktion übergeben wird, die es mutiert

Aug 17 2020

Nehmen Sie dieses Beispiel:

void modl(List<int> l) {
  l.add(90);
  print(l);
}

class Foo {
  final List<int> bar;
  const Foo(this.bar);

  @override
  String toString() => 'Foo{bar: $bar}';
}

void main() {
  var foo = const Foo([1,2,3,4]);
  modl(foo.bar);
  print (foo);
}

Das Ausführen des obigen Codes führt zu einer Laufzeit Uncaught Error , das Entfernen des constvon

var foo = const Foo([1,2,3,4]);

lässt es funktionieren.


Dies scheint mir ein Fehler zu sein, da die const-Variable mutiert werden kann und Dart dies zur Laufzeit erkennt. Dies bedeutet, dass es die Möglichkeit hat, zu erkennen, wann ein const-Objekt geändert wird, dies sollte jedoch nicht zur Kompilierungszeit erkannt worden sein, da const-Variablen werden als " Konstanten zur Kompilierungszeit " bezeichnet.

Wenn dies kein Fehler ist, gibt es irgendetwas in Dart, mit dem wir beim Kompilieren erkennen können, wann eine constVariable möglicherweise durch eine Operation mutiert wird?

In C ++ tritt ein Fehler beim Compiler auf, wenn wir versuchen, so etwas zu tun. Können wir in Dart etwas tun, um zu vermeiden, dass dieser Fehler zur Laufzeit auftritt?

Antworten

3 lrn Aug 17 2020 at 04:53

Nein. Dart constist eine Funktion zur Kompilierungszeit für die Objekterstellung, die sich jedoch nicht im Typsystem widerspiegelt. An der Art eines Objekts kann man nicht erkennen, ob es sich um eine Konstante handelt oder nicht.

Normalerweise ist das kein Problem, da eine Instanz einer Klasse, die const sein kann, nicht modifizierbar ist. Es ist nicht garantiert, dass es tief unveränderlich ist, aber die Instanz selbst kann ihre Felder nicht ändern.

Listen, Mengen und Karten können sowohl konstant als auch veränderbar sein. Das sehen Sie hier. Das Listenargument to const Foo(const [1, 2, 3, 4])ist konstant, auch wenn Sie das redundante constLiteral der Liste entfernen . Sie hätten das gleiche Problem mit new Foo(const [1, 2, 3, 4]), das auch eine unveränderliche foo.bar, aber sonst nicht zu unterscheiden wäre new Foo([1, 2, 3, 4]). Der einzige wirkliche Unterschied besteht darin, ob die Liste geändert werden kann oder nicht, und die einzige Möglichkeit, dies zu erkennen, besteht darin, zu versuchen, sie zu ändern.

Listen, Sets und Karten bieten keine Möglichkeit zu erkennen, ob sie veränderlich sind oder nicht, außer zu versuchen und den Fehler zu erkennen.

Im Vergleich zu C ++ ist Darts Vorstellung vom Sein consteine Eigenschaft des Objekts oder tatsächlich die Art und Weise, wie das Objekt erstellt wird. Das kann einige Konsequenzen für das Objekt haben. A const Foo(..)erstellt nur ein normales FooObjekt, aber es kann nur tief unveränderliche Objekte erstellen, und sie werden kanonisiert. A const [...]oder const {...}erstellt eine andere Art von Liste / Map / Set als das nicht konstante Literal, aber das ist im Typ nicht sichtbar.

In C ++ ist Sein consteine Eigenschaft einer Objektreferenz und schränkt die Verwendung dieser Referenz ein, es gibt jedoch keine konstanten Objekte als solche. Jedes Objekt kann als constReferenz übergeben werden.

Die beiden Konzepte sind völlig unterschiedlich und verwenden zufällig denselben Namen (und unterscheiden sich auch von JavaScript const).