第16章 控制循环
1.循环的种类
循环用来指代任意一种迭代控制结构,任何一种能够导致应用程序反复执行的一段代码的结构。
循环的种类:
(1)计数循环:预先知道循环的次数。(例如常见的for循环)
(2)连续求值循环:预先不知道要执行多少次,它会在每次迭代时检查是否应该继续。(例如读取文本,直到遇到结束符时结束循环)
(3)无限循环:一旦启动一直执行下去。
(4)迭代器循环:对容器类里面的每个元素都执行一次操作。
2.循环的选择
(1)while循环
如果预先不知道要循环多少次,那么就使用while循环。
有关while循环的主要注意事项就是在循环开始还是结束处检测。
a)检测位于循环的开始
b)检测位于循环的结束 (do-while):该循环至少执行一次
(2)带退出的循环
所谓带退出的循环就是终止条件出现在循环中间而不是开始或者末尾的的循环。(在php中使用while和break来模拟)例如:
while(!endOfData())
{
$data = readDate();
if(errorData($data)) //如果出现数据错误
{
break;
}
process($data);
}
注意:为了便于调试和阅读代码,应当把所有的退出条件放在一起,同时应该用注释来阐明操作意图。
(3)for循环
如果需要一个执行次数固定的循环,那么就可以选择for循环。
注意:不要在for循环里通过直接修改下标的方式迫使循环结束。例如:
for($i=0;$i<=10;$i++)
{
if(error())
{
$i = 10; //修改下标使循环下次不再执行 糟糕的实践
}
。。。。
}
(4)foreach循环(编程语言支持的)
适合对容器内(数组或者其他)的各项元素进行操作。
3.循环控制
1)进入循环
a)把初始化代码紧放在循环前面。
b)用while(true)表示无限循环。
当需要一个无限循环时,(例如服务器监听连接)不要采用for i=1 to 99999这样的虚假无限循环,这样会模糊循环的用意,应当使用while(true),或者for(;;)这样的循环表示。
2)处理好循环体
a)用{ }把循环体中的语句括起来。
增加代码的可读性,防止修改代码时出错。
b)避免空循环。
空循环:把循环所处理的代码和检测循环是否终止的代码写在同一行里。例如:
while( ($inputChar = data->read()) != CharType_Eof )
{
;//循环体内是一个分号,因为循环处理代码已经在上一行做了
}
这是不好的习惯,应该分开完成各部分的内容:
do
{
$inputChar = data->read();
}while($inputChar != CharType_Eof);
c)把循环内务操作放在循环的开始或者末尾。
循环内务操作是指像i=i+1或者j++这样的表达式,他们的主要目的不是完成循环工作,而是控制循环。
d)一个循环只做一件事。
3)退出循环
a)设法确认循环能够终止。
这是使用循环的基本要求。需要考虑正常的情况‘、端点、以及每一种异常情况。
b)使循环终止条件看起来很明显。
c)不要为了终止循环而胡乱改动for循环的下标。(前面提到过)
d)考虑使用安全计数器。
安全计数器可以确保循环执行的次数。例如:
while(nodeNext())
{
saftCounter++;
if(saftCounter >= LIMIT)
{
//终止循环
}
。。。。。
}
4)提前退出循环
所谓提前退出循环是指除了满足循环终止条件以外的循环终止。
a)在某些情况下,通过使用break来实现提前退出循环比使用布尔标记要好,使得程序更容易理解。
b)小心那些有很多break散步其中的循环。
一个循环中包括的break过多,有可能导致错误的退出。例如:
do
{
switch
.......
if()
{
......
break;//这个break在这里本来是要退出if的,结果连循环一起退出了。
}
}while(......);
4.检查端点
对于简单循环来说,需要注意三种情况:开始的情况、任意选择的中间情况、最终的情况,小心出现off-by-one的错误。
5.使用循环变量
(1)用整数或者枚举类型表示数组和循环边界。
(2)嵌套循环中使用有意义的变量名来提高可读性。
(3)避免下标串话。(即在嵌套的循环中用相同的下标名表示不同变量)
(4)把下表变量的作用域限制在循环以内。
这项准则可以获得语言的内建机制的支持,例如在循环头声明下标变量:
for($index=0;$index
{
........
}
在for循环头部声明下标,则index变量的作用域不会超出for循环。