使用 'is' 检查 Dart 泛型的运行时类型



我对 Dart 相对较新,正在尝试对代数数据类型进行建模(例如具有关联值的 Swift 枚举(。

但是,当我尝试检查值的运行时类型时,我看到了一些我不太理解的行为。请考虑以下代码:

abstract class Fetchable<T> {
factory Fetchable.success(T object) = FetchableSuccess;
factory Fetchable.error(Error error) = FetchableError;
}
class FetchableSuccess<T> implements Fetchable<T> {
final T object;
const FetchableSuccess(this.object);
}
class FetchableError<T> implements Fetchable<T> {
final Error error;
const FetchableError(this.error);
}
void main() {
// ------------- CASE 1 -------------
final s = Fetchable.success("hi there");
print(s.runtimeType);                             // FetchableSuccess<dynamic>
print(s is FetchableSuccess);                     // true
print(s is FetchableSuccess<String>);             // false
print(s is FetchableSuccess<dynamic>);            // true
if (s is FetchableSuccess) {
print(s.object);                                // compile error 
}
if (s is FetchableSuccess<dynamic>) {
print(s.object);                                // compile error
}
// ------------- CASE 2 -------------
final e = Fetchable.error(StateError("uh oh"));
print(e is FetchableError);                       // true
if (e is FetchableError) {
print(e.error);                                 // Works OK
}
}

如您所见,我创建了两个案例...我似乎无法从success情况中提取object变量。is关键字告诉我这是一个FetchableSuccess<dynamic>(这似乎很奇怪......我以为飞镖不会抹掉类型?我本来以为这是一个FetchableSuccess<String>(

即便如此,如果我投射到FetchableSuccess<dynamic>编译器仍然告诉我它不知道FetchableSuccess子类中的object变量。

不过,将其与FetchableError(它没有明确使用类型T的值(形成对比......is工作正常,编译器能够访问error变量。

我错过了什么?任何指导将不胜感激。

我们这里有几个问题:首先,您需要将<T>添加到两个工厂构造函数的右侧。

如果这样做,运行时类型的s将按应有的方式ReflectableSucces<String>,并且您将从以下 3 行中获得truemain

然后你正在测试s is FetchableSuccess这意味着s is FetchableSuccess<dynamic>,这不是静态已知类型的子类型Fetchable<String>所以你不会得到提升(所以静态类型中没有objectgetter,因此错误(。当然,明确s is FetchableSucces<dynamic>测试也受到同样的对待。

所以剩下的问题是,为什么你没有收到那些缺少<T>的错误?我现在正在为此寻找问题,这可能是一个已知的错误。

更新:https://github.com/dart-lang/sdk/issues/34714 解决了这样一个事实,即推理不是在公共前端完成的,即使它应该完成。因此,我们使用来自分析器的推理来获取分析,然后在运行时获得不使用推理的语义(因此默认为<dynamic>(,这就是为什么我们遇到这种不幸冲突的原因,其中实际类型参数在运行时是错误的,并且没有编译时错误。当上述问题落地时,应该解决它。

我同意,这真的很奇怪。简短的解释:该类型被推断为Fetable<String>,所以这里有三种有趣的解决方法:

var a = Fetchable.success("hi there");
if (a is FetchableSuccess<String>) {
print(a.object);                                // fine
}
var b = Fetchable<dynamic>.success("hi there");
if (b is FetchableSuccess) {
print(b.object);                                // fine
}
var c = Fetchable.success("hi there" as dynamic);
if (c is FetchableSuccess) {
print(c.object);                                // fine
}

我会给语言人员发送电子邮件,看看他们是否有想法。

最新更新