Home > other >  How to copy a Map in dart without getting Reference of the old one
How to copy a Map in dart without getting Reference of the old one

Time:12-07

I have a map that i get from my service and i want to copy it into 2 new Maps without being referenced and every time i change a value into one, value change to other too.

This is the Initial Map from my service config.UserGroups and i copy it like this

SavedSettings.UserGroups = new Map.from(config.UserGroups);
UnSavedSettings.UserGroups = new Map.from(config.UserGroups);

This Map is dynamic but it has String,object

Do we have an easy way to bypass reference;

CodePudding user response:

What you are asking for is called deep copying and is something you need to implement yourself for your data structures since List and Map just contains references to objects. So when you are making a copy of a List or Map, you are copying the references and not the objects inside the collection.

So the correct solution would be to make some logic which allows you to make copies of UserGroup objects and put these into your new list.

But.... if you are not scared of hacky solutions....

Section with hacky solution

If you really want to have some way to get deep copy from the Dart language (and don't care if the solution is kinda hacky) it is in theory possible by make use of the idea that we can send objects to isolates which are deep copied if possible.

So we can create an ReceivePort and send our object to our self. An example of this can be seen in this example:

class MyObject {
  int value;

  MyObject(this.value);

  @override
  String toString() => 'MyObject($value)';
}

Future<void> main() async {
  final list1 = [MyObject(5)];
  final list2 = await hackyDeepCopy(list1);

  list2[0].value = 10;

  print(list1); // [MyObject(5)]
  print(list2); // [MyObject(10)]
}

Future<T> hackyDeepCopy<T>(T object) async =>
    await (ReceivePort()..sendPort.send(object)).first as T;

This "solution"/hack comes with some limitations when it comes to data we can copy:

The content of message can be:

  • Null
  • bool
  • int
  • double
  • String
  • List or Map (whose elements are any of these)
  • TransferableTypedData
  • SendPort
  • Capability

In the special circumstances when two isolates share the same code and are running in the same process (e.g. isolates created via Isolate.spawn), it is also possible to send object instances (which would be copied in the process). This is currently only supported by the Dart Native platform.

https://api.dart.dev/stable/2.14.4/dart-isolate/SendPort/send.html

It is the "In the special circumstances when two isolates share the same code and are running in the same process" part we makes use of in hackyDeepCopy which allows us to also deep copy custom made objects.

Another limitation is that hackyDeepCopy needs to be async which is kinda annoying if your code is not already async.

And lastly, this only really works on native platforms (so no Dart-running-as JavaScript stuff).

  • Related