本篇首要经过一个简略比如,谈论一下 Dart 代码里一个风趣的现象。

咱们都知道 Dart 里一切都是方针,就连根底类型 intdoublebool变量都是 class

当咱们关于 intdouble 这些 class 进行的 +-* 等操作approve时,其实是执行了这个 classoperator 操作符的操作flutter结构, 然后回来了新的 num 方针。

带你深化 Dart 解析一个风趣的引用和编译试验

关于这些 operator 操作究竟会经过 VM 去进行实现回来,而本质上 dart 代码也仅仅文本变量泵,需求究竟编译成二进制去作业。

带你深化 Dart 解析一个风趣的引用和编译试验

以下比如根据 dflutter怎样读音发音art 2.12.3 检验

那这儿想要谈论什么呢?

首要咱们看一段代码app安装下载,如下代码所示,fluttered能够看到:

  • 首要咱们界flutter菜鸟教程说了一个叫 idxint 型参数;
  • 然后在 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)getItemindexflutter是什么意思 引用,然后下次又再次传递一个对应的 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.txtfluttered查,appear比方你能够检查 finalconst 编译后的差异。

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