You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Dart中声明List<MediaItem?>后赋值null仍报错,需添加方法空安全?

Dart空安全列表赋值null报错问题

场景复现

先定义两个列表:

List<MediaItem?> playlist = [];    
List<Item> items = [Item(data:'vasya')];

对应的两个模型类:

class MediaItem {
  final String id;
  
  MediaItem({
    required this.id
  });
}

class Item {
  final String data;
  
  Item({
    required this.data,
  });
  
  MediaItem toMediaItem() => MediaItem(
    id: data,
  );
}

通过map方法填充playlist列表:

playlist = items.map(
  (el) => el.toMediaItem()
).toList();

尝试给列表元素赋值null:

playlist[0] = null;

此时IDE/DartPad没有报错提示,但运行时会抛出错误:

Uncaught Error: TypeError: null: type 'JSNull' is not a subtype of type 'MediaItem'

只有将toMediaItem方法的返回类型改为可空后,代码才能正常运行:

MediaItem? toMediaItem() => MediaItem(
  id: data,
);

疑问

明明声明了List<MediaItem?>,理论上列表元素可以是MediaItem或null,为什么赋值null会触发运行时错误?

问题根源

核心问题在于map操作生成的列表实际类型和变量声明类型不匹配:

  • 当toMediaItem返回MediaItem(非空)时,items.map(...)返回的是Iterable<MediaItem>,调用toList()后得到的是**底层类型为List<MediaItem>**的列表——这个列表本质上只能存储非空的MediaItem实例,不支持存入null。
  • 虽然你把这个列表赋值给了声明为List<MediaItem?>的变量playlist,但这只是Dart允许的隐式向上转型,列表的实际运行时类型并没有改变,依然是List<MediaItem>。所以当你尝试存入null时,就会触发类型错误。

当修改toMediaItem的返回类型为MediaItem?后,map返回的是Iterable<MediaItem?>,toList()生成的就是List<MediaItem?>类型的列表,底层支持存储null,赋值操作自然正常。

替代解决方案

如果不想修改toMediaItem的返回类型,也可以通过以下方式解决:

  • 显式指定map的泛型类型,让它生成可空类型的迭代器:
playlist = items.map<MediaItem?>((el) => el.toMediaItem()).toList();
  • 直接往已声明的List<MediaItem?>中添加元素,而不是重新赋值:
playlist.addAll(items.map((el) => el.toMediaItem()));

内容的提问来源于stack exchange,提问作者user3221449

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 07:53:42