1

我对 Dart 的理解使我相信这种“强制转换”不应该影响运行时语义,而只是想确认一下:

(foo as Bar).fee();
(foo as Bar).fi();
(foo as Bar).fo();

或者是一次“最佳实践”:

final bFoo = (foo as Bar);
bFoo.fee();
bFoo.fi();
bFoo.fo();
4

3 回答 3

3

这在很大程度上取决于 DartVM 优化器如何处理这种情况。使用最新版本的 Dart 我构建了两个测试函数:

void test1() {
  Dynamic bar = makeAFoo();

  for (int i = 0; i < 5000; i++) {
    (bar as Foo).a();
    (bar as Foo).b();
  }
}

void test2() {
  Dynamic bar = makeAFoo();

  Foo f = bar as Foo;
  for (int i = 0; i < 5000; i++) {
    f.a();
    f.b();
  }
}

查看 test1 的优化代码,您可以看到循环如下所示:

00D09A3C    bf813b9d00             mov edi,0x9d3b81  'instance of  Class: SubtypeTestCache'
00D09A41    57                     push edi
00D09A42    50                     push eax
00D09A43    6811003400             push 0x340011
00D09A48    e8d36c83ff             call 0x540720  [stub: Subtype1TestCache]
00D09A4D    58                     pop eax
00D09A4E    58                     pop eax
00D09A4F    5f                     pop edi
00D09A50    81f911003400           cmp ecx,0x340011
00D09A56    7411                   jz 0xd09a69
00D09A58    81f9710f7c00           cmp ecx,0x7c0f71
00D09A5E    0f8437000000           jz 0xd09a9b
00D09A64    e900000000             jmp 0xd09a69
00D09A69    8b1424                 mov edx,[esp]
00D09A6C    8b4c2404               mov ecx,[esp+0x4]
00D09A70    6811003400             push 0x340011
00D09A75    50                     push eax
00D09A76    68b9229d00             push 0x9d22b9
00D09A7B    51                     push ecx
00D09A7C    52                     push edx
00D09A7D    6889289d00             push 0x9d2889
00D09A82    b8813b9d00             mov eax,0x9d3b81  'instance of  Class: SubtypeTestCache'
00D09A87    50                     push eax
00D09A88    b9b0d00b00             mov ecx,0xbd0b0
00D09A8D    ba06000000             mov edx,0x6
00D09A92    e8896583ff             call 0x540020  [stub: CallToRuntime]
00D09A97    83c418                 add esp,0x18
00D09A9A    58                     pop eax
00D09A9B    5a                     pop edx
00D09A9C    59                     pop ecx
00D09A9D    50                     push eax
00D09A9E    a801                   test al,0x1
00D09AA0    0f8450010000           jz 0xd09bf6
00D09AA6    0fb74801               movzx_w ecx,[eax+0x1]
00D09AAA    81f922020000           cmp ecx,0x222
00D09AB0    0f8540010000           jnz 0xd09bf6
00D09AB6    b9d1229d00             mov ecx,0x9d22d1  'Function 'a':.'
00D09ABB    bae96ccb00             mov edx,0xcb6ce9  Array[1, 1, null]
00D09AC0    e82b6983ff             call 0x5403f0  [stub: CallStaticFunction]
00D09AC5    83c404                 add esp,0x4
00D09AC8    b911003400             mov ecx,0x340011
00D09ACD    ba11003400             mov edx,0x340011
00D09AD2    8b45f4                 mov eax,[ebp-0xc]
00D09AD5    51                     push ecx
00D09AD6    52                     push edx
00D09AD7    3d11003400             cmp eax, 0x340011
00D09ADC    0f849a000000           jz 0xd09b7c
00D09AE2    a801                   test al,0x1
00D09AE4    7505                   jnz 0xd09aeb
00D09AE6    e95f000000             jmp 0xd09b4a
00D09AEB    0fb74801               movzx_w ecx,[eax+0x1]
00D09AEF    81f922020000           cmp ecx,0x222
00D09AF5    0f8481000000           jz 0xd09b7c
00D09AFB    0fb77801               movzx_w edi,[eax+0x1]
00D09AFF    8b4e07                 mov ecx,[esi+0x7]
00D09B02    8b891c100000           mov ecx,[ecx+0x101c]
00D09B08    8b0cb9                 mov ecx,[ecx+edi*0x4]
00D09B0B    8b7927                 mov edi,[ecx+0x27]
00D09B0E    8b7f03                 mov edi,[edi+0x3]
00D09B11    81ff59229d00           cmp edi,0x9d2259
00D09B17    0f845f000000           jz 0xd09b7c
00D09B1D    bfd13b9d00             mov edi,0x9d3bd1  'instance of  Class: SubtypeTestCache'
00D09B22    57                     push edi
00D09B23    50                     push eax
00D09B24    6811003400             push 0x340011
00D09B29    e8f26b83ff             call 0x540720  [stub: Subtype1TestCache]
00D09B2E    58                     pop eax
00D09B2F    58                     pop eax
00D09B30    5f                     pop edi
00D09B31    81f911003400           cmp ecx,0x340011
00D09B37    7411                   jz 0xd09b4a
00D09B39    81f9710f7c00           cmp ecx,0x7c0f71
00D09B3F    0f8437000000           jz 0xd09b7c
00D09B45    e900000000             jmp 0xd09b4a
00D09B4A    8b1424                 mov edx,[esp]
00D09B4D    8b4c2404               mov ecx,[esp+0x4]
00D09B51    6811003400             push 0x340011
00D09B56    50                     push eax
00D09B57    68b9229d00             push 0x9d22b9
00D09B5C    51                     push ecx
00D09B5D    52                     push edx
00D09B5E    6889289d00             push 0x9d2889
00D09B63    b8d13b9d00             mov eax,0x9d3bd1  'instance of  Class: SubtypeTestCache'
00D09B68    50                     push eax
00D09B69    b9b0d00b00             mov ecx,0xbd0b0
00D09B6E    ba06000000             mov edx,0x6
00D09B73    e8a86483ff             call 0x540020  [stub: CallToRuntime]
00D09B78    83c418                 add esp,0x18
00D09B7B    58                     pop eax
00D09B7C    5a                     pop edx
00D09B7D    59                     pop ecx
00D09B7E    50                     push eax
00D09B7F    a801                   test al,0x1
00D09B81    0f8479000000           jz 0xd09c00
00D09B87    0fb74801               movzx_w ecx,[eax+0x1]
00D09B8B    81f922020000           cmp ecx,0x222
00D09B91    0f8569000000           jnz 0xd09c00
00D09B97    b961239d00             mov ecx,0x9d2361  'Function 'b':.'
00D09B9C    bae96ccb00             mov edx,0xcb6ce9  Array[1, 1, null]
00D09BA1    e84a6883ff             call 0x5403f0  [stub: CallStaticFunction]
00D09BA6    83c404                 add esp,0x4
00D09BA9    8b4df8                 mov ecx,[ebp-0x8]
00D09BAC    83c102                 add ecx,0x2
00D09BAF    0f8055000000           jo 0xd09c0a
00D09BB5    89cf                   mov edi,ecx
00D09BB7    8b5df4                 mov ebx,[ebp-0xc]
00D09BBA    e90efeffff             jmp 0xd099cd

