Flutter开发必看!浅拷贝与深拷贝的终极指南

460 阅读3分钟

1.webp

首先,让我们了解面向对象编程语言中 对象的深拷贝浅拷贝间的区别。

浅拷贝

当多个变量引用同一个对象地址时,这是一个浅拷贝。更改任何变量的值都会导致所有变量的更改。它只适用于可变对象,如列表、映射、自定义对象等等。原始类型如字符串、整数、布尔值,在赋值时会创建不同的内存地址,所以不受影响

深拷贝

它与浅拷贝完全相反。共享不同的内存地址,因此更改任何对象的值都不会影响其它变量

下面我增加一下实际示例

原始类型

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';  
    }  
}

结论

在我看来,在你想要管理两个相同副本之前,代码中通常不需要深度拷贝。

假设你的用例是管理用户的技能集,应用程序用户可以添加多个技能。在这种情况下,你想跟踪所有编辑过的技能。我们可以将所有现有的技能存储在一个变量中,然后通过使用深拷贝方法,创建一个新的变量。当用户添加、删除或更新技能时,我们将编辑这个变量。在提交操作时,我们将通过比较这两个变量来区分记录,然后将实际更新的值发送到后端。

如果以上信息帮助到你,可以点击一个小小的赞,谢谢你的浏览.