Проблема с универсальными типами, которая простирается от num и приведения типов от int к double

У меня вопрос по поводу дженериков в дротике. У меня есть следующий код дротика с параметром универсального типа, который расширяет число. В моем классе я хочу теперь определить переменную типа T со значением ноль. Это кажется невозможным. Может ли кто-нибудь объяснить мне, почему это так?

class A<T extends num> {
  T t = 0; // error: A value of type 'int' can't be assigned to a variable of type 'T'.
  num n = 0; // works 
}

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

A() {
 var list = List<T>.filled(10, 0 as T)
}

который работает для A<int>(), но не работает для A<double>() с сообщением об ошибке

тип int не является подтипом типа double в приведении типа

Что сбивает с толку, потому что, начиная с Dart 2.1, можно передать int в двойную переменную, например:

double x = 0;

Итак, как я могу это решить? Единственная возможность действительно проверить тип в моем конструкторе и сгенерировать список с 0 или 0,0 в зависимости от типа T?


person Dimitrios Begnis    schedule 25.11.2020    source источник
comment
0 as double не будет работать для виртуальной машины Dart, потому что int не может быть преобразован в double. double x = 0; не требует приведения типов; язык рассматривает его как синтаксический сахар для double x = 0.0;, поэтому он работает только для целочисленных литералов. Думаю, вам нужно будет явно проверить T.   -  person jamesdlin    schedule 25.11.2020


Ответы (3)


Нет простого выражения, которое может оцениваться как 0 или 0.0 в зависимости от того, к чему T привязан во время выполнения. Тип выражения в Dart определяется во время компиляции, и вы не знаете фактический тип T до времени выполнения.

Что вы можете сделать:

T t = 0.0 is T ? (0.0 as T) : (0 as T);

Если кому-то удастся создать T<Never>, то одно из этих приведений будет брошено, что, вероятно, именно то, что вы хотите.

Если у вас есть другое значение типа T, вы можете:

class A<T extends num> {
  T t;
  A(T someValue) : t = (someValue * 0) as T;
}

Как правило, универсальные шаблоны Dart (параметры типа) предназначены для классов, которые обрабатывают значения типов параметров типа в общем одинаково, независимо от аргумента типа. Здесь вы пытаетесь сделать специализацию типов, а не быть типом generic, поэтому у вас нет языковой поддержки для этого.

Вам, вероятно, будет лучше создать классы ANum, AInt и ADouble и создать тот, который вам нужен - тогда вам также не придется беспокоиться о A<Never> (или A<Null> безопасности до нуля).

person lrn    schedule 25.11.2020

Самое простое решение - добавить в конструктор нулевое значение. Что-то подобное:

class A<T extends num> {
  final T zero;
  A(this.zero) : assert(zero != null) {        
    var list = List<T>.filled(10, zero);
  }
}
person ChessMax    schedule 25.11.2020

Используйте фактическое двойное 0,0, а не 0.

person Randal Schwartz    schedule 25.11.2020
comment
Это работает для двойников, но затем я получаю сообщение об ошибке A<int>(), потому что type 'double' is not a subtype of type 'int' in type cast. Мне нужно универсальное решение, которое работает независимо от фактического типа T. - person Dimitrios Begnis; 25.11.2020
comment
У нас нет типов профсоюзов (пока), так что вам пока придется мыслить твердо и здраво. - person Randal Schwartz; 25.11.2020