为何索引和键均为常量时,打印值仍发生变化?(Dart/Flutter)
问题原因分析
核心问题在于对象的引用传递特性,不管是Dart还是JavaScript,对象类型(比如Map)都是按引用传递的,而非值复制。
具体执行过程拆解
- 首次调用
exec(b)时,count=1进入else分支,执行a[1]['values'][0]['options'] = selectedOption['options'];这一步,并没有复制b['options']的内容,而是把b['options']这个对象的内存引用赋值给了a对应的字段。此时a里的options和b里的options指向内存中同一个对象。 - 后续修改
b['options']['selected'] = 1、=2时,本质是修改这个共享对象的属性值,a里的options因为和b的options是同一个对象,所以会同步变化。 - 虽然首次执行后
count被设为0,不会再进入else分支修改a的结构,但之前建立的引用关联并未断开,所以每次打印a[1]['values'][0]['options']['selected']时,输出的都是那个共享对象当前的selected值。
解决方案:复制对象内容而非引用
如果希望a里的options不受b后续修改的影响,需要创建新的对象副本,而非直接赋值引用。在Dart中可以使用Map.from()复制Map内容:
void main() { var count = 1; var a = {}; exec(selectedOption) { if (count == 0) { print("NOTHING"); } else { print("ELSE"); a[1] = {}; a[1]['values'] = [ { "options": {}, } ]; // 复制对象内容,避免引用关联 a[1]['values'][0]['options'] = Map.from(selectedOption['options']); count = 0; } print(a[1]['values'][0]['options']['selected']); } var b = {}; b['options'] = {}; b['options']['selected'] = 0; exec(b); b['options']['selected'] = 1; exec(b); b['options']['selected'] = 2; exec(b); }
修改后运行输出
ELSE 0 NOTHING 0 NOTHING 0
此时a里的options是独立对象,后续修改b的options不会再影响a的值。
内容的提问来源于stack exchange,提问作者Tushar Kulkarni
相关产品推荐
相关产品推荐

