Как использовать один и тот же общий тип в StatefulWidget и виджете состояния?

#flutter #dart

#flutter #dart

Вопрос:

Ниже приведен макет кода для универсального StatefulWidget, который использует FutureBuilder. Я получаю следующую ошибку при создании экземпляра FutureBuilder:

 type '(User) => Future<List<User>>' is not a subtype of type '(dynamic) => Future<List<dynamic>>'
 

Я подозреваю, что ошибка заключается в том, что компилятор не будет знать об этом T , и U они одинаковы, поэтому U объявляются как динамические, а T как User ? Как бы мне изменить этот код, чтобы тип, используемый для общего в StatefulWidget, передавался в виджет состояния?

 Widget build(BuildContext context) => TestWidget<User>();


class TestWidget<T> extends StatefulWidget {
  final Future<List<T>> Function(T) myFunc = (_) => Future<List<T>>(null);

  @override
  _TestState<T> createState() => _TestState<T>();
}

class _TestState<U> extends State<TestWidget> {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<U>>(
        future: widget.myFunc(null),
        builder: (context, snapshot) {
          return Container();
        });
  }
}
 

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

1. Вы можете легко проверить, что U совпадает с T. На самом деле, вам даже не нужно изменять возвращаемый тип состояния создания: State createState() => _TestState<T>();

2. Проблема в вашем объявлении myFunc. Вероятно, вам потребуется создать именованное будущее для выполнения какой-либо работы.

3. Я совершенно не понимаю, как это вообще скомпилировано, учитывая, что вы передаете null в качестве вычисления Future

4. Future<List<T>> myFunc(_) async { return []; } было бы рабочим объявлением

5. Спасибо @AlexeySubbotin. Да, будущее бесполезно, но оно скомпилировано и запущено. Я больше пытался показать свою борьбу с дженериками. Мое фактическое будущее работает нормально.

Ответ №1:

Для тех, кто ищет решение, вы можете увидеть, как FutureBuilder решил эту проблему. Вместо того чтобы писать возвращаемый тип _TestState<T> для createState() метода, вы бы написали State<TestWidget<T>> .

  State<TestWidget<T>> createState() => _TestState <T>();
 

Ответ №2:

В итоге я эффективно создал вторую build() функцию в классе StatefulWidget, которая использует T общий. Он вызывается из build() класса состояния. Таким образом, класс состояния не заботится о дженериках. Я бы переключился на StatelessWidget с управляемыми состояниями, но мне нужно использовать AutomaticKeepAliveClientMixin, поэтому пришлось придерживаться StatefulWidget. Мой фактический класс состояния использует mixin и имеет немного больше возможностей.

 class TestWidget<T> extends StatefulWidget {
  final Future<List<T>> Function(T) myFunc = (_) => Future<List<T>>(null);

  Widget build(BuildContext context) {
    return FutureBuilder<List<T>>(
        future: myFunc(null),
        builder: (context, snapshot) {
          return Container();
        });
  }

  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<TestWidget> {
  @override
  Widget build(BuildContext context) {
    return widget.build(context);
  }
}