web-dev-qa-db-ja.com

Dartのダイナミックとオブジェクトの違いは何ですか?

どちらも同じケースで使用できるようです。型チェックなどで異なる表現や微妙な点はありますか?

31
user3761898

Dartプログラミング言語仕様、第3版 のセクションType dynamicは、次のように述べています。

動的型には、名前付きパラメーターの可能なすべての組み合わせで、可能なすべての識別子とアリティに対するメソッドがあります。これらのメソッドはすべて、戻り値の型がdynamicであり、それらの仮パラメーターはすべて、型がdynamicです。タイプdynamicには、可能なすべての識別子のプロパティがあります。これらのプロパティはすべてダイナミック型です。

つまり、dynamic型付き変数でメソッドを呼び出しても警告は表示されません。 Objectとして型指定された変数には当てはまりません。例えば:

dynamic a;
Object b;

main() {
  a = "";
  b = "";
  printLengths();
}

printLengths() {
  // no warning
  print(a.length);

  // warning:
  // The getter 'length' is not defined for the class 'Object'
  print(b.length);
}

実行時には、違いは見られないと思います。

24

dynamicのもう1つの見方は、それが実際には型ではないということです。これは型チェックをオフにして、静的型システムに「信頼してください、私がやっていることを知っています」と伝える方法です。 _dynamic o;_を書き込むと、型指定されていない変数が宣言されます。代わりに、「型チェックされていない」とマークされます。

_Object o = something;_を書くと、oであること以外はObjectについて何も仮定できないことをシステムに伝えます。これらのメソッドはtoStringで定義されているため、hashCodeおよびObjectを呼び出すことができますが、o.foo()を実行しようとすると、警告が表示されます-できますあなたがそれを行うことができるとは思わないので、コードがおそらく間違っていることを警告します。

_dynamic o = something_と書くと、システムに何も想定せず、何もチェックしないよう指示します。 o.foo()と書いても、警告は出されません。 「oに関連するものはすべてOKです。信頼してください、私が何をしているか知っています」とあなたは言ったので、o.foo()はOKだと思います。

大きな力には大きな責任が伴います-変数の型チェックを無効にした場合、何も問題がないことを確認する必要があります。

22
lrn

実用的な違いに関するアレクサンドルの回答に追加すると、2つの間に意味上の違いもあり、正しいものを使用すると、他のプログラマーに意図をよりよく伝えるのに役立ちます。

Objectを使用すると、使用している型がわかっており、それがObjectであると言っていることになります。例えば:

int getHashCode(Object obj) {
  return obj.hashCode;
}

hashCodeObjectのプロパティであるため、Objectをパラメーターの型として使用し、関数がObjectのすべての型を受け入れることを指定します。

一方、dynamicを使用すると、Dartシステムは使用するタイプを適切に表現できなくなります。

void setEmail(dynamic email) {
  if (email is Email) {
    _email = email;
  } else if (email is String) {
    _email = new Email.fromString(email);
  }
}

Dartは現在ユニオンタイプをサポートしていないため、タイプEmail | Stringを表現する方法がないため、dynamicを使用してすべてのタイプを受け入れ、タイプが1である場合のみを処理する必要があります。興味があります。

5
Pixel Elephant

また、拡張メソッドは動的では正しく機能しませんが、オブジェクトでは問題なく機能することにも気付きました。


// I used to have the extension on dynamic and had 
// problems that didn't occur when using the same extension on Object

extension UtilExtensions on Object {   

  bool get isStringNotEmpty => this is String && (this as String).isNotEmpty;
  String get asStringNotEmpty => isStringNotEmpty ? this as String : null;

  bool get isIntNotZero => this is int && (this as int) != 0;
  int get asIntNotZero => isIntNotZero ? this as int : null;

  Map<String, Object> get asPair {
    if (this != null && this is Map) {
      return (this as Map).cast<String, Object>();
    }

    return null;
  }

  Map<String, Object> get asFullPair {
    if (this != null && this is Map) {
      var ret = (this as Map).cast<String, Object>();

      for (var key in ret.keys) {
        var val = ret[key];

        if (val is Map) {
          ret[key] = val.asFullPair;
        }
      }

      return ret;
    }

    return null;
  }
}
0
Jonathan