Почему dart выводит тип переменной как int, когда я явно говорю, что тип двойной?

#dart

Вопрос:

Вот пример из документа

В документе говорится, что целочисленные литералы автоматически преобразуются в двойные, когда это необходимо:

 double z = 1; // Equivalent to double z = 1.0.
 

Но когда я проверяю runtimeType тип, это int

 print(z.runtimeType); // prints to int
 

Ответ №1:

Я предполагаю, что вы тестируете с помощью dartpad.dev или скомпилировали свой код на JavaScript. В JavaScript нет отдельных типов int , и double поэтому Dart просто угадывает тип при использовании runtimeType на основе текущего значения, поскольку JavaScript представляет все числа как double внутренние.

Но если мы работаем в виртуальной машине Dart или скомпилированы в машинный код, мы можем определить тип. Таким образом, ваш пример будет возвращен double как тип z , если он работает с виртуальной машиной Dart.

 void main(List<String> args) {
  print(1.1.runtimeType); // dartpad: double, dartvm: double
  print(1.0.runtimeType); // dartpad: int, dartvm: double
  print(1.runtimeType);   // dartpad: int, dartvm: int
}
 

См. Также Примечание о различном поведении int типа при компиляции в JavaScript в документации Dart:
https://api.dart.dev/stable/2.12.3/dart-core/int-class.html

Более подробный пример показан здесь, где мы можем увидеть, как double объявленная переменная ведет себя по-разному при запуске кода Dart в DartVM против скомпилированного JavaScript:

 void main(List<String> args) {
  print('| toString | runtimeType | is int | is double |');

  for (double i = 0; i <= 2; i  = 0.5) {
    print('| ${i.toString().padRight(8)} | '
        '${i.runtimeType.toString().padLeft(11)} | '
        '${(i is int).toString().padLeft(6)} | '
        '${(i is double).toString().padLeft(9)} |');
  }
}
 

Который возвращает следующее с помощью DartPad:

 | toString | runtimeType | is int | is double |
| 0        |         int |   true |      true |
| 0.5      |      double |  false |      true |
| 1        |         int |   true |      true |
| 1.5      |      double |  false |      true |
| 2        |         int |   true |      true |
 

В то время как ДартВМ возвращается:

 | toString | runtimeType | is int | is double |
| 0.0      |      double |  false |      true |
| 0.5      |      double |  false |      true |
| 1.0      |      double |  false |      true |
| 1.5      |      double |  false |      true |
| 2.0      |      double |  false |      true |
 

И int мы можем сделать то же самое:

 void main(List<String> args) {
  print('| toString | runtimeType | is int | is double |');

  for (int i = 0; i <= 2; i  = 1) {
    print('| ${i.toString().padRight(8)} | '
        '${i.runtimeType.toString().padLeft(11)} | '
        '${(i is int).toString().padLeft(6)} | '
        '${(i is double).toString().padLeft(9)} |');
  }
}
 

Дартс:

 | toString | runtimeType | is int | is double |
| 0        |         int |   true |      true |
| 1        |         int |   true |      true |
| 2        |         int |   true |      true |
 

ДартВМ:

 | toString | runtimeType | is int | is double |
| 0        |         int |   true |     false |
| 1        |         int |   true |     false |
| 2        |         int |   true |     false |
 

Комментарии:

1. Вы говорите, что JavaScript внутренне представляет все числа как двойные, тогда во всех ваших примерах тип на dartpad должен быть двойным, но это не так.

2. Я говорю, что runtimeType вы догадываетесь, каким был бы тип, если бы это был обычный код дротика. Это связано с тем, что у вас есть некоторые ожидания (как у программиста) относительно типов, когда вы программируете в Dart. Например, вы ожидаете a int при добавлении двух int объектов. Но за кулисами все числа всегда double находятся в JavaScript.

3.Один из способов взглянуть на это-сказать, что все числа Dart являются double s при компиляции в JavaScript, но некоторые из них также int являются s. Это похоже на то, как если бы объект number fori 1 реализовывал и int то, и double другое одновременно (к счастью, интерфейсы совместимы). Если вы проверите 1 is double или 1 is int , оба дадут true . runtimeType Получатель должен лгать, нет реального класса, реализующего оба типа, поэтому он возвращается int , когда это возможно, а double когда нет. На практике никогда ни для чего не используйте runtimeType !

4. @lrn Ах да, забыл об этом. Обновил пример, чтобы добавить в него некоторые ваши данные. И да, «никогда runtimeType ни для чего не используйте!» нельзя говорить слишком часто (может быть, когда-нибудь это предупреждение будет добавлено в документацию API?) 🙂