我对 Dart 的理解使我相信这种“强制转换”不应该影响运行时语义,而只是想确认一下:
(foo as Bar).fee();
(foo as Bar).fi();
(foo as Bar).fo();
或者是一次“最佳实践”:
final bFoo = (foo as Bar);
bFoo.fee();
bFoo.fi();
bFoo.fo();
我对 Dart 的理解使我相信这种“强制转换”不应该影响运行时语义,而只是想确认一下:
(foo as Bar).fee();
(foo as Bar).fi();
(foo as Bar).fo();
或者是一次“最佳实践”:
final bFoo = (foo as Bar);
bFoo.fee();
bFoo.fi();
bFoo.fo();
这在很大程度上取决于 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 将来可能会进行的简单优化。
跑步(foo as Bar)有两个效果:
在 (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 对象。
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,或者您可以进行双重调度。