List.forEach unable to modify element?

浪尽此生 提交于 2020-04-13 05:54:33

问题


I'm attempting to create a list of lists to imitate the functionality of a 2D array in Dart, and I was having trouble for a while figuring out how to make it work.

I originally used List.forEach in order to create the lists and fill them, but after each loop, it's as if I never created the lists. Here's what that code looked like:

currentMap = new List<List<int>>(height);
currentMap.forEach((e) {
    e = new List<int>(width);
    e.forEach((f) {
        f = 1;
    });
});

Printing currentMap resulted in a list of null. Here's what I have now:

currentMap = new List<List<int>>(height);
for(int i = 0; i < height; i++) {
    currentMap[i] = new List<int>(width);
    for(int j = 0; j < width; j++) {
        currentMap[i][j] = 1;
    }
}

This works exactly as I expected it to.

I understand that this is probably a very basic issue, and I am assuming that forEach does not allow you to modify the element, but I wanted some confirmation on that, and the Dart API docs do not specify except with the phrase "apples the function f to each element..." which may just not be clear to me.

Also, I am aware of things like the List.filled() constructor -- this is just how I am starting to build towards other functionality.

EDIT: Okay, I think I understand now. Arguments are "pass-by-sharing" which means that a copy of a reference to the object is made. This means that you can modify a member of a mutable object that is pointed to by the argument (as follows):

void function(MyObject o) {
    o.x = 5;
}

but trying to change what o points to will not change the argument after exiting the function, such as this:

void function(MyObject o) {
    MyObject p = new MyObject();
    o = p;
}

回答1:


Dart does not have variable references, all elements are passed as a reference to an object, not to a variable. (In other words, Dart is purely "call-by-sharing" like both Java and JavaScript).

That means that the e parameter to the forEach callback is just a normal local variable, and assigning to it has no effect outside the callback. The same goes for iterators: they return the value in the iterable, but it has no reference back to the iterable after that.

The double loop is what you want when you do "read-modify-write". You read a value from the list, modify it and store it back into the list using the list's index-set operator.

I know you know about List.filled, but just for other readers, I'll give the one-liner to create the two-dimensional array initialized to 1 values:

currentMap = new List.generate(height, (_) => new List.filled(width, 1));



回答2:


This is because e is only a reference to the List in currentMap not to a currentMap item.
You update a copy of the reference to a List, but this reference has no connection to currentMap.
After the loop, e just gets garbage collected.




回答3:


This is because of how an Enumerator works and I believe because the Enumerator is immutable You can't modify the collection items when it's being processed in a foreach... removing members and such.

See also:

http://msdn.microsoft.com/en-us/library/ttw7t8t6.aspx

What is the best way to modify a list in a 'foreach' loop?



来源:https://stackoverflow.com/questions/22210247/list-foreach-unable-to-modify-element

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!