BREAK 与 CONTINUE 语句基础篇:从循环内部掌控程序流向(基础篇)
🔁

BREAK 与 CONTINUE 语句基础篇:从循环内部掌控程序流向(基础篇)

(1/3)· 多数初学者卡在循环控制命令,本文先铺 RETURN 基底再引出核心跳转逻辑

偏理论 第 1/3 篇
不少刚碰 MQL5 的人把循环写成死跑不停的累赘,碰到异常分支只会硬套外层判断。没搞清 RETURN、BREAK、CONTINUE 各自作用域,后面写指标或 EA 控制逻辑必然反复踩坑。

用 BREAK 和 CONTINUE 给循环装闸

MQL5 里写循环,最容易被忽略的两个控制语句是 break 和 continue。它们不改变循环逻辑本身,只在运行时决定「跳不跳得出去」或者「这轮要不要算了」。 break 一旦触发,直接终止整个循环,后面轮次全不跑;continue 只跳过当前这一轮,紧接着进下一轮判断。实盘里扫 K 线找信号,用错一个就可能漏掉关键根或者白烧 CPU。 下面这段示例在 0..9 的循环里:i 等于 5 时 break 收工,等于 3 时 continue 跳走。跑完终端里会看到输出 0 1 2 4——3 被跳、5 及之后被断。开 MT5 新建脚本粘进去,就能验证这个截断顺序。

MQL5 / C++
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 开发中这类状态管理失误,可能在高频调用下引发难以复现的计算偏差,属高风险环节。

MQL5 / C++
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 把上面两段分别挂脚本跑一遍,看终端输出差异最直观。

MQL5 / C++
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.     
把循环诊断交给小布盯盘
这些基础控制流的理解门槛,小布盯盘的 AIGC 已内置示例拆解,打开对应品种页的代码助手即可边看边试,你专注把逻辑跑通。

常见问题

RETURN 虽主要服务于函数,但在过程代码里也能提前退出,理解它才能分清哪些跳出行为受限循环、哪些不限,为后续两个命令铺底。
可以出现在 switch 结构内用于跳出分支,但它严格限定不能脱离这类块结构单独乱用,否则编译或逻辑会出问题。
在大数据量历史回测中,合理用 CONTINUE 跳过无效 K 线可能减少冗余计算,但滥用会导致可读性下降,倾向结合具体策略评估。
可以,小布盯盘内置的 AIGC 代码助手能对照基础篇逻辑提示 RETURN、BREAK 误用点,省去你翻文档的时间。
概率上不建议,本文明确以已掌握 WHILE 和 DO WHILE 为前提,跳读可能造成循环转化示例完全看不懂。