Dart泛型...不是类型错误的子类型

时间:2020-10-23 18:14:43

标签: dart

class ActivityItem {}

class Activity<T extends ActivityItem> {
  T item;
  
  Activity(this.item);
}

class Type1ActivityItem extends ActivityItem {
  final String data;
  
  Type1ActivityItem(this.data):super();
}

passType1(Activity<Type1ActivityItem> item) {
  print(item);
}

main() {
  Activity activity = Activity(Type1ActivityItem('data1'));
  print(passType1(activity as Activity<Type1ActivityItem>)); // ERROR
}

在运行时掷飞镖

未捕获的错误:TypeError:“ Activity ”的实例:类型“ Activity ”不是类型“ Activity ”的子类型

当通用类型信息丢失时,有点困惑以了解

方案1:

  print(Activity(Type1ActivityItem('data1')) is Activity<Type1ActivityItem>);   // True

Dart能够根据构造函数参数推断出通用类型

方案2:

  Activity activity1 = Activity(Type1ActivityItem('data1'));
  print(activity1 is Activity<Type1ActivityItem>);  // False

看起来像在分配给活动1时,通用类型信息丢失了。

方案3:

  Activity activity2 = Activity<Type1ActivityItem>(Type1ActivityItem('data1'));
  print(activity2 is Activity<Type1ActivityItem>);  // True

即使在分配给activity2之后,泛型类型仍然存在...

1 个答案:

答案 0 :(得分:1)

活动活动= ...

这是错误发生的原因。这为activity提供了类型Activity<ActivityItem>,这是一种不能向下转换为Activity<Type1ActivityItem>的独特类型。

可以通过以下几种方法解决此问题:

  1. 在构造函数中指定通用类型:
Activity activity = Activity<Type1ActivityItem>(Type1ActivityItem('data1'));
  1. 在类型声明中指定通用类型:
Activity<Type1ActivityItem> activity = Activity(Type1ActivityItem('data1'));
  1. 使用类型推断:
var activity = Activity(Type1ActivityItem('data1'));
final activity = Activity(Type1ActivityItem('data1'));

扩展说明

class BaseActivityItem {
  final int base = 1;
}

class SubActivityItem extends BaseActivityItem {
  final int sub = 2;
}

class Activity<T extends BaseActivityItem> {
  T item;

  Activity(this.item);
}

passType1(Activity<SubActivityItem> item) {
  print('passType1 received: $item');
}

main() {
  // The specified variable type will always be the static type of the variable.
  // Here `Activity` is shorthand for `Activity<BaseActivityItem>`.
  // Activity(SubActivityItem()) is a valid value for `Activity<BaseActivityItem>`.
  Activity activity = Activity(SubActivityItem());
  assert(activity is Activity<BaseActivityItem>);

  // `activity.item` runtime type is, as expected, `SubActivityItem`. But, its
  // interface is limited to `BaseActivityItem`.
  assert(activity.item is SubActivityItem);
  print(activity.item.base); // 1

  // The following will not compile because item has type `BaseActivityItem`.
  //print(activit.item.sub);
  // It can be downcast to `SubActivityItem`.
  print((activity.item as SubActivityItem).sub); // 2

  // `activity`'s runtime type is actually
  // Activity<BaseActivityItem> so casting will fail.
  print(activity is Activity<SubActivityItem>); // false

  print('------------------------------------------------');

  // Here we have another activity with the runtime type of
  // Activity<SubActivityItem>. The actual Activity instance
  // is a Activity<SubActivityItem>, but its interface is
  // limited by `Activity` i.e. `Activity<BaseActivityItem>`.
  Activity subRuntimeType = Activity<SubActivityItem>(SubActivityItem());
  assert(subRuntimeType is Activity<BaseActivityItem>);
  assert(subRuntimeType is Activity<SubActivityItem>);
  print(subRuntimeType.item.base); // 1

  // This will fail to compile because item's interface is
  // BaseActivityItem.
  //print(subRuntimeType.item.sub);
  // However it can be downcast:
  print((subRuntimeType.item as SubActivityItem).sub); // 2
  print((subRuntimeType as Activity<SubActivityItem>).item.sub); // 2

  // This can be properly passed to `passType1` because dart knows
  // that `subRuntimeType` is an Activity<SubActivityItem>.
  passType1(subRuntimeType);
  
  print('------------------------------------------------');
  
  // The constructor will return the correct type.
  Activity<SubActivityItem> subType = Activity(SubActivityItem());
  // The following will fail to compile as the constructor return value
  // is not valid for variable type:
  //... subType = Activity(BaseActivityItem());
  //... subType = Activity<BaseActivityItem>(SubActivityItem());
  assert(subType is Activity);
  assert(subType is Activity<SubActivityItem>);
  print(subType.item.base); // 1
  print(subType.item.sub); // 2
  passType1(subType);
  
  print('------------------------------------------------');
  
  // These will infer the type from rhs:
  var inferVarType = Activity(SubActivityItem());
  final inferFinalType = Activity(SubActivityItem());
  print(inferVarType.item.sub); // 2
  print(inferFinalType.item.sub); // 2
  passType1(inferVarType);
  passType1(inferFinalType);
}