web-dev-qa-db-fra.com

Quelle est la différence entre dynamique et objet en fléchette?

Ils semblent tous deux pouvoir être utilisés dans des cas identiques. Existe-t-il une représentation ou des subtilités différentes dans la vérification de type, etc.?

31
user3761898

La section Type dynamic de Dart Programming Language Specification, 3rd Edition indique:

Type dynamic a des méthodes pour chaque identifiant et arité possibles, avec toutes les combinaisons possibles de paramètres nommés. Ces méthodes ont toutes un type de retour dynamique et leurs paramètres formels ont tous un type dynamique. Le type dynamique a des propriétés pour chaque identifiant possible. Ces propriétés ont toutes un type dynamique.

Cela signifie que vous n'obtiendrez aucun avertissement en appelant une méthode sur une variable de type dynamic. Ce ne sera pas le cas avec une variable de type Object. Par exemple:

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

À l'exécution, je pense que vous ne devriez voir aucune différence.

24
Alexandre Ardhuin

Une autre perspective sur dynamic est que ce n'est pas vraiment un type - c'est un moyen de désactiver la vérification de type et de dire au système de type statique "faites-moi confiance, je sais ce que je fais". L'écriture de dynamic o; Déclare une variable qui n'est pas saisie - elle est plutôt marquée comme "non vérifiée par type".

Lorsque vous écrivez Object o = something;, Vous dites au système qu'il ne peut rien supposer de o sauf que c'est un Object. Vous pouvez appeler toString et hashCode car ces méthodes sont définies sur Object, mais si vous essayez de faire o.foo() vous obtiendrez un avertissement - cela peut ne voyez pas que vous pouvez le faire, et donc il vous avertit que votre code est probablement incorrect.

Si vous écrivez dynamic o = something, Vous dites au système de ne rien supposer et de ne rien vérifier. Si vous écrivez o.foo() alors il ne vous avertira pas. Vous lui avez dit que "tout ce qui concerne o est OK! Faites-moi confiance, je sais ce que je fais", et il pense donc que o.foo() est OK.

Une grande puissance s'accompagne d'une grande responsabilité - si vous désactivez la vérification de type pour une variable, cela vous revient de vous assurer que vous ne faites rien de mal.

22
lrn

Pour ajouter à la réponse d'Alexandre sur la différence pratique, il existe également une différence sémantique entre les deux, et l'utilisation de la bonne aidera à mieux communiquer votre intention aux autres programmeurs.

Lorsque vous utilisez Object, vous dites que vous connaissez le type avec lequel vous travaillez et qu'il s'agit de Object. Par exemple:

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

Puisque hashCode est une propriété sur Object nous utilisons Object comme type de paramètre pour spécifier que la fonction peut accepter tout ce qui est de type Object.

D'un autre côté, l'utilisation de dynamic signifie que le système Dart ne peut pas exprimer correctement le type que vous souhaitez utiliser:

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

Étant donné que Dart ne prend actuellement pas en charge les types d'union, il n'existe aucun moyen d'exprimer le type Email | String nous sommes donc obligés d'utiliser dynamic pour accepter tous les types et ensuite gérer uniquement les cas où le type nous intéresse.

5
Pixel Elephant

j'ai également remarqué que les méthodes d'extension ne fonctionnent pas correctement avec Dynamic mais fonctionnent correctement avec Object.


// 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