我对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
}
}
如您所见,我创建了两个案例...我似乎似乎无法从object
案例中提取success
变量。 is
关键字告诉我它是一个FetchableSuccess<dynamic>
(这似乎很奇怪……我以为Dart不会删除该类型?我希望它是一个FetchableSuccess<String>
)
尽管如此,即使我强制转换为FetchableSuccess<dynamic>
,编译器仍然告诉我它不知道object
子类中的FetchableSuccess
变量。
不过,与FetchableError
(未明确使用类型为T
的值)进行对比... is
正常工作,编译器可以访问{ {1}}变量。
我想念什么?任何指导将不胜感激。
答案 0 :(得分:3)
我们这里有两个问题:首先,您需要在两个工厂构造函数的右侧添加<T>
。
如果这样做,s
的运行时类型应为ReflectableSucces<String>
,那么您将从{{1}的以下三行中获得true
}。
然后您正在测试main
,这意味着s is FetchableSuccess
,并且它不是静态已知类型s is FetchableSuccess<dynamic>
的子类型,因此您不会获得晋升(因此没有{{ 1}}静态类型的getter,因此出现错误)。明确测试Fetchable<String>
当然也要接受同样的处理。
所以剩下的问题是,为什么您没有为那些缺少object
的人弄错?我正在为此寻找问题,这可能是一个已知的错误。
更新:https://github.com/dart-lang/sdk/issues/34714解决了这样一个事实,即即使应该在公共前端也不进行推断。因此,我们使用分析器的推论来进行分析,然后在运行时获得不使用推论的语义(因此默认为s is FetchableSucces<dynamic>
),这就是我们在实际情况下遇到这种不幸冲突的原因。 type参数在运行时错误,并且没有编译时错误。当该问题着陆时,应解决该问题。
答案 1 :(得分:1)
我同意,这真的很奇怪。简短的解释:类型被推断为class FileSaver
{
static void Main()
{
// Create a StreamWriter instance
StreamWriter writer = new
StreamWriter(Application.PersistentDataPath + "/droidlog.txt");
// This using statement will ensure the writer will be closed when no longer used
using(writer)
{
// Loop through the numbers from 1 to 20 and write them
for (int i = 1; i <= 20; i++)
{
writer.WriteLine(i);
}
}
}
}
,因此,这里有三种有趣的解决方法:
Fetable<String>
我将向语言人员发送电子邮件,看看他们是否有想法。