returns List<T> 代替 returns List<dynamic> 的通用方法
Generic method that returns List<T> instead returns List<dynamic>
我尝试编写一个简单的通用方法来迭代复制嵌套的 List
,例如 List<List<int>>
。但不幸的是,递归调用似乎总是return List<dynamic>
,所以我得到以下错误
The argument type List<dynamic> can't be assigned to the parameter type T
List<T> listDeepCopy<T>(List<T> list){
List<T> newList = List<T>();
list.forEach((value) {
if( value is List ){
newList.add(listDeepCopy(value)); // <-- listDeepCopy() always returns List<dynamic>
}
else{
newList.add(value);
}
});
return newList;
}
所以如果我打电话
List<List<int>> list = [[1,2],[3,4]];
List<List<int>> copy = listDeepCopy(list);
T
是 List<int>
value
是 T
- 即 List<int>
listDeepCopy(value)
应该等于 listDeepCopy<List<int>>
,这将 return 一个 List<int>
,它应该可以添加到 newList
,这是一个 List<List<int>>
我哪里出错了,我怎样才能使这样的东西起作用?
我可能会将其实现为:
List<T> listDeepCopy<T>(List<T> list) {
var copy = list.toList();
for (var i = 0; i < copy.length; i += 1) {
var element = copy[i];
if (element is List) {
copy[i] = listDeepCopy(element) as T;
}
}
return copy;
}
void main() {
List<List<int>> list = [
[1, 2],
[3, 4]
];
List<List<int>> copy = listDeepCopy(list);
list[0][0] = 99;
print(copy); // Prints: [[1, 2], [3, 4]]
}
您的方法存在一个问题,即 Dart 无法正确推断递归 listDeepCopy(value)
调用的泛型类型参数。 value
属于 T
类型,已知是 List
(对于 List<dynamic>
是 shorthand),我不知道提取方法静态元素类型。 (也许@lrn 会看到并提供更好、更完整的解释。)
在这种情况下,最好通过调用 List
上的方法来依赖多态性,returns 是其自身的副本:.toList()
.
(作为一个重要的例子,考虑一个浅拷贝场景:
List<T> shallowCopy1<T>(List<T> list) => <T>[...list];
List<T> shallowCopy2<T>(List<T> list) => list.toList();
extension StaticType<T> on T {
Type get staticType => T;
}
void main() {
List<num> list = <int>[1, 2, 3];
var copy1 = shallowCopy1(list);
var copy2 = shallowCopy2(list);
print('original: staticType: ${list.staticType}, runtimeType: ${list.runtimeType}');
print('copy1: staticType: ${copy1.staticType}, runtimeType: ${copy1.runtimeType}');
print('copy2: staticType: ${copy2.staticType}, runtimeType: ${copy2.runtimeType}');
}
尽管两个副本都保留了原始 List
的 static 类型,但只有 copy2
保留了对象的实际(运行时)类型。正确的复制取决于被复制对象的 运行时 类型,唯一可靠的方法是让对象创建自己的副本。)
你不能按照你想要的方式去做。
问题是 deepClone<T>
将 List<dynamic>
转换为 List<T>
(这很好),然后尝试将本身是列表的元素转换为类型化列表...但是你不知道类型。
实际上,当您检查 value is List
时,您不知道要将其转换为哪种列表。
有两种情况:
- 对于某些类型
X
,T
是 List<X>
或 Iterable<X>
,但您无法 获取您的动手 X
。 Dart 不允许您在运行时解构类型。
- 或
T
是 Object
或另一种内部没有“列表元素”类型的通用超类型,然后您根本没有关于要转换的 List
类型的任何信息嵌套列表到。 (这实际上是最简单的情况,因为那样的话你根本就不应该 deepClone
列表)。
有一种方法可以确定您处于哪种情况 (<T>[] is List<Iterable<Object?>>
),但它对前一种情况没有帮助,除非您想对所有可能的类型进行详尽搜索X
可能是。
我要做的是构建一个转换器,而不是使用单个函数。
abstract class Cloner<T> {
const factory Cloner() = _ValueCloner<T>;
T clone(dynamic source);
Cloner<List<T>> get list => _ListCloner(this);
}
abstract class _BaseCloner<T> implements Cloner<T> {
const _BaseCloner();
Cloner<List<T>> get list => _ListCloner<T>(this);
}
class _ValueCloner<T> extends _BaseCloner<T> {
const _ValueCloner();
T clone(dynamic source) => source as T;
}
class _ListCloner<T> extends _BaseCloner<List<T>> {
final Cloner<T> _base;
_ListCloner(this._base);
List<T> clone(dynamic source) =>
<T>[for (var o in source as List<dynamic>) _base.clone(o)];
}
然后,如果您确实知道数据的类型,您可以将克隆器构建为:
var typedList =
Cloner<int>().list.list.clone(
<dynamic>[<dynamic>[1, 2], <dynamic>[3, 4]]);
会产生一个 List<List<int>>
,值为 <List<int>>[<int>[1, 2], <int>[3, 4]]
。
我尝试编写一个简单的通用方法来迭代复制嵌套的 List
,例如 List<List<int>>
。但不幸的是,递归调用似乎总是return List<dynamic>
,所以我得到以下错误
The argument type List<dynamic> can't be assigned to the parameter type T
List<T> listDeepCopy<T>(List<T> list){
List<T> newList = List<T>();
list.forEach((value) {
if( value is List ){
newList.add(listDeepCopy(value)); // <-- listDeepCopy() always returns List<dynamic>
}
else{
newList.add(value);
}
});
return newList;
}
所以如果我打电话
List<List<int>> list = [[1,2],[3,4]];
List<List<int>> copy = listDeepCopy(list);
T
是 List<int>
value
是 T
- 即 List<int>
listDeepCopy(value)
应该等于 listDeepCopy<List<int>>
,这将 return 一个 List<int>
,它应该可以添加到 newList
,这是一个 List<List<int>>
我哪里出错了,我怎样才能使这样的东西起作用?
我可能会将其实现为:
List<T> listDeepCopy<T>(List<T> list) {
var copy = list.toList();
for (var i = 0; i < copy.length; i += 1) {
var element = copy[i];
if (element is List) {
copy[i] = listDeepCopy(element) as T;
}
}
return copy;
}
void main() {
List<List<int>> list = [
[1, 2],
[3, 4]
];
List<List<int>> copy = listDeepCopy(list);
list[0][0] = 99;
print(copy); // Prints: [[1, 2], [3, 4]]
}
您的方法存在一个问题,即 Dart 无法正确推断递归 listDeepCopy(value)
调用的泛型类型参数。 value
属于 T
类型,已知是 List
(对于 List<dynamic>
是 shorthand),我不知道提取方法静态元素类型。 (也许@lrn 会看到并提供更好、更完整的解释。)
在这种情况下,最好通过调用 List
上的方法来依赖多态性,returns 是其自身的副本:.toList()
.
(作为一个重要的例子,考虑一个浅拷贝场景:
List<T> shallowCopy1<T>(List<T> list) => <T>[...list];
List<T> shallowCopy2<T>(List<T> list) => list.toList();
extension StaticType<T> on T {
Type get staticType => T;
}
void main() {
List<num> list = <int>[1, 2, 3];
var copy1 = shallowCopy1(list);
var copy2 = shallowCopy2(list);
print('original: staticType: ${list.staticType}, runtimeType: ${list.runtimeType}');
print('copy1: staticType: ${copy1.staticType}, runtimeType: ${copy1.runtimeType}');
print('copy2: staticType: ${copy2.staticType}, runtimeType: ${copy2.runtimeType}');
}
尽管两个副本都保留了原始 List
的 static 类型,但只有 copy2
保留了对象的实际(运行时)类型。正确的复制取决于被复制对象的 运行时 类型,唯一可靠的方法是让对象创建自己的副本。)
你不能按照你想要的方式去做。
问题是 deepClone<T>
将 List<dynamic>
转换为 List<T>
(这很好),然后尝试将本身是列表的元素转换为类型化列表...但是你不知道类型。
实际上,当您检查 value is List
时,您不知道要将其转换为哪种列表。
有两种情况:
- 对于某些类型
X
,T
是List<X>
或Iterable<X>
,但您无法 获取您的动手X
。 Dart 不允许您在运行时解构类型。 - 或
T
是Object
或另一种内部没有“列表元素”类型的通用超类型,然后您根本没有关于要转换的List
类型的任何信息嵌套列表到。 (这实际上是最简单的情况,因为那样的话你根本就不应该deepClone
列表)。
有一种方法可以确定您处于哪种情况 (<T>[] is List<Iterable<Object?>>
),但它对前一种情况没有帮助,除非您想对所有可能的类型进行详尽搜索X
可能是。
我要做的是构建一个转换器,而不是使用单个函数。
abstract class Cloner<T> {
const factory Cloner() = _ValueCloner<T>;
T clone(dynamic source);
Cloner<List<T>> get list => _ListCloner(this);
}
abstract class _BaseCloner<T> implements Cloner<T> {
const _BaseCloner();
Cloner<List<T>> get list => _ListCloner<T>(this);
}
class _ValueCloner<T> extends _BaseCloner<T> {
const _ValueCloner();
T clone(dynamic source) => source as T;
}
class _ListCloner<T> extends _BaseCloner<List<T>> {
final Cloner<T> _base;
_ListCloner(this._base);
List<T> clone(dynamic source) =>
<T>[for (var o in source as List<dynamic>) _base.clone(o)];
}
然后,如果您确实知道数据的类型,您可以将克隆器构建为:
var typedList =
Cloner<int>().list.list.clone(
<dynamic>[<dynamic>[1, 2], <dynamic>[3, 4]]);
会产生一个 List<List<int>>
,值为 <List<int>>[<int>[1, 2], <int>[3, 4]]
。