为什么在Dart中有条件地强制转换为接口类型失败?

时间:2019-07-18 09:31:20

标签: dart casting

我有这个非常简单的代码

abstract class Bar {
  String name;
}
class Base {}
class Foo extends Base implements Bar {
  String name;
}


void main() {
  final Base foo = Foo();
  if (foo is Bar) {
    foo.name = 'a';
  }
  print(foo);
}

如果要实现对象,则要在其中设置对象的属性。但是运行它会失败,并显示错误

The setter 'name' isn't defined for the class 'Base'.

看起来好像if语句没有将foo强制转换为Bar,或者Bar没有设置器?

我该如何解决?

1 个答案:

答案 0 :(得分:0)

Dart 类型提升(允许您使用与声明类型不同的类型的变量)无法处理这种情况。

Dart中的变量在任何时候都仅具有 one 类型。 如果您进行x is SomeType测试,则编译器可以说服自己将变量视为新类型是绝对安全的,则变量可能会提升为SomeType。 / p>

此规则的一部分是类型提升仅允许您提升为当前类型的子类型。这样一来,这是一项严格的晋升,您不会丢失已经拥有的信息。

您在此处尝试从Base升级为Bar,但是Bar不是Base的子类型。 因此,促销活动必须选择BaseBar作为一个类型。两种选择都会丢弃信息(或者如果Base具有无法在Bar上调用的有用成员),则编译器必须做出选择。 因此,它将foo的类型保留为Base

您可以改为使用if (foo is Foo)进行测试,因为FooBase的子类型,并且具有name的设置器。

或者您可以创建可升级变量并对其进行推广:

  Object obj = foo;
  if (obj is Bar) foo.name = "a";

之所以可行,是因为从Object升级到Bar是对子类型的升级。

或者您可以投射:

  if (obj is Bar) (obj as Bar).foo = "a";

这看起来有些多余。希望编译器可以说服自己,没有理由进行第二次检查。