为什么通用工厂不能重定向到特定的子类?

问题描述 投票:0回答:1

下面是一些(当前)无法编译的代码:

sealed class MyValue<ValueT> {
  final ValueT value;

  const MyValue(this.value);

  const factory MyValue.bool(bool value) = MyBool;
  const factory MyValue.num(num value) = MyNumber;
}

final class MyNumber extends MyValue<num> {
  const MyNumber(super.value);
}

final class MyBool extends MyValue<bool> {
  const MyBool(super.value);
}

Dart 抱怨“重定向构造函数的返回类型‘MyBool/MyNum’不是‘MyValue’的子类型。 尝试重定向到不同的构造函数。”

但是,我不明白为什么。我觉得

const MyValue.bool(true)
成为有效的
MyBool
常数应该是完全可行的。

但这与常量没有任何关系,因为同样的问题也发生在非常量工厂上:

sealed class MyValue<ValueT> {
  final ValueT value;

  const MyValue(this.value);

  factory MyValue.bool(bool value) => MyBool(value);
  factory MyValue.num(num value) => MyNumber(value);
}

final class MyNumber extends MyValue<num> {
  const MyNumber(super.value);
}

final class MyBool extends MyValue<bool> {
  const MyBool(super.value);
}

现在,我确实看到了这个问题,这似乎与我遇到的问题有关,除了在我的情况下,我没有尝试根据输入返回不同的类型。我对答案也不满意,因为类似

sealed class MyValue<ValueT> {
  final ValueT value;

  const MyValue(this.value);

  factory MyValue.bool(bool value) => (MyBool(value) as MyValue<ValueT>);
  factory MyValue.num(num value) => (MyNumber(value) as MyValue<ValueT>);
}

final class MyNumber extends MyValue<num> {
  const MyNumber(super.value);
}

final class MyBool extends MyValue<bool> {
  const MyBool(super.value);
}

不仅可以编译,而且在运行时也完全可以正常工作。问题是,明确的

as
转换似乎是多余的,而且我仍然无法创建
const
实例...

有人可以向我解释为什么类型系统不能按我期望的方式工作吗? (我假设我在这里遗漏了一些东西,并且有一个特定的设计选择导致了我所看到的结果。)还值得一提的是,我真正想做的是制作一种“类型- union”,我可以详尽地

switch
了解“我的价值观”的类型(在本例中,
num
bool
)——所以如果有人可以告诉我另一种方法来实现这一点,那就工作也一样好。预先感谢!

dart generics types casting type-conversion
1个回答
0
投票

转发构造函数的规则是,它们转发的构造函数必须返回调用构造函数的类型的子类型,对于提供给超类的any类型变量。

如果你写:

class Super<T> {
  T get value;
  factory Super.bool(bool b) = SubBool;
}
class SubBool implements Super<bool> {
  final bool value;
  SubBool(this.value);
}

那么你就有问题了,有人可以写:

  Super<String>.bool(true);

这是不允许的,因为它的静态类型是

Super<String>
,并且它将创建的值是实现
SubBool
Super<bool>
,它不是
Super<String>

您只是被禁止编写转发构造函数,而不是试图在某些情况下阻止这种情况,并在其他情况下允许这种情况。

转发构造函数必须创建一个

Super<T>
,并且
SubBool
通常不是
Super<T>

© www.soinside.com 2019 - 2024. All rights reserved.