当启用空安全时,默认的“List”构造函数不可用。尝试使用列表字面量、“List.filled”或“List.generate”。

59

为什么在Dart的空安全后,List()构造函数不可访问?

// Compile time error: 'List' is deprecated and shouldn't be used.
// The default 'List' constructor isn't available when null safety is enabled. 
// Try using a list literal, 'List.filled' or 'List.generate'.
List<int> foo = List(); 

然而,您仍然可以执行以下操作:
List<int> foo = []; // No error

那么,这两者之间有什么区别呢?要么两个都显示错误,要么两个都不显示。

@Estradiaz 这不是真的,只要你没有明确地给它一个长度,List() 也是可增长的。 - iDecode
@Estradiaz 当我说 List<int> 时,我告诉编译器 List 和它可能包含的任何元素都必须是非空的。在第一种情况下,我只是创建了一个空列表,并在第二个转换中做了同样的事情,其中一个不被允许,但另一个被允许。这就是问题所在。 - iDecode
3
您可以阅读此语言问题中讨论更改的原因,了解移除 List() 构造函数的相关信息:https://github.com/dart-lang/language/issues/746 - julemand101
1
这也在理解空安全文章中有所解释。 - jamesdlin
4个回答

116

简短回答:

使用空安全操作代替之前的操作

var foo = List<int>();  // Now error
var bar = List<int>(n); // Now error
var baz = List<int>(0); // Now error

请使用以下内容:

var foo = <int>[];           // Always the recommended way.
var bar = List.filled(1, 0); // Not filled with `null`s.
var baz = List<int>.empty();

长答案:

List 构造函数有两个用途:

  • new List() 创建一个空的可增长列表,相当于 []
  • new List(n) 创建一个长度为 n 的固定长度列表,其中填充了 null

在空安全模式下,第二种用法大多数情况下是不安全的,也没有好的解决方法。虽然可以强制类型参数为非空,但 List<T>(4) 仅在 T 是可空的情况下才起作用。没有办法强制执行。

因此,List(n) 模式需要被移除(由 List.filled(n, value) 替换,它会强制您提供一个填充值)。 这样就只剩下了 List(),它并没有很好地发挥作用。您可以使用 [] 代替它(而且您应该这样做!),所以决定完全删除构造函数——所有使用它的地方都是不安全或无用的。 (此外,它已经是一个奇怪的构造函数了,因为如果我们想要正确地使其空安全,它将有一个可选参数,具有非空类型和没有默认值。)

通过完全删除它,有可能在未来引入一个新的 List 构造函数,例如作为 List.filled 的更短别名。我们可以期待一下。


我希望官方文档中也提到了这一点。你的回答比那篇理解空安全文章的作者描述为什么List()被移除要清晰得多。 - iDecode
1
那篇文章非常好地描述了我们做什么以及主要原因,但是深入所有细节会有些过头。文章充满了信息,避免读者负担过重也很重要。如果你从那一部分中得到了一个东西,那就应该是“List构造函数已经不存在了”,这就是我们所能希望的。 (此外,使用[]而不是List()的建议并不新鲜,https://dart.dev/guides/language/effective-dart/usage#do-use-collection-literals-when-possible,因此作者可能认为不需要重复提及。) - lrn
List.empty({bool growable = false}) 构造函数也值得一提。我在这里陷入了一些困惑,因为我不确定 [] 语法是否会创建可增长的列表(除非您使用常量空列表 const [],当然这是完全有道理的,但我没有考虑到)。 - jayjw
同意。List.empty 构造函数仅用于创建空的不可增长或潜在不可增长的列表。对于可增长的列表,您应该使用列表字面量。 - lrn
@lrn 引用您的 if we wanted to make it ... no default value -- 在 List<T>() 中有什么问题。为了使 List<int>() 具有空值安全性,我们不需要可选参数。它只是等同于 <int>[] - iDecode
显示剩余4条评论

10
除了@lrn先生提到的内容外,您还可以使用以下方式创建列表:
List<int> foo = List<int>.empty(growable: true); // []

3
这是因为默认的 List() 元素已被弃用,你可以尝试使用如下的 List.filled() 元素。
void display() {
    var fixedList = new List<int>.filled(5, 0, growable: false);
    fixedList[0] = 0;
    fixedList[1] = 10;
    fixedList[2] = 20;
    fixedList[3] = 30;
    fixedList[4] = 40;
    print('Elements in the list are as follows: $fixedList');
  }
} 

对于可增长长度列表,您可以尝试按以下方式进行:

void main() {
    var growableList = new List<int>.filled(0,0, growable:true);
    growableList = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90];
    print('The elements in the growable list include: $growableList');
  }

1
嗨,“这是因为默认的List()元素已被弃用”- 这就是我提出问题的原因,而对于“你是否尝试使用List.filled()”,Lrn已经提供了这个选项。 - iDecode
假设这是一个对象列表,例如List<OnDemandVideo> - Lutaaya Huzaifah Idris

0

_items = List<DropdownMenuItem<String>>(); 可以使用空安全写成:

_items = List<DropdownMenuItem<String>>.from(<DropdownMenuItem<String>>[]);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接