参数类型的兼容性

Compatibility of argument types

不知我的想法是否正确,还是我犯了大错。让我们有简单的代码:

class A { String a = "a"; }

class B extends A { String b = "b"; }

void goofy(Map<String, A> map) {
  A? item = map["b1"];
  print(item?.a);
}

void croc(dynamic map) {
  final A? item = (map as Map<String, A>)["b1"];
  print(item?.a);
}

void frape(dynamic map) {
  final A? item = (map["b1"]) as A;
  print(item?.a);
}


void main() {
  Map<String, B> mapInst = {"b1":B()};
  goofy(mapInst);
  croc(mapInst);
  frape(mapInst);
  
  Map<String, A> mapInst2 = {"b1":A()};
  goofy(mapInst);
  croc(mapInst);
  frape(mapInst);
}

所有函数 goofycrocfrape 都按预期工作。但是我不太确定签名。由于 B 继承自 A,Map<String,A> 是否与 Map<String,B> 兼容?或者这只是一个副作用,实际上基类型是 Map 并且不考虑泛型很重要?当我想传递在通用签名中可以具有 A 或 B 类型的地图时,建议使用哪种语法?也许只是普通地图?

Do Map<String,A> is compatible with Map<String,B> since B inherits from A

是的,如果 B 没有继承自 A,代码将无法编译。

Which syntax is recommended for situation when I want to pass Maps which can have A or B type in generic signature?

正如您在其中一条评论中所说,您可以在类型参数上使用 extends 关键字

void myFunction<T extends A>(Map<String, T> map) { ... }

如果classDerived派生自classBase,那么Generic<Derived>将被认为是一个子类型(更具体的类型)共 Generic<Base>.

Do Map<String,A> is compatible with Map<String,B> since B inherits from A?

取决于您所说的“兼容”是什么意思。 Map<String, B> 可替代 Map<String, A>。也就是说,您可以安全地传递一个 Map<String, B>,而应该是 Map<String, A>。但是,反过来并不安全(因此需要显式转换)。

Which syntax is recommended for situation when I want to pass Maps which can have A or B type in generic signature?

我会用 Map<String, A>.