是否支持语言在Dart中制作对象的完整(深层)副本?
仅限中学;有多种方法可以做到这一点,有什么区别?
感谢您的澄清!
答案 0 :(得分:13)
没有公开的问题似乎表明:
http://code.google.com/p/dart/issues/detail?id=3367
具体而言:
.. Objects have identity, and you can only pass around references to them. There is no implicit copying.
答案 1 :(得分:6)
Darts内置集合使用名为“from”的命名构造函数来完成此任务。请参阅此帖子:Clone a List, Map or Set in Dart
Map mapA = {
'foo': 'bar'
};
Map mapB = new Map.from(mapA);
答案 2 :(得分:4)
要复制一个没有引用的对象,我发现的解决方案与此处发布的解决方案相似,但是如果该对象包含MAP或LIST,则必须采用以下方式:
class Item {
int id;
String nome;
String email;
bool logado;
Map mapa;
List lista;
Item({this.id, this.nome, this.email, this.logado, this.mapa, this.lista});
Item copyWith({ int id, String nome, String email, bool logado, Map mapa, List lista }) {
return Item(
id: id ?? this.id,
nome: nome ?? this.nome,
email: email ?? this.email,
logado: logado ?? this.logado,
mapa: mapa ?? Map.from(this.mapa ?? {}),
lista: lista ?? List.from(this.lista ?? []),
);
}
}
Item item1 = Item(
id: 1,
nome: 'João Silva',
email: 'joaosilva@gmail.com',
logado: true,
mapa: {
'chave1': 'valor1',
'chave2': 'valor2',
},
lista: ['1', '2'],
);
// -----------------
// copy and change data
Item item2 = item1.copyWith(
id: 2,
nome: 'Pedro de Nobrega',
lista: ['4', '5', '6', '7', '8']
);
// -----------------
// copy and not change data
Item item3 = item1.copyWith();
// -----------------
// copy and change a specific key of Map or List
Item item4 = item1.copyWith();
item4.mapa['chave2'] = 'valor2New';
在dartpad上查看示例
答案 3 :(得分:3)
我想对于不太复杂的对象,你可以使用转换库:
import 'dart:convert';
然后使用JSON编码/解码功能
Map clonedObject = JSON.decode(JSON.encode(object));
如果您使用自定义类作为要克隆的对象中的值,则该类要么需要实现toJson()方法,要么必须为JSON.encode方法和reviver提供toEncodable函数解码调用的方法。
答案 4 :(得分:3)
它仅适用于可以用JSON表示的对象类型。
ClassName newObj = ClassName.fromMap(obj.toMap());
或
ClassName newObj = ClassName.fromJson(obj.toJson());
答案 5 :(得分:3)
尝试使用Dart提供的Copyable界面。
答案 6 :(得分:3)
没有深度克隆对象的内置方法 - 您必须自己提供方法。
我经常需要从 JSON 编码/解码我的类,所以我通常提供 MyClass fromMap(Map)
和 Map<String, dynamic> toJson()
方法。这些可用于创建深度克隆,方法是首先将对象编码为 JSON,然后将其解码回来。
但是,出于性能原因,我通常会实现一个单独的 clone
方法。这是几分钟的工作,但我发现这通常是值得的。
在下面的示例中,cloneSlow
使用 JSON 技术,而 cloneFast
使用显式实现的克隆方法。打印输出证明该克隆确实是一个深度克隆,而不仅仅是对 a
的引用的副本。
import 'dart:convert';
class A{
String a;
A(this.a);
factory A.fromMap(Map map){
return A(
map['a']
);
}
Map<String, dynamic> toJson(){
return {
'a': a
};
}
A cloneSlow(){
return A.fromMap(jsonDecode(jsonEncode(this)));
}
A cloneFast(){
return A(
a
);
}
@override
String toString() => 'A(a: $a)';
}
void main() {
A a = A('a');
A b = a.cloneFast();
b.a = 'b';
print('a: $a b: $b');
}
答案 7 :(得分:2)
很遗憾,没有语言支持。我要做的是创建一个名为copyable
的抽象类,可以在我想复制的类中实现:
abstract class Copyable<T> {
T copy();
T copyWith();
}
然后我可以按以下方式使用它,例如位置对象:
@override
Location copy() {
return Location(
longitude: this.longitude,
latitude: this.latitude,
timestamp: this.timestamp,
country: this.country,
locality: this.locality,
postalCode: this.postalCode,
name: this.name,
isoCountryCode: this.isoCountryCode,
bearing: this.bearing);
}
@override
Location copyWith({
String country,
String locality,
String name
}) {
return Location(
country: country,
locality: locality,
name: name,
longitude: this.longitude,
latitude: this.latitude,
timestamp: this.timestamp,
postalCode: this.postalCode,
isoCountryCode: this.isoCountryCode,
bearing: this.bearing);
}
答案 8 :(得分:0)
比方说,您想要深度复制一个对象 Person
,它的属性是其他对象 Skills
的列表。按照惯例,我们使用带有可选参数的 copyWith
方法进行深度复制,但您可以随意命名。
你可以这样做
class Skills {
final String name;
Skills({required this.name});
Skills copyWith({
String? name,
}) {
return Skills(
name: name ?? this.name,
);
}
}
class Person {
final List<Skills> skills;
const Person({required this.skills});
Person copyWith({
List<Skills>? skills,
}) =>
Person(skills: skills ?? this.skills.map((e) => e.copyWith()).toList());
}
请记住,仅使用 this.skills
只会复制列表的引用。因此原始对象和复制对象将指向相同的技能列表。
Person copyWith({
List<Skills>? skills,
}) =>
Person(skills: skills ?? this.skills);
如果您的列表是原始类型,您可以这样做。原始类型会自动复制,因此您可以使用这种较短的语法。
class Person {
final List<int> names;
const Person({required this.names});
Person copyWith({
List<int>? names,
}) =>
Person(names: names ?? []...addAll(names));
}
答案 9 :(得分:0)
很多答案都说你可以定义一个新的构造函数来启用深度复制,但 CONSIDER copying nullable field to enable type promotion
下的 Effective Dart Usage Guide 提供了一个更简单的解决方案。
文档建议使用局部变量来制作可用的副本。从标题可以推断出,如果可空字段有值,此技术还会将它们转换为不可空字段。
class UploadException {
final Response? response;
UploadException([this.response]);
@override
String toString() {
var response = this.response; // This makes a new copy.
if (response != null) {
return "Could not complete upload to ${response.url} "
"(error code ${response.errorCode}): ${response.reason}.";
}
return "Could not upload (no response).";
}
}
如果在整个代码库中广泛使用,那么围绕此局部变量的便利构造函数包装器将更合适。我认为这种技术更简洁,因为它减少了编写具有相同最终结果的代码量。
使用本地副本时要小心。如果您需要写回该字段,请确保这样做,而不要只写入局部变量。此外,如果该字段可能在本地仍在范围内时发生更改,则本地可能具有过时的值。有时最好在场上简单地使用 !
。
答案 10 :(得分:0)
创建一个辅助类:
class DeepCopy {
static clone(obj) {
var tempObj = {};
for (var key in obj.keys) {
tempObj[key] = obj[key];
}
return tempObj;
}
}
并复制您想要的内容:
List cloneList = [];
if (existList.length > 0) {
for (var element in existList) {
cloneList.add(DeepCopy.clone(element));
}
}
答案 11 :(得分:0)
//希望这项工作
void main() {
List newList = [{"top": 179.399, "left": 384.5, "bottom": 362.6, "right": 1534.5}, {"top": 384.4, "left": 656.5, "bottom": 574.6, "right": 1264.5}];
List tempList = cloneMyList(newList);
tempList[0]["top"] = 100;
newList[1]["left"] = 300;
print(newList);
print(tempList);
}
List cloneMyList(List originalList) {
List clonedList = new List();
for(Map data in originalList) {
clonedList.add(Map.from(data));
}
return clonedList;
}
答案 12 :(得分:0)
dart中深拷贝的示例。
void main() {
Person person1 = Person(
id: 1001,
firstName: 'John',
lastName: 'Doe',
email: 'john.doe@email.com',
alive: true);
Person person2 = Person(
id: person1.id,
firstName: person1.firstName,
lastName: person1.lastName,
email: person1.email,
alive: person1.alive);
print('Object: person1');
print('id : ${person1.id}');
print('fName : ${person1.firstName}');
print('lName : ${person1.lastName}');
print('email : ${person1.email}');
print('alive : ${person1.alive}');
print('=hashCode=: ${person1.hashCode}');
print('Object: person2');
print('id : ${person2.id}');
print('fName : ${person2.firstName}');
print('lName : ${person2.lastName}');
print('email : ${person2.email}');
print('alive : ${person2.alive}');
print('=hashCode=: ${person2.hashCode}');
}
class Person {
int id;
String firstName;
String lastName;
String email;
bool alive;
Person({this.id, this.firstName, this.lastName, this.email, this.alive});
}
以及下面的输出。
id : 1001
fName : John
lName : Doe
email : john.doe@email.com
alive : true
=hashCode=: 515186678
Object: person2
id : 1001
fName : John
lName : Doe
email : john.doe@email.com
alive : true
=hashCode=: 686393765
答案 13 :(得分:0)
假设您有课
Class DailyInfo
{
String xxx;
}
通过
创建类对象dailyInfo的新克隆。 DailyInfo newDailyInfo = new DailyInfo.fromJson(dailyInfo.toJson());
为此,您的课程必须已实现
factory DailyInfo.fromJson(Map<String, dynamic> json) => _$DailyInfoFromJson(json);
Map<String, dynamic> toJson() => _$DailyInfoToJson(this);
可以通过使用
使类可序列化来完成@JsonSerializable(fieldRename: FieldRename.snake, includeIfNull: false)
Class DailyInfo{
String xxx;
}
答案 14 :(得分:0)
晚了聚会,但是我最近遇到了这个问题,不得不采取以下措施:-
RandomObject {
int x;
int y;
RandomObject(int x, int y) {
this.x = x;
this.y = y;
}
RandomObject.clone(RandomObject randomObject): super(randomObject.x, randomObject.y);
}
调用RandomObject.clone似乎做了类似的事情。可以将其添加到抽象类中,以便您可以创建对象的通用生成器。
答案 15 :(得分:-1)
参考@Phill Wiggins 的回答,这是一个带有 .from 构造函数和命名参数的示例:
class SomeObject{
String parameter1;
String parameter2;
// Normal Constructor
SomeObject({
this.parameter1,
this.parameter2,
});
// .from Constructor for copying
factory SomeObject.from(SomeObject objectA){
return SomeObject(
parameter1: objectA.parameter1,
parameter2: objectA.parameter2,
);
}
}
然后,在要复制的地方执行此操作:
SomeObject a = SomeObject(parameter1: "param1", parameter2: "param2");
SomeObject copyOfA = SomeObject.from(a);
答案 16 :(得分:-3)
您可以使用可相等的库https://pub.dev/packages/equatable 如果它们扩展了Equatable类,则允许等同于同一类的不同实例。