为何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
相关产品推荐
相关产品推荐