test2 的优化代码你可以看到循环如下所示:

00D09F3D    894df4                 mov [ebp-0xc],ecx
00D09F40    81f910270000           cmp ecx,0x2710
00D09F46    0f8d46000000           jnl 0xd09f92
00D09F4C    3b251c414700           cmp esp,[0x47411c]
00D09F52    0f8659000000           jna 0xd09fb1
00D09F58    50                     push eax
00D09F59    b9d1229d00             mov ecx,0x9d22d1  'Function 'a':.'
00D09F5E    bae96ccb00             mov edx,0xcb6ce9  Array[1, 1, null]
00D09F63    e8886483ff             call 0x5403f0  [stub: CallStaticFunction]
00D09F68    83c404                 add esp,0x4
00D09F6B    8b45f0                 mov eax,[ebp-0x10]
00D09F6E    50                     push eax
00D09F6F    b961239d00             mov ecx,0x9d2361  'Function 'b':.'
00D09F74    bae96ccb00             mov edx,0xcb6ce9  Array[1, 1, null]
00D09F79    e8726483ff             call 0x5403f0  [stub: CallStaticFunction]
00D09F7E    83c404                 add esp,0x4
00D09F81    8b4df4                 mov ecx,[ebp-0xc]
00D09F84    83c102                 add ecx,0x2
00D09F87    0f8048000000           jo 0xd09fd5
00D09F8D    8b45f0                 mov eax,[ebp-0x10]
00D09F90    ebab                   jmp 0xd09f3d

并且只有一组对 SubTypeTestCache 的调用(在 test2 的循环之外)而不是 test1 中的两个。

今天,执行一次强制转换似乎更快,但将强制转换退出循环似乎是 VM 将来可能会进行的简单优化。

于 2012-09-13T16:03:11.967 回答
2

跑步(foo as Bar)有两个效果:

  • 它告诉编辑器 foo 是一个 Bar ,它有助于静态类型分析并让编辑器完成代码。
  • 它检查 foo 是否是 Bar(或 Bar 的子类型),否则会抛出 CastException。

在 (http://www.dartlang.org/docs/spec/latest/dart-language-specification.pdf) 中查找“类型转换”。

更新:我也喜欢约翰的回答,但我想我应该再说一件事。我忽略了一个事实,你说的是做一次演员而不是三次。看着final bFoo = (foo as Bar);,我想再说一件事关于语言语义。

确实,Dart 编辑器、dart2js 和 VM 可以推断出 foo 是 Bar 类型,这样可以节省额外的检查等。但是,语言的语义稍有不同。“final bFoo”没有类型注释。所以根据语言规范,bFoo 的类型是动态的。

因此,当您写三遍“(foo as Bar)”时,每个表达式都会产生一个 Bar。但是当你写 bFoo 时,你有一个 Dynamic 对象。

于 2012-09-13T15:50:45.430 回答
1

as对同一个变量连续执行三个强制转换不是“最佳实践” 。

as演员表实际上是运行时检查。我只是猜测,但如果你想减少来自编辑器的警告,可能有更好的方法来做到这一点。

例如,这是一个场景:

class Foo {

}

class Bar extends Foo {
  m1() => print('m1');
}

doStuff(Foo foo) {
  foo.m1();  // warning here
}

main() {
  var foo = new Bar();
  doStuff(foo);
}

上面的代码运行得很好,但编辑器确实显示了一个警告。要消除警告,最好重构代码。您可以从 doStuff 中删除 Foo 注释,或者您可以考虑将 m1() 移至 Foo,或者您可以进行双重调度。

于 2012-09-14T06:42:09.157 回答