Dart/Flutter中List字面量初始化配合级联notation的运行逻辑疑问
Dart级联运算符运行逻辑解答
你对代码运行逻辑的猜测是完全正确的,出现你疑惑的现象本质是对Dart语法的执行顺序理解偏差,下面逐一说明:
核心规则说明
你最初疑惑的“numberList = []执行完好像还有值”是因为你错误拆分了代码的执行顺序:numberList= []..add(1)..add(2)..addAll(numberList)是一整行完整的赋值语句,遵守两个Dart语法规则:
- 级联运算符
..的返回值是最初调用级联的对象本身,所有级联调用都在同一个对象上执行,不会生成新对象 - 赋值操作
=的执行顺序是先计算完右侧整个表达式的全部结果,再将结果的引用赋值给左侧变量,右侧表达式执行过程中,左侧变量的旧值不会被覆盖
完整执行流程拆解
- 执行
List<int> numberList=[10];,此时numberList变量指向内存中的列表A:[10] - 开始计算右侧整个表达式
[]..add(1)..add(2)..addAll(numberList):- 第一步创建新的空列表B:
[] - 调用列表B的
add(1)方法,列表B变为[1],级联返回列表B本身 - 调用列表B的
add(2)方法,列表B变为[1,2],级联返回列表B本身 - 调用列表B的
addAll()方法,此时还未执行赋值操作,numberList变量仍然指向旧的列表A[10],所以添加后列表B变为[1,2,10]
- 第一步创建新的空列表B:
- 右侧表达式计算完成,返回列表B,赋值给
numberList变量,此时numberList才指向新的列表B - 打印结果为
[1, 2, 10]
疑问解答
1. 如何调试查看每一步的添加操作
可以用Dart 2.17及以上版本内置的run扩展方法,在级联操作中插入打印或者断点逻辑,不需要修改原有代码结构:
void main() { List<int> numberList=[10]; numberList=[] ..add(1) ..run((temp) => print('add(1)执行后:$temp')) ..add(2) ..run((temp) => print('add(2)执行后:$temp,此时原numberList值:$numberList')) ..addAll(numberList) ..run((temp) => print('addAll执行后:$temp')); print(numberList); }
运行后就能看到每一步的变量状态,也可以在run方法内部打断点调试。
2. 如何给运行时生成的匿名临时列表定义名称
直接拆分级联写法,将原本匿名的临时列表提前显式声明即可,拆分后的代码和原代码逻辑完全等价:
void main() { List<int> numberList = [10]; // 显式声明原本匿名的临时列表,自定义变量名 List<int> newList = []; newList.add(1); newList.add(2); // 此时numberList还未被赋值,取的是旧值[10] newList.addAll(numberList); // 所有操作完成后再赋值给原变量 numberList = newList; print(numberList); }
内容的提问来源于stack exchange,提问作者Davoud
相关产品推荐
相关产品推荐

