新闻详情

新闻详情

首页 / 资讯中心 / 详情

Dart流程控制详解:分支、循环与Dart 3新特性

发布时间:2026/10/2 19:23:33来源:尧图网络
Dart流程控制详解:分支、循环与Dart 3新特性
学Dart第五天终于轮到流程控制语句这个模块了。前面几天的变量、集合、函数学下来最直观的感受是语法足够干净该有的东西一样不缺。流程控制在Dart里其实没有太多花活跟Java、JavaScript这类C系语言高度重叠但这恰恰是它的友好之处——你带着其他语言的经验来几乎可以无缝切换。不过Dart还是有自己独特的脾气比如switch必须显式写break、case不允许隐式穿透再比如Dart 3之后switch直接进化出了表达式和模式匹配的玩法。这篇文章就把我在Day05实操中整理出来的内容完整记录下来既有基础的if/for/while也有容易踩坑的细节还有实测过的排查思路希望对正在学Dart的你有点帮助。适合谁看零基础可以按顺序理解概念写过其他语言想快速上手Dart的重点看差异点就行。我会尽量用直白的方式讲配合可以直接跑起来的代码片段保证你照着敲一遍就能建立手感。1. 流程控制的整体设计与思路1.1 Dart流程控制的定位克制但完整先说一个宏观感受。Dart的流程控制语句整体设计思路用一个词概括就是“克制”。它没有Python那种用缩进当语法的激进也没有C那种恨不得给每个关键字都塞满重载的复杂。它选择的是主流C系语言那套经典结构if、for、while、do-while、switch、break、continue几乎都是你熟悉的长相。这份“克制”带来的好处很明显学习成本低、代码可读性高、静态分析的坑少。坏处呢在某些极端场景下会觉得它不够“聪明”比如早期的switch还不支持非const条件、也不允许fall-through。但Dart团队在3.0版本里用switch表达式和模式匹配补齐了很多短板让它从“够用”变成了“真的能写出优雅逻辑”的程度。我在实际练习里体会到的一个核心判断标准是流程控制首先解决的是“程序怎么走”的问题而不是“代码怎么写少”的问题。所以不管语法怎么演进清晰的优先级永远是先保证分支和循环的条件正确再谈简化写法。很多新手一上来就追求用三元表达式、链式判断把代码压到一行结果可读性反而崩了这是我在Day05练习里吃过的小亏。1.2 与其他语言的差异对照掌握了这些就掌握了Dart下面这张表是我学习时自己做的对照把Dart和JavaScript、Java在流程控制上的主要区别列出来有过相关语言经验的人可以快速定位重点。特性DartJavaScriptJavaif/else语法C系标准写法基本一致基本一致switch是否要求break必须显式break/return/throw结尾空case可以穿透允许fall-through容易漏break必须break允许fall-throughswitch条件类型int/String/枚举/常量表达式Dart 3支持更多模式任意类型整型/字符串/枚举循环类型for/for-in/while/do-whilefor/for-in/while/do-whilefor/for-each/while/do-while跳转语句break/continue/labelbreak/continue/labelbreak/continue/label模式匹配Dart 3的switch表达式、if-case语句弱类型随意有限Java 17有preview从这张表能看出Dart在基础控制上和Java最接近但在switch的处理上比Java更严格不允许隐式穿透。这个设计其实是站在“规避bug”角度出发的——C/C里switch缺break导致的暗坑实在太多Dart选择从语法层面直接堵死。后面我会专门展开讲这个细节。1.3 一个总览流程控制在Dart里的完整分类在进入具体语法前先给这份内容画个粗略的地图接着学哪里都清楚分支类if / else if / else、三元运算符、switch表达式与语句循环类for循环、for-in遍历、while循环、do-while循环跳转类break、continue、带标签的break/continue辅助控制assert断言、以及Dart 3新增的if-case、pattern switch这份地图也对应了后面几节的结构。我的建议是不要跳过任何一类因为实际项目里这四类会混着用。比如你写一个网络请求重试的逻辑会同时用到while、break、continue和if判断缺一个都会觉得别扭。2. 分支语句条件与多路选择2.1 if / else if / else最基础但最容易写乱的结构Dart的if语句长这样int score 85; if (score 90) { print(优秀); } else if (score 60) { print(及格); } else { print(不及格); }注意一个容易被忽略的点条件表达式的结果必须是布尔类型。这点和JavaScript很不一样JS里你可以直接写if (score)依赖隐式转换把数字转成布尔值Dart不允许。你写了if (1)编译器直接报错。刚开始从JS转过来的人在这里几乎都会踩一脚。我当时的一个小建议是养成把“最能区分优先级的条件”放在最前面的习惯。比如判断用户状态时把已封禁这种需要优先拦截的情况放在第一个而不是把正常放在第一个。否则后面的分支逻辑会越写越绕多层嵌套之后很难维护。还有一个实战技巧如果条件只是判断一个值是否等于某几个常量用if写多了会显得很笨重这种时候就该切换到switch下面这节就是个很好的例子。2.2 三元运算符写短逻辑的利器但别滥用三元运算符是if-else的语法糖格式是条件 ? 表达式1 : 表达式2。我是这么用的int age 20; String category age 18 ? 成年人 : 未成年人;另一个我个人很喜欢的用法是配合空安全操作符一起判断String? name; String displayName name?.isNotEmpty true ? name! : 匿名用户;不过这里我要真心劝一句三元运算符嵌套三元运算符一定别干代码一行拉满像个加密谜语。我见过有人写出这种“杰作”String result a 0 ? (b 0 ? positive : mixed) : (b 0 ? mixed : negative);这种写法能跑但后续维护的人大概率是你自己会想打人。我的原则是一旦需要嵌套三元立刻改写if-else或者用Dart 3的switch表达式来接管可读性会好很多。2.3 switch语句Dart的纪律性和Dart 3的新玩法先看传统switch在Dart里的标准姿势String command open; switch (command) { case open: print(打开文件); break; case close: print(关闭文件); break; default: print(未知命令); }关键规则来了每个非空case结尾必须显式写break、continue、return或throw。Dart不允许从一个case自动掉落到下一个case执行代码。写case open:之后没写break就去写case close:编译器直接报错不存在“忘了写break”这种运行时事故。你可能会问那如果两个case想执行同一段逻辑怎么办Dart允许空case穿透。也就是说你可以在一个case里什么都不写直接fall到下一个caseswitch (grade) { case A: case B: print(优秀); break; case C: print(合格); break; default: print(补考); }这里case A:没有内容它会被允许“滑过”到case B:执行。这不是漏洞是官方支持的空穿透。Dart 3之后switch的最大变化是支持表达式写法。上面的代码可以改写成一个表达式甚至可以返回一个值String result switch (command) { open 打开文件, close 关闭文件, _ 未知命令, };看到_了吗那是通配符相当于default。整段代码连break都省了因为每个分支都是用箭头表达式返回一个值本身就不存在穿透问题。另外Dart 3还支持if-case这种模式匹配语句比如// 配合Map和模式匹配使用 var user {name: 张三, age: 30}; if (user case {name: String name, age: int age}) { print(用户$name年龄$age); } else { print(数据格式不对); }这种写法在解构Map或List时特别顺手但一开始不用强求掌握。我的建议是先把传统switch玩明白再把表达式写法当作简化工具逐步引入。因为Dart 3的switch表达式虽然简洁但模式匹配的报错信息对于刚接触的人来说可能不够直白你需要基本理解常量模式、类型模式之后才用得顺手。3. 循环语句遍历与重复执行3.1 for循环标准写法与作用域注意事项Dart的for循环长这样和Java几乎一样for (int i 0; i 5; i) { print(第$i次); }但我在Day05踩了一个特别隐蔽的坑循环变量i的作用域只在循环体内部。如果你在循环之后还想用i的值必须在外面先声明int i 0; for (i 0; i 5; i) { // 循环体 } print(循环结束时i $i); // 这里才能访问还有一种更推荐的做法把循环的结果装进一个变量而不是依赖循环变量。比如我想知道1到100里第一个能被7整除的数不用循环结束后读取i而是这样写int found -1; for (int i 1; i 100; i) { if (i % 7 0) { found i; break; } } print(第一个能被7整除的数是$found);循环结束后真正需要的是found这个业务结果不是循环变量本身。把业务结果显式保存下来代码语义更清楚也避免作用域的坑。3.2 for-in循环遍历集合的首选如果你只是要把一个列表里的元素挨个处理一遍for-in比下标for循环更爽ListString fruits [苹果, 香蕉, 橙子]; for (String fruit in fruits) { print(我喜欢$fruit); }以前在Java里写for (String fruit : fruits)到Dart这里就是for (String fruit in fruits)区别只是把冒号换成了in。这一点从其他语言转过来的人应该秒懂。需要注意的一点是如果循环体内需要知道当前索引for-in就给不了你了得回到下标循环或者用索引遍历for (int i 0; i fruits.length; i) { print(第$i个水果是${fruits[i]}); }也可以用Dart的forEach方法配合回调但要注意forEach里不能用break和continue想中途跳出的逻辑还是得用for循环。3.3 while与do-while循环先判断还是后判断while循环先判断条件条件为真才进入循环体。do-while循环先执行一次循环体再判断条件。这个差异听起来很小但使用场景完全不同。// while典型使用场景不确定循环次数 int attempts 0; while (attempts 3) { attempts; print(第$attempts次尝试); }// do-while至少要执行一次的场景 int input; do { input getInputFromUser(); // 不管三七二十一先执行一次 } while (input null); print(用户输入了$input);就拿用户输入来说如果你用while去写就得先把input初始化成一个可能导致循环不执行的值逻辑会别扭。do-while天生适合“先做一次再判断要不要继续”的场景。在写while循环时我最怕的就是忘了更新循环条件导致死循环。比如刚才那个while如果把attempts这行漏掉程序就永远卡在里面了。这一点在排查问题时是头号怀疑对象。Dart的IDE通常能在你写死循环时给警告但依赖IDE不如自己脑子里那根弦每次写while都默念一遍“条件会不会改变”。3.4 break、continue和标签跳转循环的刹车与油门break负责马上跳出当前循环continue负责跳过本次循环的剩余部分、直接进入下一次迭代。for (int i 1; i 10; i) { if (i % 2 0) { continue; // 跳过偶数 } print(奇数$i); if (i 5) { break; // 到7就结束因为7 5 } }这段代码的输出是1、3、5、7奇数里大于5的第一个就是7然后break跳出循环。这个小例子同时演示了两个跳转语句的行为差异。Dart还支持标签跳转也就是给循环起个名字然后配合break/continue指定跳到哪一层。这个在嵌套循环里特别有用比如想在二维数组中找到特定元素后直接跳出外层ListListint matrix [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]; outerLoop: for (var row in matrix) { for (var col in row) { if (col 5) { print(找到5了); break outerLoop; // 直接跳出外层循环 } } }这里outerLoop:就是标签写在最外层循环之前。break outerLoop会让程序从两层循环里一口气跳出来。如果不用标签你只能用一个布尔标志位去打断嵌套或者写return处理起来会很啰嗦。这个技巧在日常编码里属于“低频但救命”的类型。4. 常见问题与排查技巧实录4.1 最容易踩的七个坑速查表这几天我把班里同学和自己踩过的坑整理成了一个表直接对照排查效率很高症状原因解决办法提示条件不是布尔类型写了if (score)这种隐式转换改成if (score 0)之类的显式布尔条件switch报错“case必须结尾”非空case没有break/return/throw补上break或改用空case穿透循环变量在循环外无法使用变量作用域只在for内部在循环外声明变量并保存结果程序卡住不响应while条件没有更新或条件恒真检查循环体里是否修改了条件相关变量循环多跑或少跑一次边界条件写错比如i n写成i n用极端值代入验证n1和n0各试一次continue没跳过预期代码把continue放在需要跳过的代码之后continue只影响它后面的代码执行空列表用for-in没问题但用下标报错索引越界先判空或改用for-in4.2 排查思路三步定位法我以前排查循环相关bug就是瞎看后来总结出一个固定套路基本能应对大部分问题。第一步先看循环条件。把循环变量的初始值和结束条件写出来代入边界值算一遍。比如for (int i 0; i list.length; i)当list长度为0时循环体一次都不执行这是正常行为如果是do-while则会执行一次。明确预期后看实际行为是否一致。第二步看循环体内部的跳转语句。break和continue放的位置直接决定了跳过范围。很多人犯的错误是continue放太靠前导致下面本想执行的代码全被跳过。建议每写一个break/continue都问自己一句话这一跳跳到哪里跳过什么第三步打印关键变量。调试循环最直接的手段就是打印循环变量和关键中间值。Dart里用print(i$i, result$result)看输出就能判断逻辑卡在哪。现在IDE的调试器也能断点看变量但print对于快速验证思路仍然很香。4.3 关于assert断言的一个实用补充严格来说assert不是流程控制但它在“程序走不下去时主动停下”这件事上跟流程控制配合得很好。它的用法是int total 100; assert(total 0, 总数不能为负数);当total小于0时程序会在开发环境抛出一个AssertionError。这里最值得记住的是assert只在开发模式下生效发布到生产环境后会被自动移除。所以不能用assert做输入校验它只适合在开发期做内部不变量检查。我在练习里养成的习惯是循环或分支计算出一个关键结果之后加一个assert来校验结果范围。比如遍历求完最小值后assert(min ! null)这样能更早发现逻辑漏洞而不是等数据崩了才回头排查。5. 实操代码一个融合所有知识点的练习5.1 练习需求模拟一个简单成绩统计器光看语法容易忘我建议把流程控制串起来做个小练习。这里分享一个我Day05练手的小项目统计一组学生分数中的优秀、及格、不及格人数并找出其中最高分和第一个低于60分的学生名字。void main() { MapString, int scores { 张三: 92, 李四: 58, 王五: 73, 赵六: 45, 孙七: 88, }; int excellentCount 0; int passCount 0; int failCount 0; int maxScore 0; String? firstFailName; scores.forEach((name, score) { // 更新最高分 if (score maxScore) { maxScore score; } // 统计档次 if (score 90) { excellentCount; } else if (score 60) { passCount; } else { failCount; firstFailName ?? name; // 记录第一个不及格的人 } }); print(优秀人数$excellentCount); print(及格人数$passCount); print(不及格人数$failCount); print(最高分$maxScore); print(第一个不及格的学生$firstFailName); }这段代码把if-else if-else、forEach、空安全运算符??都用上了。我的点评是用forEach是因为这里不需要break单纯遍历就够了如果需要中途跳出就要改成for-in加break。这种“根据跳转需求选择循环结构”的判断能力比记住语法本身更重要。5.2 加餐用switch表达式处理更复杂的业务分支如果统计完分数后要根据分数段生成评语传统写法是用一大堆if-else但Dart 3的switch表达式更利落String getComment(int score) { return switch (score) { 90 太优秀了继续保持, 60 已经及格还有上升空间, _ 需要加把劲了, }; } void main() { print(getComment(92)); // 太优秀了继续保持 print(getComment(73)); // 已经及格还有上升空间 print(getComment(45)); // 需要加把劲了 } 90这种写法叫关系模式是Dart 3带来的新能力。第一次看会有点陌生但它表达的语义比一连串if-else清晰得多。当然如果你当前的Dart版本还不支持这些新语法用传统if-else完全没问题效果等价。这属于“知道有更好的工具但不必吊死在最新语法上”。6. 我的几点学习体会Day05这天的内容看似基础实际上承载了后面几乎所有复杂逻辑的底层能力。我在实际操作中最深的体会是流程控制不在于你会写多少种语法而在于你能不能准确判断该用哪一种。能用if解决的就别硬套switch能用for-in解决的就别执着于下标需要中途跳出嵌套就立刻想起标签。另一点是关于调试的。学流程控制最推荐的练习方式不是背题而是故意写错再看报错。我可以拍胸脯说我今天从switch报错里得到的理解比看十遍文档都深刻。程序报错不可怕它反而是帮你把规则记牢的最快途径。最后分享一个小技巧给我所有的学习搭子每次写循环之前先在纸面上写清楚“循环变量怎么初始化、条件是什么、每轮怎么变”。这三件事想清楚了写出来的循环基本不会翻车。流程控制这东西说到底就是这三行字的事。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

