Обнаружение передачи константного объекта функции, которая его изменяет, в Dart

Aug 17 2020

Вот пример:

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);
}

Выполнение приведенного выше кода приводит к запуску среды выполнения Uncaught Error , но удаление constиз

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

позволяет ему работать.


Мне это кажется ошибкой, потому что переменная const может быть изменена, и dart обнаруживает это во время выполнения, что означает, что у него есть средства для определения того, когда объект const изменяется, но не должно ли это быть обнаружено во время компиляции, поскольку Переменные const называются « константами времени компиляции ».

Если это не ошибка, есть ли в dart что-нибудь, что позволяет нам обнаруживать во время компиляции, когда constпеременная может быть изменена в результате операции?

В C ++ компилятор выдает ошибку, когда мы пытаемся сделать что-то подобное. Что мы можем сделать в Dart, чтобы избежать появления этой ошибки во время выполнения?

Ответы

3 lrn Aug 17 2020 at 04:53

Нет. Dart const- это функция времени компиляции, связанная с созданием объекта, но она не отражается в системе типов. По типу объекта нельзя сказать, константа он или нет.

Обычно это не проблема, потому что экземпляр класса, который может быть константным, нельзя изменить. Не гарантируется, что он будет полностью неизменяемым, но для самого экземпляра нельзя изменить его поля.

Списки, наборы и карты могут быть как постоянными, так и изменяемыми. Вот что вы здесь видите. Аргумент списка const Foo(const [1, 2, 3, 4])является постоянным, даже если вы удалите лишний в литерале constсписка. У вас будет такая же проблема с new Foo(const [1, 2, 3, 4]), которая также предоставит неизменяемый foo.bar, но в противном случае будет неотличима от new Foo([1, 2, 3, 4]). Единственная реальная разница заключается в том, можно ли изменить список или нет, и единственный способ определить это - попытаться изменить его.

Списки, наборы и карты не предоставляют никакого способа определить, являются ли они изменяемыми или нет, кроме попытки и выявления ошибки.

По сравнению с C ++ понятие бытия Дарта constявляется свойством объекта или, в действительности, способом создания объекта. Это может иметь некоторые последствия для объекта. A const Foo(..)просто создает обычный Fooобъект, но может создавать только глубоко неизменяемые объекты, и они канонизированы. A const [...]or const {...}создает список / карту / набор другого типа, чем неконстантный литерал, но он не отображается в типе.

В C ++ бытие const- это свойство ссылки на объект, которое ограничивает использование этой ссылки, но как таковые константные объекты отсутствуют. В качестве constссылки можно передать любой объект .

Эти две концепции полностью различаются по своей природе и просто используют одно и то же имя (и оба они отличаются от JavaScript const).