【问题标题】:How to clone (copy values) a complex object in Dart 2如何在 Dart 2 中克隆(复制值)复杂对象
【发布时间】:2018-12-23 10:59:40
【问题描述】:

我想使用 Dart 2 克隆一个复杂对象(复制值),而不是引用。

例子:

class Person {
  String name;
  String surname;
  City city;
}

class City {
  String name;
  String state;
}

main List<String> args {
  City c1 = new City()..name = 'Blum'..state = 'SC';
  Person p1 = new Person()..name = 'John'..surname = 'Xuebl'..city = c1;


  Person p2 = // HERE, to clone/copy values... Something similar to p1.clone();
}

这样做的方法(最佳实践)是什么?

更新说明:How can I clone an Object (deep copy) in Dart? 是不久前发布的。这里的重点是了解带来许多改进的 Dart 2 是否具有复制复杂对象的功能。

【问题讨论】:

  • 因为帖子是前段时间发的,是针对 Dart 1 版本的。我的目的是发布一个新帖子来专门讨论 Dart 2,它带来了出色的改进,并且可能与克隆复杂对象有关。

标签: dart


【解决方案1】:

对于您在这里向我们展示的课程,没有比这更短的了

Person p2 = Person()
  ..name = p1.name
  ..surname = p1.surname
  ..city = (City()..name = p1.city.name..state = p1.city.state);

如果您将clone 方法添加到PersonCity,那么您显然可以使用它。 该语言没有内置任何内容允许您复制对象的状态。

我建议更改类,至少通过添加构造函数:

class Person {
  String name;
  String surname;
  City city;
  Person(this.name, this.surname, this.city);
}
class City {
  String name;
  String state;
  City(this.name, this.state);
}

然后你可以通过写来克隆:

Person P2 = Person(p1.name, p1.surname, City(p1.city.name, p1.city.state));

(和ob-link关于名字)

我说没有复制对象的语言功能,但实际上,如果您可以访问dart:isolate 库:通过隔离通信端口发送对象。我不推荐使用该功能,但为了完整起见,它在这里:

import "dart:isolate";
Future<T> clone<T>(T object) {
  var c = Completer<T>();
  var port = RawReceivePort();
  port.handler = (Object o) {
    port.close();
    c.complete(o);
  }
  return c.future;
}

同样,我不推荐使用这种方法。 它适用于像这样的简单对象,但不适用于所有对象(并非所有对象都可以通过通信端口发送,例如,一流函数或任何包含一流函数的对象)。

编写你的类来支持你需要的操作,包括复制。

【讨论】:

  • 明白。我真的很想避免按属性做属性值的复制。在另一种选择中,使用隔离,它也有一些影响。或许等到 Dart 2 最终版本的发布,我们才能更直接一些。
  • Dart 非常希望避免有一种通用的方法来克隆对象而不通过构造函数。安全地允许克隆的唯一方法是要求类本身公开功能。从外部克隆一个类是脆弱和危险的。
【解决方案2】:

我的更简单的解决方案只是让clone() 返回一个新的Person 与当前值:

class Person {
  String name;
  String surname;
  City city;
  Person(this.name, this.surname, this.city);
  clone() => Person(name, surname, city);
}

您可能还需要递归地克隆 Person 中的对象。例如,在City 中创建一个类似的clone() 函数并将其用作city.clone()
对于字符串,您需要检查它们的行为或创建/添加清理它们的方法。

【讨论】:

    【解决方案3】:

    如前所述,没有内置解决方案,但如果您的想法是实现不可变值类型,您可以查看built_value

    https://medium.com/dartlang/darts-built-value-for-immutable-object-models-83e2497922d4

    【讨论】:

      【解决方案4】:

      我注意到使用Map.from() 进行浅拷贝而不是深拷贝

      要对包含另一个类的 Map 的类进行深层复制,一种解决方案是使用命名构造函数

      class MyClassB {
         int myVar;
         
         // Constructor
         MyClassB(this.id);
         
         // Named Constructor to do a deep clone
         MyClassB.clone(MyClassB b){
           id = b.id;
         }
      }
      
      class MyClassA { 
        Map<int,MyClassB> mapOfClassB;
      
        // Constructor
        MyClassA(this.myClassB)
      
        // Named constructor to do a deep clone
        MyClassA.clone(MyClassA a){
          Map<int,myClassB> m = {};
          myClassB  = a.mapOfClassB.forEach((k,v)=> m[k] = MyClassB.clone(v)); // Use the clone constructor here, if not the maps in MyClassA and MyClassB will be linked
        }
      }
      
      main() {
        var b1 = MyClassB(20);
        var a1 = MyClassA({0:b1});
        
        var a2 = MyClass1A.clone(a1);
        
        a2.mapOfClassB[0].id = 50;
        
        print(a1.mapOfClassB[0].id); // Should display 20
        print(a2.(a1.mapOfClassB[0].id) // Should display 50 
      }
      

      【讨论】:

        猜你喜欢
        • 2013-04-06
        • 2011-03-29
        • 2011-10-17
        • 2011-10-30
        • 2013-02-18
        • 1970-01-01
        • 2019-11-18
        • 1970-01-01
        • 2012-10-17
        相关资源
        最近更新 更多