MCP协议:AI开发者的“万能插线板”,三招破解大模型落地难题(附TaoToken实战配置) 2026/10/2 20:11:43

MCP协议:AI开发者的“万能插线板”,三招破解大模型落地难题(附TaoToken实战配置)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
策略模式+工厂模式:重构多端登录逻辑的最佳实践 2026/10/2 20:11:43

策略模式+工厂模式:重构多端登录逻辑的最佳实践

“每次加一个登录方式就改一遍Controller?那段if-else是不是已经长到你不敢动了?” 如果你维护过稍微有点年头的 SpringBoot 项目,大概率遇到过这种场景:小程序端要手机号快捷登录,管理后台要账号密码登录&#xff0c…

阅读更多 →
微信浏览器Download: Null报错排查与解决:OSS配置与服务端中转方案 2026/10/2 20:11:42

微信浏览器Download: Null报错排查与解决:OSS配置与服务端中转方案

1. 问题现象与成因定位:为什么微信浏览器会弹“Download: Null”1.1 这个报错到底长什么样,什么场景触发先说一个我自己的经历。去年做一个移动端 H5 项目,文件下载功能在 PC 和普通手机浏览器上一切正常,结果一到微信内置浏览器里…

阅读更多 →
迈向超级Agent!谷歌Gemini接入个人智能,TaoToken统一Key打通多工具调用链 2026/10/2 20:11:36

迈向超级Agent!谷歌Gemini接入个人智能,TaoToken统一Key打通多工具调用链

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
美丽的杀手!幕墙如何防范“冰柱坠击”事件 2026/10/2 20:11:36

美丽的杀手!幕墙如何防范“冰柱坠击”事件

美丽的杀手!幕墙如何防范“冰柱坠击”事件 近年来,随着建筑遮阳和外观造型的需要,建筑幕墙檐口和外侧横向悬挑构件越来越多,突出建筑立面可承雪的向上表面的尺寸越来越大,使得建筑幕墙冰坠伤害事故日渐增多,形成了社会公共安全的问题,引起了社会各界的关注。特别是堆积…

阅读更多 →
企业级RAG实战(保姆级教程):从零搭建FastMCP服务,模型上下文协议看这一篇就够了,TaoToken统一Key接入 2026/10/2 20:11:36

企业级RAG实战(保姆级教程):从零搭建FastMCP服务,模型上下文协议看这一篇就够了,TaoToken统一Key接入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