如何解决尝试在列表中添加超类对象时如何克服列表子类型推断问题?
在Flutter应用中,我有Row
个小部件层次结构中的一个Column
。但是,我想在小部件的每个交替列中添加一个额外的SizedBox
。
Column getColumn(List<DAO> column,int index,BoardLayout layout) {
final key = column.map((c) => c.toString()).toList().join('_');
final items = column.map((c) => MyWidget(data: c)).toList();
if (index % 2 == 0 && layout == BoardLayout.Hexagonal)
items.add(SizedBox(height: magicNumber));
return Column(children: items);
}
这将产生"The argument type 'SizedBox' can't be assigned to the parameter type 'MyWidget'."
的编译时错误。这是可以理解的,因为final items
必须具有推断的类型List<MyWidget>
,然后我想添加一个SizedBox
。尽管所有这些都具有Widget
的超类型。如果我将其修改为:
Column getColumn(List<DAO> column,BoardLayout layout) {
final key = column.map((c) => c.toString()).toList().join('_');
List<Widget> items = column.map((c) => MyWidget(data: c)).toList();
if (index % 2 == 0 && layout == BoardLayout.Hexagonal)
items.add(SizedBox(height: magicNumber));
return Column(children: items);
}
它会编译,但随后会抛出_TypeError
"type 'SizedBox' is not a subtype of type 'MyWidget' of 'value'"
的运行时异常。我还没有找到强制转换列表的方法。我尝试使用List的cast<T>
,并尝试使用显式的(Widget)
或(List<Widget>)
强制转换前缀,但尚未编译任何尝试。有什么可能的解决方案? MyWidget
或DAO
的详细信息无关紧要,我希望列表是超类类型,以便可以向其中添加各种类型的Widget。
解决方法
调用column.map
时,Dart根据内部函数返回的内容推断类型。在这种情况下,它将返回MyWidget
,因此即使Dart的类型系统允许您将items
声明为List<Widget>
,但实际上它是List<MyWidget>
。 (应该在即将发布的Dart版本中消除这种歧义。)
要解决此问题,您需要向map
添加类型参数,以明确说明您希望其返回的列表类型:
List<Widget> items = column.map<Widget>((c) => MyWidget(data: c)).toList();
另外要注意的是,使用as
关键字可以在Dart中进行投射。因此,例如,如果您想使用强制转换来解决此问题,它将看起来像这样:
List<Widget> items = column.map((c) => MyWidget(data: c) as Widget).toList();
但是我认为map
上的type参数是更干净的方法。
这是一个问题,其原因是与大多数编程语言Dart allows the assignment of supertype values to subtype variables不同。这实质上意味着,如果您将超类型值分配给子类型变量,即使运行时不允许,编译也会允许它。
以以下为例:
int a = 2.5; // Compilation error: double is not int
此代码显然会引发错误,因为double
不是int
。但是,如果将其更改为以下内容:
int a = 2.5 as num; // Linter warning: unnecessary cast
我们在IDE中获得此代码的唯一通知是不需要将double
强制转换为num
,但这现在已经掩盖了相当严重的错误。像以前一样,我们试图将double
的值分配给int
变量,但是由于强制转换,编译器看到的全部是我们试图将num
分配给{ {1}}。在大多数强类型语言中,这仍然会导致编译错误,因为即使所有int
都是int
,但并非所有num
都是num
,所以不能保证值和变量之间的兼容性。但是Dart还是决定允许编译中的赋值,直到程序运行时它才抛出类型不匹配错误。
我无法终生提出Dart工程师以这种方式设计语言的原因,因为我看到的唯一实际结果是将易于发现的编译错误更改为可能难以捉摸的运行时错误。我唯一能提出的理由是,它是为了与JavaScript(Dart最初为之开发)具有互操作性,并且是Dart较弱的一门语言的产物。这是一个非常重大的设计缺陷,就像我之前说过的那样,我相信Dart的未来版本将删除此“功能”(尽管我找不到我读到的页面是这样说的,所以我希望我不仅在吸烟东西)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。