重新审视案例4-2的解决思路,可能有的读者会想到:完全不使用ElseIf语句也能够解决这个问题。比如把代码写成下面的样子:
在这个新的解决方案中一共有3个完整的If … End If判断结构,而且这些判断结构的每个分支里还有可能包含另一个判断结构。这种“一环套一环”的写法,就被称为“嵌套判断结构”。
对于案例4-2,使用嵌套结构显然不如直接使用ElseIf判断语句清晰简洁。因为该案例中奖学金的计算规则完全依据平均成绩这个因素,因此“>=85”“>=80”“>=60”可以被看作“相互平行、择一即可”的三个标准。但是假如需要根据多个因素进行判断,而且判断规则“层层递进”,那么使用嵌套结构就会更加符合业务逻辑,比如案例4-3所示的新的奖学金计算方案。
案例4-3: 重新修订案例4-2的奖学金发放规则:只有平均成绩在80分及以上的同学才有资格获得奖学金。其中数学成绩达到90分者可得奖学金3000元,否则发放奖学金2000元。案例4-3的原始数据及预期运行效果如图4.14所示。
图4.14 案例4-3的原始数据及预期运行效果
在这个案例中,计算奖学金的金额时需要先看平均成绩,再看数学成绩,这属于典型的“递进关系”或“多层判断”,因此可以在代码中使用嵌套 If 结构。比如在下面的参考答案中,首先使用一个If … Else … End If结构,判断其平均成绩是否在80分以上。如果不是,就执行Else中的语句 “amount=0”,并结束判断;反之如果符合该条件,那么就执行If与Else之间的代码,也就是第一个分支。而在这个分支中,又会遇到一个新的判断结构,进一步判断其数学成绩是否大于90分,如果是则让amount等于3000,否则让它等于2000。
从这个例子可以看出,嵌套If结构可以清晰地表达层层递进的判断规则。不过如果想用好嵌套结构,还需要读者注意一些重要的技巧和细节。
(1)每个判断结构必须书写完整。
通过前面的学习可知,一个标准的If判断结构必须以“If … Then”为起始,以“End If”作为结束,这两条语句缺一不可 。所以在嵌套结构中,必须保证每个If结构都有头有尾,书写完整,否则就会引发一些莫名其妙的错误。
比如在案例4-3的参考答案中,如果忘记书写第二层判断结构(数学成绩>=90)的End If,就会引发一个奇怪的“Else 没有If”警告,如图4.15所示。
图4.15 在案例4-3的参考答案中忘记书写第二层判
之所以出现这个错误,是因为VBA在执行到第二层If语句,即“If Cells(i,4)>=90 Then”时,发现这个结构的Else子句后面没有End If语句,而是一个Else语句,即“Else amount=0”,然后才出现“End If”。于是VBA理所当然地认为第二层If结构是以这个“End If”为结束的,而在这个结构中一共包含了两个Else子句。但实际上,一个If结构中只能出现一个Else语句,否则就会产生“Else找不到If”的错误。
通过观察图4.15中的代码和错误,还可以总结出一个规律:当程序中存在多个 If 结构时,VBA 会自己判断各个“If…Then”语句与“End If”语句之间的配对关系。判断的顺序归纳起来就是八个字:先内后外,近者优先。比如在图4.15所示的例子中,VBA 先为最内层的判断结构(数学成绩>=90)寻找End If,找到离它最近的尚未配对的End If作为这个判断结构的结束;然后再考虑它外面的一层判断结构(平均分>=80),寻找离它最近的尚未配对的End If,以此类推。所以,如果我们忘写某层判断结构的End If,VBA可能会把它外面一层判断结构的End If分配给它,最后导致最外层的判断结构缺少End If。所以,把每个判断结构都书写完整,做到有If就有End If,是非常重要的。
(2)合理使用缩进格式。
当多个判断结构嵌套在一起时,应当合理使用缩进,从而体现出各个判断结构之间的包含关系,否则会给阅读代码和调试错误带来极大的困扰。比如案例4-3的参考答案,如果不使用缩进格式,一旦出错将很难找出错误原因,如图4.16所示。
图4.16 使用缩进与不使用缩进格式案例4-3的参考
当然,不使用缩进格式也完全不影响程序的运行,在计算机看来,图4.16中两种格式的代码是完全等价,没有任何区别的。但是随着程序设计学习不断深入,我们编写的程序日益复杂,将会出现大量的嵌套结构(不仅是判断语句之间的嵌套,还包括循环、对象等嵌套结构)。这时必须使用缩进和空行保持清晰的代码格式,以便于阅读,毕竟开发人员才是保证程序逻辑正确、灵活高效的关键因素。这点至关重要,以至于在Python等一些最新的程序设计语言中,正确使用缩进格式已经成为强制性要求,一旦格式不正确就会直接导致程序无法运行。所以很多Python开发者会开玩笑地说:不带一把游标卡尺就别想写出正确的代码。
(3)必须避免交叉嵌套。
当两个结构(如If判断结构或For循环结构)存在嵌套关系时,内层结构必须完整地包含于外层结构之中,否则就会形成交叉嵌套,导致程序无法运行。比如在图4.17所示的两段案例4-1的参考答案中,均包含一个For结构和一个If结构。在图4.17左侧所示的正确代码中,If结构从开始(If … Then)到结束(End If)都包含于For结构的循环体内;然而在图4.17右侧所示的错误代码中,If结构的起始行(If…Then)处于For的循环体内,但其结束行(End If)却位于For的循环体之外,也就是在Next语句的后面。图4.17右侧所示代码的写法就是典型的交叉嵌套,无法被VBA理解和执行,只会导致错误警告。
图4.17 正确嵌套的代码与错误的交叉嵌套代码示例