在颤振中通过 Function(T) 传递泛型类型

Posted

技术标签:

【中文标题】在颤振中通过 Function(T) 传递泛型类型【英文标题】:passing generic type by Function(T) in flutter 【发布时间】:2020-01-13 03:32:59 【问题描述】:

我正在尝试创建一个通用的消费者小部件,以方便其子视图模型。因此我有两个功能。一个在 ViewModel 初始化后具有函数(T),另一个用于将模型传递给其子 Widget。

在泛型类中是 ChangeNotifier 的子类,它工作正常,直到我想在两个函数中发送 T 值。

然后我收到以下错误:

type '(OnBoardingViewModel) => Null' 不是 type 的子类型 '(ChangeNotifier) => 无效'

type '(BuildContext, OnBoardingViewModel, Widget) => Scaffold' 不是 类型的子类型 '(BuildContext, ChangeNotifier, Widget) => Widget'

但是当我将扩展类型从 ChangeNotifier 更改为 OnBoardingViewModel 时,一切正常。

有人可以帮助我或解释为什么这不起作用吗?

import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:provider/provider.dart';

class StateFullConsumerWidget<T extends ChangeNotifier> extends StatefulWidget

  StateFullConsumerWidget(@required this.builder,Key key,this.onPostViewModelInit,this.child) : super(key : key);

  final Widget Function(BuildContext context, ChangeNotifier value, Widget child) builder;
  final Widget child;

  final void Function(T) onPostViewModelInit;

  @override
  _StateFullConsumerWidgetState<T> createState() => _StateFullConsumerWidgetState<T>();


class _StateFullConsumerWidgetState<T extends ChangeNotifier> extends State<StateFullConsumerWidget>
  T _viewModel;
  @override
  void initState() 
    // assign the model once when state is initialised
    _viewModel = GetIt.instance.get<T>();
    widget.onPostViewModelInit(_viewModel);


    super.initState();
  
  @override
  Widget build(BuildContext context) 
    return ChangeNotifierProvider<T>(
      builder: (context) => _viewModel,
      child: Consumer<T>(
        builder: widget.builder,
        child: widget.child,
      ),
    );
  


我的小部件

StateFullConsumerWidget<OnBoardingViewModel>(
      onPostViewModelInit: (viewModel)
        buildIntroList(viewModel);
        viewModel.maxPages = _introWidgetsList.length;
      ,
      builder: (context,viewModel,child) 
        return Scaffold(
          key: widget.scaffoldKey,
          body: SafeArea(
            child: Container(),
            ),
          ),
        );
      ,
    );

我的视图模型

import 'package:flutter/material.dart';

class OnBoardingViewModel extends ChangeNotifier

  OnBoardingViewModel()

  

【问题讨论】:

【参考方案1】:

您使用泛型类型T 的方式不完整。 StateFullConsumerWidget_StateFullConsumerWidgetState 类在您的代码中编写的关系是这样的:StateFullConsumerWidget 使用与其自身相同的 T 类型参数创建其状态,因此小部件知道该状态使用相同的泛型类型确实如此。但是,从_StateFullConsumerWidgetState 的角度来看,该类是这样声明的:

class _StateFullConsumerWidgetState<T extends ChangeNotifier> 
    extends State<StateFullConsumerWidget>

问题是状态类使用StateFullConsumerWidget的一般形式,因此_StateFullConsumerWidgetState作为类型参数接收的TStateFullConsumerWidgetT之间没有明确的关系使用。 Dart 不知道如何调和这种模棱两可的关系,因此它默认使用类型约束允许的最小公分母,即ChangeNotifier

因此,当您尝试将T 视为OnBoardingViewModel 时,Dart 会抛出错误,因为据状态类所知,父窗口小部件的TChangeNotifier,而不是@987654338 @。

您可以通过在声明状态类时传递类型参数来解决此问题:

class _StateFullConsumerWidgetState<T extends ChangeNotifier> 
    extends State<StateFullConsumerWidget<T>>

【讨论】:

【参考方案2】:

我不确定为什么会这样,但是 dart 编译器无法将 StateFullConsumerWidget 中的类型 T 识别为 _StateFullConsumerWidgetState 的相同类型 T。如果你将函数传递给 State 一切都会按预期工作。

结果代码:

class StateFullConsumerWidget<T extends ChangeNotifier> extends StatefulWidget

  StateFullConsumerWidget(@required this.builder,Key key,this.onPostViewModelInit,this.child) : super(key : key);

  final Widget Function(BuildContext context, T value, Widget child) builder;
  final Widget child;

  final Function(T viewModel) onPostViewModelInit;

  @override
  _StateFullConsumerWidgetState<T> createState() => _StateFullConsumerWidgetState<T>(onPostViewModelInit, builder);


class _StateFullConsumerWidgetState<T extends ChangeNotifier> extends State<StateFullConsumerWidget>
  final Function(T viewModel) _onPostViewModelInit;
  final Widget Function(BuildContext context, T value, Widget child) _builder;
  T _viewModel;

  _StateFullConsumerWidgetState(this._onPostViewModelInit, this._builder);

  @override
  void initState() 
    // assign the model once when state is initialised
    _viewModel = GetIt.instance.get<T>();
    _onPostViewModelInit(_viewModel);
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    return ChangeNotifierProvider<T>(
      builder: (context) => _viewModel,
      child: Consumer<T>(
        builder: _builder,
        child: widget.child,
      ),
    );
  

【讨论】:

以上是关于在颤振中通过 Function(T) 传递泛型类型的主要内容,如果未能解决你的问题,请参考以下文章

Java之泛型<T> T与T的用法

C#如何将类型Type作为泛型T的参数T传递

在颤振中通过路由传递数据时检测到 null 类型的值

TS错误:“找不到名称'T'如何通过泛型?

Java泛型理解

Dart泛型没有根据文档具体化