Joh*_*ang 3 future async-await dart
为什么以下代码有效?我认为应该有编译时错误。我认为return体内返回一个int(值1)。如果不是,它必须返回 a Future,这也不符合返回类型。发生了什么事await?
void longRun() async {
return await Future.delayed(
Duration(seconds: 3),
()=>1,
);
}
Run Code Online (Sandbox Code Playgroud)
如果我将await部分分配给变量,如下所示,编译器就会开始抱怨,这是显而易见且易于理解的。但为什么上面的代码没有抱怨呢?
void longRun() async {
var foo = await Future.delayed(
Duration(seconds: 3),
()=>1,
);
return foo;
}
Run Code Online (Sandbox Code Playgroud)
继续研究我发现了更令人困惑的事情:以下所有版本都有效。它们看起来一模一样,都是有线的。
版本1:
void longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
Run Code Online (Sandbox Code Playgroud)
版本2:
Future<void> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
Run Code Online (Sandbox Code Playgroud)
版本3:
Future<int> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
Run Code Online (Sandbox Code Playgroud)
版本4:
Future longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
Run Code Online (Sandbox Code Playgroud)
版本5:
Future longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
Run Code Online (Sandbox Code Playgroud)
版本6:
void longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
Run Code Online (Sandbox Code Playgroud)
这主要是关于 的行为=>,而不是关于await。通常() => 1可以被认为是 的简写() { return 1; },但这实际上过于简单化了。
=>为了方便起见,允许使用void函数,以便人们可以编写如下内容:
bool functionWithSideEffect() {
print('Some side effect');
return true;
}
void foo() => functionWithSideEffect();
int _someValue = 0;
set someValue(int value) => _someValue = value;
Run Code Online (Sandbox Code Playgroud)
即使这些不合法:
var foo() {
// error: A value of type 'bool' can't be returned from the function 'foo'
// because it has a return type of 'void'.
return functionWithSideEffect();
}
set someValue(int value) {
// error: A value of type 'int' can't be returned from the function
// 'someValue' because it has a return type of 'void'.
return _someValue = value;
}
Run Code Online (Sandbox Code Playgroud)
您感到困惑的关键在于,() => 1要么是int Function()要么void Function(),并且类型推断在给定不同约束的情况下选择不同的事物。
当你这样做时:
Run Code Online (Sandbox Code Playgroud)void longRun() async { return await Future.delayed( Duration(seconds: 3), ()=>1, ); }
然后类型推断从外到内工作,通过不受约束的返回表达式传播void返回类型。longRun调用Future.delayed被推断为Future<void>.delayed,() => 1回调被推断为void Function()。(可以说,void async函数返回Future<void>可以被视为错误。)
相反,当你这样做时:
Run Code Online (Sandbox Code Playgroud)void longRun() async { var foo = await Future.delayed( Duration(seconds: 3), ()=>1, ); return foo; }
现在类型推断以另一个方向运行(由内而外):foo没有显式类型,因此它不限制右侧。因此() => 1被假定为int Function(),这导致Future.delayed被推断为Future<int>.delayed并被foo推断为int。由于foo是 an int,因此尝试从声明为 return 的函数返回它void是一个错误。
版本2:
Run Code Online (Sandbox Code Playgroud)Future<void> longRun() async { return await Future.delayed(Duration(seconds:2), ()=>1); }
您已将longRun的返回类型从更改void为Future<void>。async函数通常应该返回 aFuture但也可能返回void为 fire-and-forget。与版本 1 的唯一区别是调用者现在可以在完成时等待(触发回调)longRun。() => 1仍被推断为void Function().
版本3:
Run Code Online (Sandbox Code Playgroud)Future<int> longRun() async { return await Future.delayed(Duration(seconds:2), ()=>1); }
与 version2 相同,只是longRun返回Future<int>而不是Future<void>. 现在() => 1推断是int Function()。
版本4:
Run Code Online (Sandbox Code Playgroud)Future longRun() async { return await Future.delayed(Duration(seconds:2), ()=>1); }
longRun的返回类型是 now Future,这意味着Future<dynamic>. () => 1被推断为dynamic Function().
版本5:
Run Code Online (Sandbox Code Playgroud)Future longRun() async { await Future.delayed(Duration(seconds:2), ()=>1); }
与 version4 相同,但没有明确return声明。现在Future.delayed表达式不再受longRun返回类型的限制,推理将由内而外流动;() => 1假设为int Function().
版本6:
Run Code Online (Sandbox Code Playgroud)void longRun() async { await Future.delayed(Duration(seconds:2), ()=>1); }
与 version5 相同,只是longRun返回void并且是一个即发即弃函数。完成后无法通知调用者longRun。
(请注意,在上面,当我写() => 1被推断为int Function()或时void Function(),它确实应该是FutureOr<int> Function()或FutureOr<void> Function(),但这不是重要的部分。)
编辑:
先发制人地解决一些潜在的后续问题:
为什么是:
void longRun() async {
int f() {
return 1;
}
return await Future<void>.delayed(
Duration(seconds: 3),
f,
);
}
Run Code Online (Sandbox Code Playgroud)
好的,但是:
void longRun() async {
return await Future<void>.delayed(
Duration(seconds: 3),
// info: Don't assign to void.
() {
return 1;
},
);
}
Run Code Online (Sandbox Code Playgroud)
产生分析投诉?两个版本都是合法的,因为当是 的子类型时,用 a 替换Future<U>aFuture<T>是合法的。当是 时,可以是任何东西;该值可以忽略。(在 Dart 中,部分由于历史原因,它并不总是有类型,实际上意味着该值无法使用,而不是没有值。是合法的,但尝试读取 的值将是一个错误。这这就是为什么“不要分配给无效”分析投诉没有被归类为错误。)UTTvoidUvoidvoidvoid x = 42;x
在使用匿名函数的第二个版本中,return语句的更紧密的局部性允许分析器执行更广泛的检查。
| 归档时间: |
|
| 查看次数: |
116 次 |
| 最近记录: |