BREAK 与 CONTINUE 语句基础篇:从循环内部掌控程序流向(基础篇)
(1/3)· 多数初学者卡在循环控制命令,本文先铺 RETURN 基底再引出核心跳转逻辑
用 BREAK 和 CONTINUE 给循环装闸
MQL5 里写循环,最容易被忽略的两个控制语句是 break 和 continue。它们不改变循环逻辑本身,只在运行时决定「跳不跳得出去」或者「这轮要不要算了」。 break 一旦触发,直接终止整个循环,后面轮次全不跑;continue 只跳过当前这一轮,紧接着进下一轮判断。实盘里扫 K 线找信号,用错一个就可能漏掉关键根或者白烧 CPU。 下面这段示例在 0..9 的循环里:i 等于 5 时 break 收工,等于 3 时 continue 跳走。跑完终端里会看到输出 0 1 2 4——3 被跳、5 及之后被断。开 MT5 新建脚本粘进去,就能验证这个截断顺序。
for(class="type">int i=class="num">0; i<class="num">10; i++) { if(i==class="num">5) break; if(i==class="num">3) class="kw">continue; Print(i); }
◍ 循环内部控制的三个关键命令
MQL5 里循环不是只有 while 和 do-while 这种显式结构,还有些命令专门用来从循环体内部改变执行流向。上一篇讲 while/do-while 时只涉及进入和退出条件,这一节要补的是在循环跑起来之后,怎么在中途干预它。 常用的三个命令里,有两个能在循环外单独用,但有一个严格限定在循环内。除非遇到极特殊的中断逻辑,否则那个循环专属命令绝不该脱离循环上下文单独出现,否则编译虽可能过,语义已经乱了。 本文重点放在标题点出的两个内部控制命令上——理解不透,后面写 EA 或指标时大概率会在嵌套循环里卡死或漏算。外汇和贵金属行情跳动频繁,这类逻辑错误在高波动时段可能直接引发重复下单或止损失效,属于高风险坑点。
「用循环改写重复调用的落地思路」
上一节留了个练习:把连续五次手动调用 Factorial() 的代码改成循环版本。原文给出的代码 01 在 OnStart 里写了 5 行完全相同的 Factorial() 调用(第 6~10 行),纯靠复制粘贴,维护时极易漏改。 更干净的做法是用 while 把计数器交出去。下面这段代码把 counter 作为引用参数传入函数,OnStart 里只跑一个 while (counter < 5) 循环,调用次数从 5 行压缩到 1 行逻辑。 [CODE] //+------------------------------------------------------------------+ #property copyright "Daniel Jose" //+------------------------------------------------------------------+ void OnStart(void) { uchar counter = 0; while (counter < 5) Factorial(counter); } //+------------------------------------------------------------------+ void Factorial(uchar &counter) { static ulong value = 1; Print("Factorial of ", counter, " => ", value); counter = counter + 1; value = value * counter; } //+------------------------------------------------------------------+ [/CODE] 逐行拆解:第 6 行声明 uchar 类型 counter 初值 0;第 8 行 while 判断 counter 小于 5 时持续进入循环;第 9 行每次把 counter 以引用方式传给 Factorial,函数内第 17 行 counter 自增会直接反映到外部,循环因此能退出。函数里 value 用 static 保活,第一次打印 value=1(0 的阶乘),随后依次算出 1、2、6、24——这是 5 次调用的实际输出序列。 别把静态变量当万能膏药 上面代码 02 依赖 static ulong value 跨调用保留状态,一旦你在别处也调 Factorial 且不重置,value 会带着上次的结果继续乘,输出直接串味。MT5 里测之前先确认调用路径唯一,或改用局部传参。 若你看完仍不理解为何两段代码输出等价,先停下手头往下翻的动作,回前面把引用参数和 static 存储期那块啃透。外汇与贵金属 EA 开发中这类状态管理失误,可能在高频调用下引发难以复现的计算偏差,属高风险环节。
class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Daniel Jose" class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart(class="type">void) { class="type">uchar counter = class="num">0; class="kw">while (counter < class="num">5) Factorial(counter); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void Factorial(class="type">uchar &counter) { class="kw">static class="type">ulong value = class="num">1; Print("Factorial of ", counter, " => ", value); counter = counter + class="num">1; value = value * counter; } class=class="str">"cmt">//+------------------------------------------------------------------+
RETURN 在循环里的提前跳出不终止 EA
有 MQL5 经验的人一眼会看出 RETURN 更像是函数层面的东西,而不是循环语句。确实,它在函数里是必选项,在过程(procedure)里只是可选;正因为它在过程里能用,才常被塞进循环做提前退出。 关键陷阱在 OnInit 和 OnStart:这两个是 MetaTrader 5 直接调用的入口,若在里面执行 RETURN,应用会被终止并从图表移除。OnInit 里是否终止还看返回值,OnStart 里只要碰到 RETURN 就直接死。外汇和贵金属 EA 调试时误写这一句,可能让策略刚加载就消失,属于高风险操作失误。 下面这段是入口过程里写 RETURN 的示范,第 8 行 return 之后第 10 行永远打不出来:
- //+------------------------------------------------------------------+
- #property copyright "Daniel Jose"
- //+------------------------------------------------------------------+
- void OnStart(void)
- {
- Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
07.
- return;
09.
- Print(__FUNCTION__, " ", __LINE__, " This line will never be executed...");
- }
- //+------------------------------------------------------------------+
逐行拆解:04 定义 MT5 入口过程 OnStart;06 先打印一句“无论如何都会执行”;08 直接 return,把控制权交还 MT5,过程结束;10 的打印永远到不了,因为执行流已离开 OnStart。 真正在循环里用 RETURN 退出,要看被谁调用。下面代码里 OnStart 调了 Procedure_Loop,循环内 info 降到低于 -5 就 return:
- //+------------------------------------------------------------------+
- #property copyright "Daniel Jose"
- //+------------------------------------------------------------------+
- void OnStart(void)
- {
- Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
07.
- Procedure_Loop();
09.
- Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
- }
- //+------------------------------------------------------------------+
- void Procedure_Loop(void)
- {
- char info = 10;
16.
- Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
18.
- while (info)
- {
- info = info - 3;
22.
- Print("Loop : ", info);
24.
- if (info < -5) return;
- }
27. 逐行拆解:04–11 是 OnStart,调完子过程还会打印第 10 行;13 定义无返回过程 Procedure_Loop;15 给 info 初值 10;19–26 是 while 循环,每轮减 3 并打印;25 判断 info 小于 -5 就 return,此时只退回 OnStart,不会杀掉整个程序。 跑出来的值从 7 到 -8 为止,第 28 行(若有)不会执行。原因是 RETURN 只把控制权还给调用方,这里调用方是 OnStart 而非 MT5 系统,所以应用继续活着。 别把入口 return 当循环 break 用 很多人初写 EA 把 OnStart 里的 return 当成跳出循环,结果策略直接被 MT5 卸掉。记住:只有 MT5 直接调的 OnInit / OnStart 内 return 才致命,子过程里的 return 只是还本层调用。开 MT5 把上面两段分别挂脚本跑一遍,看终端输出差异最直观。
class="num">01. class=class="str">"cmt">//+------------------------------------------------------------------+ class="num">02. class="macro">#class="kw">property copyright "Daniel Jose" class="num">03. class=class="str">"cmt">//+------------------------------------------------------------------+ class="num">04. class="type">void OnStart(class="type">void) class="num">05. { class="num">06. Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway..."); class="num">07. class="num">08. class="kw">return; class="num">09. class="num">10. Print(__FUNCTION__, " ", __LINE__, " This line will never be executed..."); class="num">11. } class="num">12. class=class="str">"cmt">//+------------------------------------------------------------------+ class="num">01. class=class="str">"cmt">//+------------------------------------------------------------------+ class="num">02. class="macro">#class="kw">property copyright "Daniel Jose" class="num">03. class=class="str">"cmt">//+------------------------------------------------------------------+ class="num">04. class="type">void OnStart(class="type">void) class="num">05. { class="num">06. Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway..."); class="num">07. class="num">08. Procedure_Loop(); class="num">09. class="num">10. Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway..."); class="num">11. } class="num">12. class=class="str">"cmt">//+------------------------------------------------------------------+ class="num">13. class="type">void Procedure_Loop(class="type">void) class="num">14. { class="num">15. class="type">char info = class="num">10; class="num">16. class="num">17. Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway..."); class="num">18. class="num">19. class="kw">while (info) class="num">20. { class="num">21. info = info - class="num">3; class="num">22. class="num">23. Print("Loop : ", info); class="num">24. class="num">25. if (info < -class="num">5) class="kw">return; class="num">26. } class="num">27.