Dartで、constオブジェクトがそれを変更する関数に渡されたときの検出

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変数は「コンパイル時定数」と呼ばれます

これがバグではない場合、コンパイル時にconst変数が操作によって変更される可能性があることを検出できるものはdartにありますか?

C ++では、このようなことを行おうとするとコンパイラがエラーになります。実行時にこのエラーが発生しないようにするために、Dartでできることはありますか?

回答

3 lrn Aug 17 2020 at 04:53

いいえ。ダートconstはオブジェクト作成に関するコンパイル時の機能ですが、型システムには反映されていません。オブジェクトのタイプから、それが定数であるかどうかを判断することはできません。

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オブジェクトのプロパティであり、実際には、オブジェクトの作成方法です。それはオブジェクトにいくつかの結果をもたらす可能性があります。aconst Foo(..)は通常のFooオブジェクトを作成するだけですが、作成できるのは深く不変のオブジェクトのみであり、それらは正規化されています。Aconst [...]またはconst {...}リスト/マップ非constリテラルより/セットの異なる種類を作成しますが、それはタイプには見えないのです。

C ++では、beingconstはオブジェクト参照のプロパティであり、その参照の使用方法を制限しますが、そのような定数オブジェクトはありません。任意のオブジェクトをconst参照として渡すことができます。

2つの概念は本質的に完全に異なり、たまたま同じ名前を使用しています(また、どちらもJavaScriptとは異なりますconst)。