为什么在 Dart 的列表定义中使用 if 和 for?

Pte*_*tyl 2 dart flutter

Dart 支持在创建列表期间使用“if”和“for”:

var nav = [
  'Home',
  'Furniture',
  'Plants',
  if (promoActive) 'Outlet'
];
Run Code Online (Sandbox Code Playgroud)

和:

var listOfInts = [1, 2, 3];
var listOfStrings = [
  '#0',
  for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
Run Code Online (Sandbox Code Playgroud)

这有什么意义?它比创建一个列表,然后像其他编程语言一样附加到它有什么好处:

var nav = [
  'Home',
  'Furniture',
  'Plants',
];

if (promoActive) nav.add('Outlet');
Run Code Online (Sandbox Code Playgroud)

Rém*_*let 5

有多种因素在起作用:

  • 表现
  • 可读性

可读性

实现此功能的主要原因是ListView/Stack和所有其他带有children参数的小部件。

这些小部件不支持null作为参数,这导致了大量的挫败感(这导致了这个 github 问题:Allow null values in childor children[]collections to signal that an element should not be draw

简而言之,问题在于小部件的声明性意味着使用add& co 并不是一个真正的选择。

如果没有if/for内部集合,我们将不得不写:

List<Widget> children = [
  Foo(),
]

if (condition)
  children.add(Bar());

return Scaffold(
  body: ListView(
    children: children,
  ),
);
Run Code Online (Sandbox Code Playgroud)

这使得很难理解屏幕上呈现的内容,因为构建方法现在是碎片化的

或者,我们必须写:

return Scaffold(
  body: ListView(
    children: [
      Foo(),
      condition ? Bar() : null,
    ].where((e) => e != null).toList(),
  ),
);
Run Code Online (Sandbox Code Playgroud)

这更具可读性,但明显缺乏灵活性,因为比这个例子更复杂的东西将难以实现

作为解决方案,我们现在可以写:

return Scaffold(
  body: ListView(
    children: [
      Foo(),
      if (condition)
        Bar(),
    ]
  ),
);
Run Code Online (Sandbox Code Playgroud)

这既可读,又易于编写,而且不易出错。

表现

此功能的一个有趣方面是,它提高了 Flutter 应用程序的性能。

写作时要考虑的事情:

final list = <Widget>[
  Foo(),
];

if (condition)
  list.add(Bar());
Run Code Online (Sandbox Code Playgroud)

是通过使用add,列表大小会随着时间而变化。这意味着 anyadd可能会导致List重新分配以支持更多项目,这是昂贵的。

同样的问题适用于:

ListView(
  children: [
    Foo(),
    condition ? Bar() : null,
  ].where((e) => e != null).toList(),
)
Run Code Online (Sandbox Code Playgroud)

我们有效地实例化了List两次并对其所有项目进行了两次迭代(一次为where,另一次为ListView

使用if/ forinside 集合时不会发生这些性能问题。写作时:

ListView(
  children: [
    Foo(),
    if (condition)
      Bar(),
  ],
);
Run Code Online (Sandbox Code Playgroud)

这会立即分配List具有正确大小的 ,并且如果执行一次且仅执行一次分配。

原因是,实际上这种语法等效于:

List<Widget> children;
if (condition)
  children = [
    Foo(),
    Bar(),
  ];
else
  children = [
    Foo(),
  ]
Run Code Online (Sandbox Code Playgroud)

既不涉及add也不涉及where/toList