如何在不影响 Flutter 中的原始列表的情况下将列表深复制到另一个列表
How to perform deep copy for a list to another list without affecting the original one in Flutter
我有两个 Type 对象列表,_types
和 _filteredTypes
:
List<Type> _types = []; // Original list
List<Type> _filteredTypes = []; // Where i bind filter the contents
类型对象是:
class Type extends Equatable {
final int id;
final String title;
List<SubType>? subTypes;
Type({
required this.id,
required this.title,
this.subTypes,
});
}
一个 SubType 对象是:
class SubType extends Equatable {
final int id;
final String title;
Type({
required this.id,
required this.title,
});
}
我需要根据搜索文本过滤列表,因此只要用户输入字母,_filteredTypes
就会更新。
我在 setState()
中对 _onSearchChangedEvent()
进行筛选,如下所示:
_filteredTypes = List.from(_types); // To get the original list without filter
for(var i = 0; i < _filteredTypes.length; i++) {
// This is where i filter the search result when a subType.title matches the search query:
_filteredTypes[i].subTypes = List.from(_types[i].subTypes!.where((element) => element.title.toLowerCase().contains(query!.toLowerCase())).toList());
}
// This is where i filter the search result and remove any type doesn't match any subType.title:
_filteredTypes.removeWhere((element) => element.subTypes!.length == 0);
bindTypes(); // To refresh the list widget
问题是当我需要获取原始列表时,我得到了主要的 type 但是 type.subTypes 仍然是基于过滤的以前的搜索不是原来的!即使是在没有引用的情况下复制 _filteredTypes = List.from(_types);
这似乎是 Flutter 中的一个错误,伙计们有什么想法吗?
List.from
不会为您提供 _types
的深拷贝 - 它会为您提供浅拷贝。这意味着 _filteredTypes
和 _types
共享相同的 subTypes
。它的行为类似于此示例
var sharedList = [1];
final listOne = [1, sharedList];
final listTwo = [1, sharedList];
sharedList[0] = 2;
更改 sharedList
将同时更改 listOne
和 listTwo
中的值。如果共享列表只是一个整数,则更改该整数不会产生相同的效果。就像这个例子:
var sharedInteger = 1;
final listOne = [1, sharedInteger];
final listTwo = [1, sharedInteger];
sharedInteger = 2;
当你创建一个 class 的实例时,它可能像 List
或你自己的自定义 class 一样内置,你得到的返回是一个引用或指向它的指针instance/object。对象本身分配在堆内存区域而不是堆栈上,这意味着可以在函数外部引用该对象。因为它的生命(对象生命)不受函数范围的限制,所以当你到达函数的末尾 }
时,对象仍然存在,并且它的内存被称为垃圾收集器的特殊程序释放。
与许多现代编程语言一样,在 dart 中使用垃圾收集器并在堆上自动分配对象。例如,在 C++ 等语言中,您可以在堆栈上分配对象,并且必须明确堆分配,并在完成后释放堆上的任何对象。
上面的所有内容你都可以查看它的要点是因为 subtypes
是一个列表,它是一个引用类型所以 _filteredTypes
和 _types
都有那个引用。如果你想要一个深拷贝,你也可以这样做,我会留给你看。
这是对包含子列表的列表执行深度复制的方法,谢谢moneer alhashim,您的回答指导了我。
我将其作为答案发布,以帮助其他人轻松找到解决方案。
所以,这里的关键是映射原始列表 types.map(...)
并手动填充它而不是使用 List.from()
,这将为深层对象创建一个新实例。
首先,我为每个列表声明了一个函数:
//For the parent list:
List<Types> getNewTypesInstance {
// This function allows to perform a deep copy for the list.
return types.map((e) =>
Type(id: e.id, title: e.title, subTypes: e.subTypes))
.toList();
}
// For the child list:
List<SubType> getNewSubTypesInstance(List<SubType> lst) {
// This function allows to perform a deep copy for the list:
return lst.map((e) =>
SubType(id: e.id, title: e.title))
.toList();
}
如果你有更深的列表,你将需要第三个函数来获取它作为新实例等等。
最后,调用方法是在setState()中写这段代码:
_filteredTypes = getNewTypesInstance
for(var i = 0; i < _filteredTypes.length; i++) {
// This is where i filter the search result when a subType.title matches the search query:
_filteredTypes[i].subTypes = List.from(getNewSubTypesInstance(_types[i].subTypes!.where((element) => element.title.toLowerCase().contains(query!.toLowerCase())).toList()));
}
// This is where i filter the search result and remove any type doesn't match any subType.title:
_filteredTypes.removeWhere((element) => element.subTypes!.length == 0);
bindTypes(); // To refresh the list widget
我有两个 Type 对象列表,_types
和 _filteredTypes
:
List<Type> _types = []; // Original list
List<Type> _filteredTypes = []; // Where i bind filter the contents
类型对象是:
class Type extends Equatable {
final int id;
final String title;
List<SubType>? subTypes;
Type({
required this.id,
required this.title,
this.subTypes,
});
}
一个 SubType 对象是:
class SubType extends Equatable {
final int id;
final String title;
Type({
required this.id,
required this.title,
});
}
我需要根据搜索文本过滤列表,因此只要用户输入字母,_filteredTypes
就会更新。
我在 setState()
中对 _onSearchChangedEvent()
进行筛选,如下所示:
_filteredTypes = List.from(_types); // To get the original list without filter
for(var i = 0; i < _filteredTypes.length; i++) {
// This is where i filter the search result when a subType.title matches the search query:
_filteredTypes[i].subTypes = List.from(_types[i].subTypes!.where((element) => element.title.toLowerCase().contains(query!.toLowerCase())).toList());
}
// This is where i filter the search result and remove any type doesn't match any subType.title:
_filteredTypes.removeWhere((element) => element.subTypes!.length == 0);
bindTypes(); // To refresh the list widget
问题是当我需要获取原始列表时,我得到了主要的 type 但是 type.subTypes 仍然是基于过滤的以前的搜索不是原来的!即使是在没有引用的情况下复制 _filteredTypes = List.from(_types);
这似乎是 Flutter 中的一个错误,伙计们有什么想法吗?
List.from
不会为您提供 _types
的深拷贝 - 它会为您提供浅拷贝。这意味着 _filteredTypes
和 _types
共享相同的 subTypes
。它的行为类似于此示例
var sharedList = [1];
final listOne = [1, sharedList];
final listTwo = [1, sharedList];
sharedList[0] = 2;
更改 sharedList
将同时更改 listOne
和 listTwo
中的值。如果共享列表只是一个整数,则更改该整数不会产生相同的效果。就像这个例子:
var sharedInteger = 1;
final listOne = [1, sharedInteger];
final listTwo = [1, sharedInteger];
sharedInteger = 2;
当你创建一个 class 的实例时,它可能像 List
或你自己的自定义 class 一样内置,你得到的返回是一个引用或指向它的指针instance/object。对象本身分配在堆内存区域而不是堆栈上,这意味着可以在函数外部引用该对象。因为它的生命(对象生命)不受函数范围的限制,所以当你到达函数的末尾 }
时,对象仍然存在,并且它的内存被称为垃圾收集器的特殊程序释放。
与许多现代编程语言一样,在 dart 中使用垃圾收集器并在堆上自动分配对象。例如,在 C++ 等语言中,您可以在堆栈上分配对象,并且必须明确堆分配,并在完成后释放堆上的任何对象。
上面的所有内容你都可以查看它的要点是因为 subtypes
是一个列表,它是一个引用类型所以 _filteredTypes
和 _types
都有那个引用。如果你想要一个深拷贝,你也可以这样做,我会留给你看。
这是对包含子列表的列表执行深度复制的方法,谢谢moneer alhashim,您的回答指导了我。
我将其作为答案发布,以帮助其他人轻松找到解决方案。
所以,这里的关键是映射原始列表 types.map(...)
并手动填充它而不是使用 List.from()
,这将为深层对象创建一个新实例。
首先,我为每个列表声明了一个函数:
//For the parent list:
List<Types> getNewTypesInstance {
// This function allows to perform a deep copy for the list.
return types.map((e) =>
Type(id: e.id, title: e.title, subTypes: e.subTypes))
.toList();
}
// For the child list:
List<SubType> getNewSubTypesInstance(List<SubType> lst) {
// This function allows to perform a deep copy for the list:
return lst.map((e) =>
SubType(id: e.id, title: e.title))
.toList();
}
如果你有更深的列表,你将需要第三个函数来获取它作为新实例等等。
最后,调用方法是在setState()中写这段代码:
_filteredTypes = getNewTypesInstance
for(var i = 0; i < _filteredTypes.length; i++) {
// This is where i filter the search result when a subType.title matches the search query:
_filteredTypes[i].subTypes = List.from(getNewSubTypesInstance(_types[i].subTypes!.where((element) => element.title.toLowerCase().contains(query!.toLowerCase())).toList()));
}
// This is where i filter the search result and remove any type doesn't match any subType.title:
_filteredTypes.removeWhere((element) => element.subTypes!.length == 0);
bindTypes(); // To refresh the list widget