带你深入 Dart 解析一个有趣的引用和编译实验
本篇首要经过一个简略比如,谈论一下 Dart 代码里一个风趣的现象。
咱们都知道 Dart 里一切都是方针,就连根底类型 int
、double
、bool
也变量都是 class
。
当咱们关于 int
、 double
这些 class
进行的 +
、-
、*
、 等操作approve时,其实是执行了这个
class
的 operator
操作符的操作flutter结构, 然后回来了新的 num
方针。
关于这些 operator
操作究竟会经过 VM
去进行实现回来,而本质上 dart 代码也仅仅文本变量泵,需求究竟编译成二进制去作业。
以下比如根据 dflutter怎样读音发音art 2.12.3 检验
那这儿想要谈论什么呢?
首要咱们看一段代码app安装下载,如下代码所示,fluttered能够看到:
- 首要咱们界flutter菜鸟教程说了一个叫
idx
的int
型参数; - 然后在
for
循环里添加了三个InkWell
可点击控件; - 究竟在
onT变量类型有哪些ap
里面将idx
打印出来;
class MyHomeP变量名的命名规矩age extends StatelessWidget {
var images = ["RRR", "RRR", "RR变量是什么意思R",];
@override
Wid二进制手表get build(BuildContext context) {
List<Widget> contents = [];
int idx = 0;
for (var imgUrl in images) {
contents.add(InkWell(
onTap: () {
pflutter中文网rint("######## $idx");
},
child: Container(
height: 100,
width: 100,
color: Colors.red,
child: Text(imgUrl),
)));
idx++;fluttering
}
return Scaffo变量类型有哪些ld(
appBa变量类型有哪些r: AppBar(),
body: Center(
child: Column(
children: [
...contents,
],
)));
}
}
-
问题来了,你觉得点击这三个
InkWell
打印出来的会是什么效果? -
答案是打印出来的都是 3。
为什么呢?让咱们看这段代码编译后的逻辑,如下所示二进制转十进制计算器代码,能够看到上述代码编译后, print
函数appstore里指向的永远是 idx
这个 int*
指针,当咱们点击时,究竟打印出来的都是究竟的 idx
的值。
@#C475
method build(fra2::BuildContflutter怎样读音发音ext* context) → fr变量a2::Wappearanceidget* {
core::List<fra2::Widget*>* contents = core::_GrowableList::•<fra2::Widget*>(0);
core::int* idx = 0;
{
core::Iter二进制手表ator<core::String*>* :sync-for-iterator = this.{main::MyHomePage::image变量名s}.{core::Iterable::iterator};
for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
c二进制ore::FlutterString* imgUrl = :sync-for-iterator.{core::Iterator::curreflutter结构优缺点nt};
{
[@vm.call-site-attributes.metadata=receiv变量值erType:dart.core::List<library package:flu变量tter/src/widget变量类型有哪些s/framework.dart::Wi二进制手表dget*>*] contents.{core::List::add}(new ink5::InkWell::•(o二进制nTap: () → Null {
core::print("###二进制八进制十进制十六进制转化##### ${idx}");
}, child: new con7::Container::•(height: 100.0, width: 100.0, color: #C40086, $creationLocationd_0dea112b090073变量与函数317d4: #C66610), $creationLocationd_0dflutter结构优缺点ea112b090073317d4: #C66614));
iflutter怎样读音发音dx = idx.{core::num::+}(1);
}
}
}
那假定咱们需求打印出来的是每个 InkWell
自己的 index
呢?
如下二进制转化为十进制代码所示,咱们在 for 循环里添加了一个 index
参数,把每次 idx
都赋值给 index
,这样点击打印出来的效果,就会是点击对应的 index
。
class MyHomePage extends StatelessWidget {
var images = ["RRR", "RRR", "RRR",];
@override
Widget build(BuildContext context) {
List<Widget>apple contents = [];
int idx =变量的界说 0;
for (var imgUrl in images) {
int index = idx;
contents二进制计算器.add(InkWell(
onTap: (fluttered) {
print("######## $index");
},
child: Container(
height: 100,
width: 100,
color: Co变量泵lors.red,
child: Text(imgUrl),
)));
idx++;
}
return Scaffold(
appBar: AppBar(),
body: Center(
chi二进制八进制十进制十六进制转化ld: Column(
c变量名hildren:application [
...contents,
],
)));
}
}
为什么呢?变量之间的联络
让咱们看新编译出来的代码,如下所示,能够看到对了 core::int* indflutter结构优缺点ex = idx;
这flutter结构优缺点段代码二进制怎样算,然后回想下前面所说的,Dart 里根柢类型都是方针,而 operator
操作符运算后回来新的方针二进制手表。
这样就等于用 index
把每次的操作到保存下来,而 print
打印的天然便是每次被保存下来的 idx
。
@#C475
method build(fra2::BuildContext* context) → fra2::Widget* {
core::List<fra2::Widget*>* contents = core::_GrowableList::•<fra2:application:Widget*>变量泵(0);
core::int* idxfluttershy = 0;
{
core::Iterator<core::S变量类型有哪些tring*>* :sync-for-iteratflutter怎样读音发音or = this.{main::MyHomePage::images}.{core::Iterable::iterator};
for (; :sync-flutteredfor-iterator.{core::Iterator::moveNext}(); ) {
cor变量泵e::String* imgUrl = :sync-for-iterator.{core::Iterator::current};
{
core::int* index = idx;
[@vm.call-site-attributes.metaflutter面试题data=receiverType:daFlutterrt.core::List<library pac变量的界说ka变量值ge:flutter/src/widgets/f二进制转十进制计算器ramework.flutter结构dart::Widget*>*] contents.{core::List::add}approve(new ink5::InkWell::•(onTap: () → Nul变量的界说l {
core::print("######## ${index}");
}, child: new con7::Container::•(height: 100.0, width: 100.0, coloflutter是什么意思r:flutter菜鸟教程 #C40086, $creationLocationd_0dea112b090073317d4: #C66610), $creationLocationd_0dea112b090073317d4: #C66614));
idx = idx.{core::num::+}(1);
}
}
}
那再来个不一样的写法。
如下代码所示,把 InkWell
放到一个 getItem
函数里回来,然后 index
经过函数参数传递进来,能够看到作业后的成变量名的命名规矩果,也是点击对应flutter怎样读音发音 InkWell
打印对应的 index
。
class MyHomePageapplication exappointmenttends StatelessWidget {
var images = ["RRR", "RRR", "RRR",];
@ovflutteringerride
Widget build(BuildContext context) {
List<Widget> contents = [];
int idx = 0;
getItem(int index, Strin变量名的命名规矩g imgflutter结构Url) {
return InkWell(
onTap: () {
print("#######二进制转化器# $index");
},
child: Container(
height: 100,
width: 100,
color: Colo二进制八进制十进制十六进制转化rs.redAPP,
chAPPild: Text(imgUrl)));
}
for (var imgUappearrl in images) {
cFlutteront二进制计算器ents.add(getItem(iappstoredx, imgUrl));
idx++;
}
return Scaffold(
appBar: AppBar(),
body: Center(
chiflutteringld: Column(
childflutter菜鸟教程ren: [
...contents,
],
)));
}
}
为什么呢?
咱们继续看编译后的代码,如下代码所示,其实便是每次的 idx
都经过 getItem.call(idx)
被 getItem
的 indexflutter是什么意思
引用,然后下次又再次传递一个对应的 idx
进去,原理appreciate其实和上面的状况一样,所以每次点击也会打印对应的 index
。
@#C475二进制转十进制计算器
method build(fra2::Bui变量泵ldContext* context) → fra2::Widget* {
core::List<fra2::Widget*>* contents = core::_GrowableList::•<fra2::Widget*>(0);
core:变量与函数:int* idx = 0;
function getItem(core::int* iflutter中文网napp安装下载dex) → ink5::In变量泵kappointmentWell* {
return new ink5::InkWell::•(onTa二进制转八进制p: () → Null {
core::print("######## ${index}");
}, child: new con7::Container::•(变量与函数height: 100.0, width: 100.0, color: #C40086, $creationLocationd_0dea112二进制转十进制计算器b090073317d4: #C66610), $creationLocationd_0dea112b090073317d4: #C66614);
}
{
core::Iterator<core::String*>* :sync-fappearanceor-iterator = this.{main::MyHomePage::images}.{core::Iterable::iterator};
for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
core::String* imgUrl = :sync-for-iterator.{core::Iterappreciateator::currflutter怎样读音发音ent};
{
[@vm.call-site-attributes.metadata=receiverType:d二进制art.core::List<library package:flutter/src/widgets/framewoapplerk.dart::Widget*&flutter菜鸟教程gt;*] contents.{变量类型有哪些core::List::add}([@vm.call-site-attributes.metadata=receiverType:library package变量的界说:flutter/src/material/ink_well.dart::InkWell* Function(dart.core::int*)*] getItem.call(iappstoredx));
idx = idx.{core::num::+}(1);
}
}
}
究竟咱们变量与函数再换种写法。
如下代码所变量的界说示二进制转八进制,直接用最根柢的 for
循环添加 InkWell
并打印 idx
,效果会怎样样呢?
class MyHomePage extends StatelessWidget {
var images = [ "RRR","RRR",flutter结构优缺点 "RRR"];
@ovflutter菜鸟教程erride
Wid变量名的命名规矩get build(BuildContext context) {
List&二进制怎样算lt;Widget> content二进制计算器s = [flutter结构];
for (int idx = 0; idxappointment < images.length; idx++) {
contents.add(InkWell(
onTap: (变量与函数教案) {
print("flutter是什么意思######## $idx");
},
child: Container(
height:二进制亡者列车 100,
width: 100,
color: Colors.red,
child: Text(images[idx]),
)));
}
return Scaffold(
appBar: AppBarappear(),
body: Center(
child: Co二进制转化为十进制lumn(
children: [
...contents,
],
)));
}
}
答案便是:点击对应变量之间的联络 InkWell
打印对应的 index
。
为什么呢?
咱们继续看编译后的代码,能够看到都是打印的 idx
,为什么这样就能够正常呢?
这儿最大的变量值不同便是idx
被声明的方位不同。
@#C475
method build(fra2::flutter结构优缺点BuildContext* context) → fra2::Widget* {
core::List<fra2::Widget*&flutter面试题gt;* cflutter中文网ontents = core:变量名的命名规矩:_GrowableList::•<fra2::Widget*>(0);
for (core::ifluttershynt* idx =fluttered 0; idx.{core::num::<}(this.{main::MyHome变量与函数教案Page::images}.{core::List::length}); idx = idx.{core::num::+}(1)) {
[@vm.call-site-attributes.metadata=receiverType:dart.core:变量与函数教案:List<library package:flutter/src/widgets/framework.dart::Widgeappearancet*>*] contents.{core::List::add}(newfluttershy ink5::InkWell::•(onTap: () → Null {
core::print("##flutter中文网###### ${idx}");
}, child: new co二进制转八进制n7::Container::•(height: 100.0, width: 100.0, color: #C40086, child: new text::Text::•appstore(this.{main::MyHomePage::images}.{core::List::[]}(idx), $creationLocationd_二进制0dea112b090073317d4: #C66607), $creationLocationd_0dea112b090073317d变量与函数4: #C66613), $creationLocationd_0dea112b090073317d4: #C66617));
}
那这时候咱们从头调整下,把 idx
放到 for 外面,点击检验会发现,打印的效果又都是 3。
class MyHomePage extends S变量与函数tatelessWidget {
var变量 imagefluttereds = [ "RRR", "RRR","RRR"];
@override
Widget build(BuildContext context) {
List<Widapp安装下载get> contents = [];
int idx = 0;
f变量与函数教案or (; idx < images.length; idx++) {
contents.add(InkWell(
onTap: () {
print("########flutter怎样读音发音 $idx");
},
child: Container(
height: 100,
width: 100,
color: Colors.red,
child: Texflutter怎样读音发音t(images[idxappstore]),
)));
}
return Scaffo二进制怎样算ld(
appBar: AppBar(),
body: Center(
child: Column(
capproachhildren: [
...contents,
],
)));
}
}
这是为什么呢?
看编译后的代码,仅有不同的便是 core::int* idx
的声明方位,那原因毕竟是什么呢?
@#C475
method build(fra2::BuildContext* context) → fra2::Widget* {
core::List<fra2::Widget*>* contents = core::_GrowableList::•<fra2::Widget*>(0);
core::int* idx = 0;
for (; idx.{core::num::<}(this.{main::MyHomePage::images}.{core::List::length}); idx = idx.{core::num::+}(1)) {
[@vm.call-site-attributes.metadata=receiverType:dart.core::Lisflutteringt&lflutteredt;library package:flutter/src/widgets/framework.dart::Widget*>*] contents.{core::List::add}(new ink5::InkWell::•(onTa变量p: () → Null {
core::pr二进制计算器int("######## ${idx}");
}, child: new con7::Container::•(height: 100.0, width: 100.0, color: #C40086, child: new text::Text::•(this.{main::MyHomePage::imagappeares}.{core::List::[]}(idx), $creatio变量类型有哪些nLocationd_0dea112b090073317d4: #C66607), $creationLocationd_0dea112b090073317d4: #C变量值66613), $creationLocationd_0dea112APPb090073317d4: #C66617变量与函数));
}
因为 onTap
是在点击后才输出参数application的,而关flutter中文网于 for (core::int* idx = 0;
来说,idx
的效果域是在 for
循环之内,所以编译后在 onTap
内要有对应持有一个值,flutter面试题来保存需求输出的效果。
而关于 for
循环外界说的 core::int* idx
, 循环内的一切二进制转化器 onTap
都能够指向它这个地址,所以导致点击时都输出了同一个 idx
的值。
至于为什么会有这样的逻辑,在深化的作业时逻辑就没有去探求了(懒),估测应该是编译flutter怎样读音发音后的二进制文件在作业时,针对循环外的参数和循环内的参数优化有联络。
理论上,应该是归于变量捕获:
- 关于全局变量,不会捕获,经过flutter菜鸟教程全局变量访问。
- 关于局部变量,自动变量将会捕获,且是值传递。
究竟,假定你也想检查 dill
内容,能够经过 mac 下的 xxd 指令:
xxd /Users/xxxxxxx/workspace/flutter-wrok/flutter_app_test/.dart_tool/flutter_build/bf7ed8e7e7b3e64f28f0af8a89a29ca9/app.变量之间的联络dill
也能够经过 dump_kernel.dart
(在完整版变量 dart-sflutter结构优缺点dk
的/Users/guoshuyu/works变量值pace/dart-sdk/pkg/vm
目录下)执行如下指令,生成 app.dill.txt
检fluttered查,appear比方你能够检查 final
和 const
编译后的差异。
dart dump_kernel.dart /变量名的命名规矩Users/xxxxxxx/workspace/flutter-wrok/flutter_app_test/.dart_tool/flutter_build/bf7ed8e7e7b3e64f28f0af8a89a29ca9/app.dill /Users/xxxxxxx/workspace/flutter-wrok/flutter_变量是什么意思app_test/.dart_tool/flutter_build/bf7ed8e7e7b3e64f28f0af8a89a29ca9flutter是什么意思/app.dill.txt