在 Flutter 应用程序中,我有一个 Row
的 Column
s 小部件层次结构。但是我想添加一个额外的 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
的父类(super class)型尽管。如果我将其修改为: Column getColumn(List<DAO> column, int index, 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
没关系,我希望列表是父类(super class)类型,这样我就可以向它添加各种类型的小部件。
最佳答案
当您调用 column.map
, Dart 根据内部函数返回的内容推断类型。在这种情况下,它返回 MyWidget
, 所以即使 Dart 的类型系统允许你声明 items
作为 List<Widget>
,其实是一个List<MyWidget>
. (据说在即将发布的 Dart 版本中会消除这种歧义。)
要解决此问题,您需要将类型参数添加到 map
明确说明您希望它返回什么样的列表:
List<Widget> items = column.map<Widget>((c) => MyWidget(data: c)).toList();
另一方面,在 Dart 中的转换是使用 as
完成的。关键词。例如,如果你想使用强制转换来解决这个问题,它看起来像这样:List<Widget> items = column.map((c) => MyWidget(data: c) as Widget).toList();
但是 map
上的类型参数在我看来是更清洁的方法。这是一个问题的原因是,与大多数编程语言不同,Dart allows the assignment of supertype values to subtype variables .这实质上意味着,如果您将父类(super class)型值分配给子类型变量,编译将允许它,即使运行时不允许。
以以下为例:
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
到 int
.在大多数强类型语言中,这仍然会导致编译错误,因为即使所有 int
是 num
s,并非全部 num
是 int
s,所以不保证值和变量的兼容性。然而,Dart 决定在编译中无论如何都允许赋值,并且直到程序运行它才会抛出类型不匹配错误。我一辈子都想不出为什么 Dart 工程师以这种方式设计语言的原因,因为我能看到的唯一实际结果是将易于发现的编译错误更改为潜在的难以捉摸的运行时错误。我能想到的唯一可能的理由是,它是为了与 JavaScript(Dart 最初是为它开发的)的互操作性,并且是 Dart 早期作为弱类型语言的产物。这是一个相当大的设计缺陷,正如我之前所说,我相信 future 版本的 Dart 将删除这个“功能”(虽然我找不到我读过的页面,所以我希望我不只是在抽烟某物)。
关于list - 尝试将父类(super class)对象添加到列表时如何克服列表子类型推断问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63541104/