首先,让我们了解面向对象编程语言中 对象的深拷贝与浅拷贝间的区别。
浅拷贝
当多个变量引用同一个对象地址时,这是一个浅拷贝。更改任何变量的值都会导致所有变量的更改。它只适用于可变对象,如列表、映射、自定义对象等等。原始类型如字符串、整数、布尔值,在赋值时会创建不同的内存地址,所以不受影响
深拷贝
它与浅拷贝完全相反。共享不同的内存地址,因此更改任何对象的值都不会影响其它变量
下面我增加一下实际示例
原始类型
void main() {
int i1 = 1;
int i2 = i1;
i1 = 2;
print('Value of i1 = $i1'); // 2
print('Value of i2 = $i2'); // 1
String s1 = 'Hello';
String s2 = s1;
s1 = 'World';
print('Value of s1 = $s1'); // World
print('Value of s2 = $s2'); // Hello
bool b1 = true;
bool b2 = b1;
b1 = false;
print('Value of b1 = $b1'); // false
print('Value of b2 = $b2'); // true
}
在这里,您可以看到输出。Dart在为变量赋值时总是会创建一个新的内存空间变量
可变对象/集合
void main() {
final list = <int>[1, 2, 3];
final listShallow = list;
final listDeep = List.of(list);
list.add(4);
print(list); // [1, 2, 3, 4]
print(listShallow); // [1, 2, 3, 4]
print(listDeep); // [1, 2, 3]
final map = {'id': 1, 'name': 'Nayan'};
final mapShallow = map;
final mapDeep = Map.of(map);
map.addAll({'gender': 'male'});
print(map); // {id: 1, name: Nayan, gender: male}
print(mapShallow); // {id: 1, name: Nayan, gender: male}
print(mapDeep); // {id: 1, name: Nayan}
final set = {'Alpha', 'Beta'};
final setShallow = set;
final setDeep = Set.of(set);
set.add('Gamma');
print(set); // {Alpha, Beta, Gamma}
print(setShallow); // {Alpha, Beta, Gamma}
print(setDeep); // {Alpha, Beta}
}
在集合对象中,将同一个对象地址赋值给同一个新变量。如果要避免上述情况,可以使用如 List.of List.from Map.of Map.from Set.of Set.from等方法构造一个新的集合。
自定义对象
示例一
大多数情况下,我们遵循Flutter中自定义模型类中的字段。因此,一旦通过调用构造函数分配了它们,它们就无法更改。我们可以调用来更改任何字段的值,这样,我们就得到了一个全新的对象,我们需要分配现有变量。
void main() {
var user1 = User(id: 1, firstName: 'Nayan', lastName: 'Babariya');
final user2 = user1;
// At this level, "user2" and "user1" have the same memory reference.
// So this is "shallow copy".
user1 = user1.copyWith(id: 2);
// Now, "user1" has been assigned with a newly created constructor.
// So at this point, "user1" and "user2" have different memory allocation.
print(user1.toString());
// {id: 1, firstName: Nayan, lastName: Babariya}
print(user2.toString());
// {id: 2, firstName: Nayan, lastName: Babariya}
}
class User {
final int id;
final String firstName;
final String lastName;
User({
required this.id,
required this.firstName,
required this.lastName,
});
User copyWith({
int? id,
String? firstName,
String? lastName,
}) {
return User(
id: id ?? this.id,
firstName: firstName ?? this.firstName,
lastName: lastName ?? this.lastName,
);
}
String toString() {
return 'id: $id, firstName: $firstName, lastName: $lastName';
}
}
示例二
为对象中的字段设置一个新的值。non-final
void main() {
final user1 = User(id: 1, firstName: 'Nayan', lastName: 'Babariya');
final user2 = user1;
// Both "user1" and "user2" have the same memory reference.
user1.id = 2;
user1.firstName = 'Nyn';
// When fields of "user1" is updated, "user2" will also updated.
print(user1.toString());
// {id: 2, firstName: Nyn, lastName: Babariya}
print(user2.toString());
// {id: 2, firstName: Nyn, lastName: Babariya}
}
class User {
int id;
String firstName;
String lastName;
User({
required this.id,
required this.firstName,
required this.lastName,
});
@override
String toString() {
return 'id: $id, firstName: $firstName, lastName: $lastName';
}
}
结论
在我看来,在你想要管理两个相同副本之前,代码中通常不需要深度拷贝。
假设你的用例是管理用户的技能集,应用程序用户可以添加多个技能。在这种情况下,你想跟踪所有编辑过的技能。我们可以将所有现有的技能存储在一个变量中,然后通过使用深拷贝方法,创建一个新的变量。当用户添加、删除或更新技能时,我们将编辑这个变量。在提交操作时,我们将通过比较这两个变量来区分记录,然后将实际更新的值发送到后端。