if 选择结构
if 语句有几种不同形式。在最简单的情况下,如果指定的条件为真,它将执行从属语句:
if ( condition )
|
如果条件为假,则跳过该语句,并立即跳转到执行算法的其余部分(后续语句,如有的话)。
该语句可以是简单语句,也可以是复合语句。条件是布尔或可转换类型的表达式。
第二种形式允许指定两个操作分支:不仅包括条件为真 (statement_A) 的操作分支,还包括条件为假 (statement_B) 的操作分支:
if ( condition )
|
无论执行哪个受控语句,算法都将继续执行 if/else 语句下面的语句。
例如,脚本可以遵循不同的策略,这取决于它所在图表的时间范围。为此,只需分析由 Period 内置函数返回的值。该值是 ENUM_TIMEFRAMES 枚举类型。如果小于 PERIOD_D1,则表示短线交易,否则表示长线交易 (StmtSelectionIf.mq5)。
if(Period() < PERIOD_D1)
|
else 分支中的语句允许指定 if 运算符,从而将它们组成一系列连续的检查。例如,下面的代码片段可计算字符串中大写字母和标点符号(更准确地说,非拉丁字母)的数量。
string s = "Hello, " + Symbol();
|
该循环会遍历字符串的所有字符(编号从 0 开始)并且 StringLen 函数返回字符串的长度。第一个 if 检查每个字符,判断是否属于范围 'A' 到 'Z' ,如果是,将大写计数器加 1。如果字符不在此范围内,则运行第二个 if ,其中用于判定是否属于小写字母范围的条件 (s[i] >= 'a' && s[i] <= 'z') 用 ! 运算符进行取反。也就是说,该条件表示字符不在给定的范围内。经过两次连续检查后,如果字符既不是大写字母 (else) 也不是小写字母(第二个 if),则我们可以断定该字符不是拉丁字母表中的字母。在这种情况下,我们将 punctuation 计数器的值递增。
可以用更详细的形式编写同样的检查,即采用 {...} 的代码块以提高可读性。
int capital = 0, small = 0, punctuation = 0;
|
使用花括号有助于避免相关的逻辑错误,程序员仅依赖代码缩进作为参考时可能会发生这种错误。特别是,最常见的问题被称为“挂起”else。
当 if 语句嵌套时,有时会出现 else 分支数量少于 if 分支数量的情况。下面是一个例子:
factor = 0.0;
|
缩进表明程序员所指的逻辑类型:当 mode 大于 20 时,factor 应为 +1,当 mode 介于 10 和 20 之间时,应仍然为 0,否则,应变为 -1 (mode <= 10)。但是代码会那样运行吗?
在 MQL5 中,假设每个 else 引用最近的前一个 if(它没有 else)。其结果是,编译器将按如下方式处理语句:
factor = 0.0;
|
因此,mode 在 10 到 20 范围内,factor 将为 -1,对于 mode <= 10,则为 0。最有趣的是,无论是在编译期间还是在执行期间,程序都没有产生任何形式错误。但就是结果不正确。
为了消除这种隐蔽的逻辑问题,允许添加花括号。
if(mode > 10)
|
为了保持设计的一致性,如果语句的任何一个分支中至少需要一个代码块,那么最好在所有分支中都使用代码块。
当使用循环检查相等性时,要考虑到可能的输入错误,比如误将两个等号 == 写成一个等号 =。这样就把比较变成了赋值,将被赋予的值作为逻辑条件进行分析。例如,
// should have been x == y + 1, which would give false and skip the if
|
编译器将生成一个警告“表达式不是布尔型”。