Perl5学习笔记-第七章-控制结构
2010-07-03 15:06:22 阿炯

一、条件判断
二、循环:
1、while循环
2、until循环
3、for循环
4、foreach循环(针对列表(数组)每个元素)
5、do循环
6、标签循环
7、循环控制
8、goto语句
三、单行条件


判断运算

布尔值判断

如果是数字,0表示假,其它所有数字都是真。
如果是字符串,空字符串('')为假,其它所有字符串为真(有例外,见下一条)。
如果是字符串'0',perl是当作数值0来处理的,所以这是唯一的非空但为假的字符串。
如果既不是数字,也不是字符串,那么先转换为数字或字符串再做判断(也就是"undef"表示假,其它所有引用表示真)。
"!"表示取反。

perl有个技巧,将两个“!”一起用,相当于“负负得正”,所以原来是真的仍然是真的,原来是假的仍然是假的。但实际上,perl会将它们转换值"1"和"undef"。

$still_true = !!"fred"; # $still_true的值是1
$still_false1 = !!"0"; # $still_false1的值为空(undef)
$still_false2 = !!""; # $still_false2的值为空(undef)

print "$still_true"."\n";
print "$still_false1"."\n";
print "$still_false2"."\n";

逻辑运算符:and(&&)、or(||)、//、not(!)

expr1 < and or && || // > expr2
<not !>expr

&&运算符只有两边为真时才返回真,且短路计算:expr1为假时直接返回false,不会评估expr2
||运算符只要一边为真时就返回真,且短路计算:expr1为真时直接返回true,不会评估expr2
and和or基本等价于对应的&&和||,但文字格式的逻辑运算符优先级非常低
not和!求反,同样文字格式的not的优先级很低
因为符号格式的逻辑运算符优先级很高,所以往往左边和右边都会加上括号,而文字格式的优先级很低,左右两边不需加括号
//运算符见下文

if (($n >=60) && ($n <80)){
 print "...";
}

if ($n >=60 and $n <80){
 print "...";
}

or运算符往往用于连接两个“成功执行,否则就”的子句。例如,打开文件,如果打开失败,就结束该perl程序:
open LOG '<' "/tmp/a.log" or die "Can't open file!";

更常见的,还会分行缩进:
open LOG '<' "/tmp/a.log" or die "Can't open file!";

同样,and运算符也常用于连接两个行为:左边为真,就执行右边的操作(例如赋值)。

$m < $n and $m = $n; # 以$m的姿态取出$m和$n之间较大值

以下是3个语句是等价语句:
if ($m<$n){$m=$n}
$m=$n if $m<$n;
$m=($m < $n) ? $n : $m;

短路计算和//

perl的短路计算非常特别,它返回的是最后运算的表达式的值:
如果这个返回值对应的布尔值为真,则整个短路计算自然为真
如果这个返回值对应的布尔值为假,则整个短路计算自然为假

这个返回值有时候很有用,往往通过逻辑或的操作来设置默认值,所以这个返回值既保证短路计算的结果不改变,又能得到返回值。
my $name = $myname || "freeoa"

当$myname变量存在时,它返回真(0是例外,见下面),并将$myname赋值给$name;当$myname变量不存在时,它返回假,于是评估“freeoa”,因为是个字符串,所以返回真,于是将freeoa赋值给$name。这样一来,$myname变量就有了默认值。

但如果$myname变量存在,但值为0(字符串的或数值的),由于它也返回假,导致$name被赋以“freeoa”。

这种行为显然并非我们所需要的。于是改用下面这种先判断,再赋值的行为:
my $name = defined($myname) ? $myname : "freeoa";

但是这样的写法比较复杂,perl 5.10版本提供了更方便的“逻辑定义或”(logical defined-or)操作符//:当发现左边的值是已经定义过的,就直接进行短路计算,而不管该左边的值评估后是真是假。
use 5.10;
my $name = $myname // "freeoa";

这个操作符应对开启了use warnings功能的perl程序很有用,免得warnings发出烦人的警告。


一、条件判断
Perl条件语句if和unless,它们允许你控制脚本的执行。if语句有五种不同的格式:
if (EXPR)
if (EXPR) BLOCK
if (EXPR) BLOCK else BLOCK
if (EXPR) BLOCK elsif (EXPR) BLOCK ...
if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK
STATEMENT if (EXPR)

建立if语句的另一种方法是使用多个表达式,然后根据哪个表达式是真,来运行代码:可以像下面这样来读取上面这个语句块:如果标号为expression 1的表达式是真,那么语句块BLOCK1就运行。否则,控制权转给elsif,对expression 2进行测试,如果该表达式是真,则运行BLOCK2。如果expression 1和expression 2都不是真,那么BLOCK3运行。

其中EXPR可以是任意一个标量值。布尔值的判断很简单,方式和bash shell有点类似,但有点相反。

unless和if判断方式相反,if的condition为真则执行后面的代码,否则执行else或者退出if结构。unless则是condition为假时才执行后面的代码,否则执行else或退出unless结构。所以unless相当于if的else部分,或者相当于if(!condition)。

一般来说,不会用到unless的else语句,因为它完全可以改编成if语句。之所以有时候会使用unless而不是if的否定形式,是因为有时候的条件语句用if来写确实不方便。条件语句盘点:

if 语句
一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。

if...else 语句
一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。

if...elsif...else 语句
可以在一个 if 语句后可跟一个可选的 elsif 语句,然后再跟另一个 else 语句。

unless 语句
一个 unless 语句 由一个布尔表达式后跟一个或多个语句组成。

unless...else 语句
一个 unless 语句 后可跟一个可选的 else 语句。

unless...elsif..else statement
一个 unless 语句 后可跟一个可选的 elsif 语句,然后再跟另一个 else 语句。

switch 语句
在最新版本的 Perl 中可以使用 switch 语句,它根据不同的值执行对应的代码块。但在后续的版本中又被标识为实验性质。


二、循环
Perl提供了以下几种循环类型

while 循环
当给定条件为 true 时,重复执行语句或语句组。循环主体执行之前会先测试条件。

until 循环
重复执行语句或语句组,直到给定的条件为 true。 循环主体执行之前会先测试条件。

for 循环
多次执行一个语句序列,简化管理循环变量的代码。

foreach 循环
foreach 循环用于迭代一个列表或集合变量的值。

do...while 循环
除了它是在循环主体结尾测试条件外,其他与 while 语句类似。

嵌套循环
可以在 while、for 或 do..while 循环内使用一个或多个循环。

循环控制语句

循环控制语句改变了代码的执行顺序,通过它你可以实现代码的跳转。Perl 提供了下列的循环控制语句:

next 语句
停止执行从next语句的下一语句开始到循环体结束标识符之间的语句,转去执行continue语句块,然后再返回到循环体的起始处开始执行下一次循环。

last 语句
退出循环语句块,从而结束循环。

continue 语句
continue 语句块通常在条件语句再次判断前执行。

redo 语句
redo 语句直接转到循环体的第一行开始重复执行本次循环,redo语句之后的语句不再执行,continue语句块也不再执行。

goto 语句
有三种 goto 形式:got LABLE,goto EXPR,和 goto &NAME。


主要有四类主循环类型:
while、for、until、foreach

在每一种情况下,继续执行循环,直到表达计算值发生变化。
表达式的值为true时,一个while循环执行继续进行。
until 循环执行,而循环的表达式是假的(false),只有停止时表达式计算为一个真值(true)。
列表形式和foreach循环的特殊情况,他们继续下去,直到结束为止所提供的列表。

1、while循环
while循环有三种形式:
while EXPRLABEL
while (EXPR) BLOCKLABEL
while (EXPR) BLOCK continue BLOCK

在第一种形式,表达的是首先计算,然后它适用的声明被求值;第二个while循环的形式反复执行代码块由于条件表达式的结果是真的(true)。

$i=0;
while($i < 10){
    print "$group[$i]\n";
    $i++;
}

主块主要用于为每个迭代执行一个给定的语句(或语句)后continue块立即执行,不论怎样终止当前迭代方法。这是某种相当于循环:
my $i = 0;
while($i <100){ ... }
continue{
   $i++;
}

1 while (...)

相当于

while(...){
    1;
}

可见:简洁与可读性是矛盾的,甚至包括性能在内。

2、until循环
$i = 0;
until($i == 10){
    print "$group[$i]\n";
    $i++;
}

联合示例:从数组中移除指定的元素

use v5.20;
use Data::Dumper;

#remove 'Sleepy' from array by splice
my $index=0;
my @dwarfs = qw(Freeoa Grumpy Happy Sleepy Sneezy Dopey Bashful);
#splice @dwarfs, 3, 1;
print Dumper \@dwarfs;

say '-' x 19;

#$index++ until $dwarfs[$index] eq 'Sleepy';
$index++ while $dwarfs[$index] ne 'Sleepy';
say '$index:',$index,';','$dwarfs[$index]:',$dwarfs[$index];
splice(@dwarfs, $index, 1);
print Dumper \@dwarfs;

3、类C的for循环 ,如
for($count=1; $count <= 5; $count++){
  # statements inside the loop go here
}

for关键字后面括号中的3个表达式都可以省略,但两个分号不能省略:
如果省略第三个表达式,则表示一直判断,直到退出循环或者无限循环
如果省略第二个表达式,则表示不判断,所以会无限循环
如果省略第一个表达式,则表示不做初始赋值

for循环基本上是一个while循环重新计算原有的条件表达式使用一个额外的表达,基本格式是:
LABEL for (EXPR; EXPR; EXPR) BLOCK

第一个expr是初始化 - 变量值在循环开始之前迭代。第二是要作为一个测试循环的每次迭代执行的表达。第三个表达式为每个迭代执行,应该是一个循环变量修饰符。下面是在for循环中使用逗号操作符的例子:
for ($line = <>, $count = 1; $count <= 3; $line = <>, $count++) {
  print ($line);
}

它等价于下列语句:
$line = <>;
$count = 1;
while($count <= 3){
  print ($line);
  $line = <>;
  $count++;
}

可以创建一个类似这样的无限循环:
for(;;){
...
}

对于无限循环,Perl中更好更优化的方式是使用:
while(1){
    command;
}

for也支持成员测试性的遍历,就像shell中的for i in ...的操作一样,它期待一个列表上下文,表示遍历整个列表。如果省略控制变量,表示使用$_。例如:
my @arr = qw(Shell Python Perl PHP);
for $i (@arr){ print "$i\n" }
for (@arr) {print "$_\n"}

像for遍历列表元素的操作,可以使用foreach来替代,大多数迭代列表的时候它们可以互换。foreach则是简单版的for循环。


4、针对列表(数组)每个元素的循环:foreach, 语法为:
foreach localvar (listexpr){
  statement_block;
}

LABEL foreach VAR (LIST) BLOCK
LABEL foreach VAR (LIST) BLOCK continue BLOCK

示例:
foreach $word (@words){
  if ($word eq "the"){
    print ("found the word 'the'\n");
  }
}

注意:
(1)此处的循环变量localvar是个局部变量,如果在此之前它已有值,则循环后仍恢复该值。
(2)在循环中改变局部变量,相应的数组变量也会改变,如:
@list = (1, 2, 3, 4, 5);
foreach $temp (@list){
  if ($temp == 2){
    $temp = 20;
  }
}

此时@list已变成了(1, 20, 3, 4, 5)。

5、do循环
do {
  statement_block
} while_or_until (condexpr);
do循环至少执行一次循环。

$i = 0;
do {
    print "$group[$i]\n";
    $i++;
} while($i < 10);

从PASCAL语言借鉴来的do...until循环:
$i = 0;
do {
    print "$group[$i]\n";
    $i++;
} until ($i == 10);

甚至还有利用动态语言特性,用map函数也可以做循环:
map { print "$_\n" } @group;

until循环与while循环相反,until循环仅在表达式返回假,计算条件表达式并重申过的循环。一旦表达式返回true,循环结束。在一个do..until循环的案例下,条件表达式只计算在代码块的结束。until(表达式)块循环,在计算表达式之前块执行:

do{
  $calc += ($fact*$ivalue);
} until $calc >= 100;

This is equivalent to:
do{
  $calc += ($fact*$ivalue);
} while $calc <100;

6、 标签循环
标签可应用于任何块,但它们使的在循环最有意义的。由您给定循环名称,使闭环控制关键字指定操作,应适用于这样循环。标记循环的格式是:
LABEL: loop (EXPR) BLOCK ...

ITERATE: for (my $i=1; $i<100; $i++){
   print "Count: $i\n";
}

7、循环控制之last、next、redo、LABEL(标签)
退出循环为last,与C中的break作用相同;执行下一个循环为next,与C中的continue作用相同;Perl特有的一个命令是redo,其含义是重复此次循环,即循环变量不变,回到循环起始点,但要注意,redo命令在do循环中不起作用。循环控制 - 下一步, 上一步和重做

有三个循环控制关键字: next, last, and redo

last相当于其它语言里的break关键字,用于退出当前循环块(for/foreach/while/until/执行一次的语句块都属于循环块),注意是只退出当前层次的循环,不会退出外层循环
next相当于其它语言里的continue关键字,用于跳入下一次迭代。同样只作用于当前层次的循环
redo用于跳转到当前循环层次的顶端,所以本次迭代中曾执行过的语句可能会再次执行
标签用于为循环块打上标记,以便那些循环块控制关键字(last/next/redo)可以指定操作的循环层次

next 关键字跳过余下的代码块,强制循环进行循环中的下一个值。例如:
while (<DATA>){
   next if /^#/;
}

上面的代码将跳过文件中的行,如果他们与一个hash符号开始。如果有一个continue块,它执行之前继续执行下一轮循环。last关键字完全结束循环,跳过代码块中的剩余的语句,以及循环丢弃。因此,最后的关键字与C和Shellscript break关键字相同。例如:
while (){
   last if($found);
}

将退出循环,如果发现$found的值是真的(true),该文件的末尾是否实际上已达到或没有。不执行continue块。

redo关键字重新执行不重新计算循环的条件语句的代码块。这将跳过余下的代码块和continue块之前重新执行主代码块。例如下面的代码会从文件中读取下一行,如果当前行以反斜杠终止:
while(<DATA>){
   if (s#\\$#){
      $_ .= <DATA>;
      redo;
   }
}

下面是一个例子展示如何在内部和外部的循环使用标签:
OUTER:
while(<DATA>){
    chomp;
    @linearray=split;
    foreach $word (@linearray){
        next OUTER if ($word =~ /next/i)
    }
}

示例:
use v5.10;
foreach (1..10){
    say "startline...: $_";
    say "enter a word: last, next, redo?";
    chomp(my $choice = <STDIN>);
    last if $choice =~ /last/i;
    next if $choice =~ /next/i;
    redo if $choice =~ /redo/i;
    say "endline...: $_";
}
say "outside loop...";

以下是打标签的示例(标签建议采用大写):
use v5.10;
LINE: while(<>){
    foreach(split){
        last LINE if /error/i;
        say "$_";
    }
}

上面的标签循环中,首先读取一行输入,然后进入foreach遍历,因为split没有参数,所以使用默认参数$_,这个$_所属范围是while循环,split以空格作为分隔符分割这一行,同时foreach也没有控制变量,所以使用默认的控制变量$_,这个$_所属范围是foreach循环。当foreach的$_能匹配字符串”error”则直接退出while循环,而不仅仅是自己的foreach循环。这里if语句后采用的匹配目标是属于foreach的默认变量$_。

例如,这个perl程序读取a.txt文件,其中a.txt文件的内容如下:
$ cat a.txt
1hello world
2hello world Error
3hello world Error hei2

执行这个perl程序:
$ perl -w test.plx a.txt
1hello
world
2hello
world

可见,只输出了a.txt中第二行Error前的4个单词。

8、附加循环代码:continue
perl中还有一个continue关键字,它可以是一个函数,也可以跟一个代码块。

continue # continue函数
continue BLOCK # continue代码块

如果指定了BLOCK,continue可用于while和foreach之后,表示附加在循环结构上的代码块。
while(){
    code
}continue{
    attached code
}

foreach(){
    code
}continue{
    attached code
}

每次循环中都会执行此代码块,执行完后进入下一循环。在continue代码块内部,也可以使用redo、last和next控制关键字。所以这几个流程控制关键字更细致一点的作用是:redo、last直接控制循环主体,而next是控制continue代码块。所以:
while(){
    # redo jump to here
    CODE
}continue{
    # next jump to here
    CODE
    # next loop
}
# last jump to here

实际上,while和foreach在没有给定continue的时候,逻辑上等价于给了一个空的代码块,这时next可以跳转到空代码而进入下一轮循环。

示例:
use v5.20;
$a=3;
while($a<10){
    if($a<6){
        print '$a in main if block: ',$a,"\n";
        next;
    }
}continue{
    print '$a in continue block: ',$a,"\n";
    $a++;
}

输出结果:
$a in main if block: 3
$a in continue block: 3
$a in main if block: 4
$a in continue block: 4
$a in main if block: 5
$a in continue block: 5
$a in continue block: 6
$a in continue block: 7
$a in continue block: 8
$a in continue block: 9


9、传统的goto label语句
有三种基本的Goto形式:goto LABEL, goto EXPR 和 goto &NAME,在每一种情况下,执行从当前位置到目的地。在GOTO标签的情况下,停止执行在当前点和恢复点指定的标签。goto在现代编程语言中已经不再被推荐和被鼓励,因其副作用太多。

goto &NAME 语句更为复杂。它允许你指定的子程序,而不是取代与当前执行的子程序调用。

Label:
It will simply jump to the statement marked with the LABEL, and will continue the execution from that statement.
它将简单地跳转到带有LABEL标记的语句,并从该语句继续执行。

Expression:
In this form, there will be an expression that will return a Label name after evaluation and goto will make it jump to the labeled statement.
在这种形式中,将有一个表达式,它将在求值后返回一个Label名称,并且goto将使其跳转到标记的语句。

Subroutine:
goto will transfer the compiler to the subroutine of the given name from the currently running subroutine.
将编译器从当前运行的子程序转移到给定名称的子程序。

调用形式如下:
goto LABEL

goto EXPRESSION

goto Subroutine_Name

1.goto using LABEL name:
LABEL name is used to jump to a specific statement in code and will start execution from that statement. Its reach is limited though. It can work only within the scope from where it is being called.

# print numbers by lable
# from 1 to 10 using goto statement

# function to print numbers from 1 to 10
sub say_nums() {
    my $n = 1;
label:
    print "$n ";
    $n++;
    if ($n <= 10) {
        goto label;
    }
}

say_nums();

2.goto using Expression:
An expression can also be used to give a call to a specific label and pass the execution control to that label. This expression when passed to the goto statement, evaluates to generate a label name, and further execution is continued from that statement defined by that label name.

# print numbers by expres
# from 1 to 10 using the goto statement
# Defining two strings which
# contain label name in parts
my ($a,$b) = ("lab","el");

# function to print numbers from 1 to 10
sub say_nums() {
    my $n = 1;
label:
    print "$n ";
    $n++;
    if ($n <= 10) {
        # Passing Expression to label name
        goto $a.$b;
    }
}

say_nums();

3.goto using Subroutine:
A subroutine can also be called with the use of the goto statement. This subroutine is called from within another subroutine or individually based on its use. It holds the work that is to be performed next to the calling statement. This method can be used to call a function recursively to print a series or a range of characters.

# print numbers by subroutine
# from 1 to 10 using goto statement
# function to print numbers from 1 to 10
sub label {
    print "$n ";
    $n++;
    if($n <= 10) {
        goto &label;
    }
}

my $n = 1;
label();

perlsub中对函数调用的一段说明:
To call subroutines:
NAME(LIST);    # Regular subroutine call.
NAME LIST;    # Parentheses optional if predeclared/imported.
&NAME(LIST);    # Circumvent prototypes.
&NAME;    # Makes current @_ visible to called subroutine.
&foo;    # foo() gets current args, like foo(@_)!

&形式不仅使参数列表成为可选的,它还禁用了对所提供的参数的任何原型检查。下面提供了一个递减输出字符串的函数示例。

use v5.32;

my $strd='Free';

sub repeatx {
    my ($cnt,$str)=@_;
    $str=$strd unless(defined($str));
    return if($cnt<=0);
    say $str x $cnt--;
    @_=($cnt,'OA');
    goto &repeatx;
    #warn for 'goto must have label at freeoa.net.pl line NN' following
    #goto &repeatx($cnt,'Oa');
    #goto repeatx->($cnt,'Oa');
    #goto __SUB__->($cnt,'Oa'); #above v5.16.0
}

repeatx(5);


10、each遍历
each HASH
each ARRAY

each用来遍历hash或数组,每次迭代的过程中,都获取hash的key和value,数组的index(从0开始的数值)和元素值。each放在列表上下文,会返回key/value或index/element,放在标量上下文则只返回key或index。

each放在标量上下文:
my %hash = (
    name1 => "freeoa",
    name2 => "wugui",
    name3 => "xiaofang",
    name4 => "woniu",
);
my @arr = qw(Perl Shell Python PHP Ruby Rust);

while(my($key,$value) = each %hash){
    print "$key => $value\n";
}

while(my($key) = each %hash){
    print "$key\n";
}

while(my($key,$value) = each @arr){
    print "$key => $value\n";
}

while(my($key) = each @arr){
    print "$key\n";
}


三、单行条件
语法为statement keyword condexpr。其中keyword可为if、unless、while或until,如:
print ("This is zero.\n") if ($var == 0);
print ("This is zero.\n") unless ($var != 0);
print ("Not zero yet.\n") while ($var-- > 0);
print ("Not zero yet.\n") until ($var-- == 0);
 
虽然条件判断写在后面,但却是先执行的。

指令: unless 假如非
unless的含义就是说“如果判别式不为真,就执行...”。

语法一:
unless(判别运算式) {
判别式为假时语句块;
}

上个语法在Perl中也可以写成:判别式为假时语句块 unless(判别运算式)

print"请输入您的分数?\n";
$scorre=<STDIN>;  #代表标准输入,会让使用者输入一字符串
chop($score); #将$score最后一个换行字符\n删除掉
unless($score<60){
 print"您的分数及格了!\n";
}
也可以写成: print"您的分数及格了!\n"unless($score<60);

语法二:
unless(判别运算式){
判别式为假时语句块;
}else{
判别式为真时语句块;
}

print"请输入您的分数?\n";
$scorre=<STDIN>;
chop($score);
unless($score<60){
print"您的分数及格了!\n";
}else{
print"您的分数不及格!\n";
}

执行一次的语句块

使用大括号包围一段语句,这些语句就属于这个语句块,这个语句块其实是一个循环块结构,只不过它只循环一次。语句块也有自己的范围,例如可以将变量定义为局部变量。
{
    print "Enter a Num","\n";
    chomp(my $n = <STDIN>);
    $res = sqrt $n;
    print "$res","\n";
}
print $res,"\n";


进阶技巧:&&,||及?:作为控制结构

它们看上去像标点符号,或是表达式的一部分,但在Perl中可作为控制结构。
比如说:
if (判别表达式)
 {为真时语句块};
也可以写为:
 为真时的语句块 if (判别表达式)
但更简单的方式是:
 判别式 && 为真时的语句块
为什么呢?&&为逻辑与操作符,其含义为:
   若判别式为真,则表达式的值依赖于后面语句块的值。所以为真时的语句块被执行(用来求值)。
   若判别式为假,则整个表达式为假,不用考虑后面语句块的值。所以为假时的语句块不被执行。

同样道理,unless(this){that}可替换为this||that。

三目运算符?:


perl也支持三目运算符:如果expression返回真,则整个表达式返回if_true,否则返回if_false:
expression ? if_true : if_false

?:表达式举例:exp1?exp2:exp3表示:如果exp1为真则求exp2的值,否则求exp3的值:
(expression)?(statement if true):(statement if false)

通过用户输入类似布尔类型来决定前缀或后缀:
my $word="free";
my $fixps="oa";
print 'Enter a number-like for bool test:';
my $before=int(<STDIN>); #no warnings in case when enter no numeric text
($before ? substr($word,0,0) : substr($word,length($word),0))=$fixps;
say $word;


控制结构的修饰

《Perl入门经典.Beginning.Perl.2013》的5.4.1章节:
常用的语句修饰符有如下形式:
STATEMENT if EXPRESSION;
STATEMENT unless EXPRESSION;
STATEMENT while EXPRESSION;
STATEMENT until EXPRESSION;
STATEMENT for LIST;
STATEMENT foreach LIST;

不同于之前所见到的关键字的代码块形式,此时EXPRESSION或LIST外面的圆括号是可有可无的,如:
print "we have a valid user: $user\n" if $user;

在for、foreach循环中,$_为变量的别名。下面的代码将连续输出数字1~5。
my array = ( 1 .. 5 );
print "$_ln" foreach @array;

while和until循环与此类似,在语句执行前计算EXPRESSION的值;下面的代码将输出数字9~0,而不是10~1。
my $countdown = 10;
print "$countdown\n" while $countdown--;

STATEMENT可能是复合语句。perldoc perlsyn中有一个示例:
go_outside () and play() unless $is_raining;

上述代码的可读性很强,但有一处不易察觉的陷阱。那就是如果go_outside()函数返回假,就不会调用play()子程序。将语句中的and替换为逗号可以避免这一问题:
go_outside(), play() unless $is_raining;

请谨慎使用语句修饰符。建议在重点强调相应语句时使用它们,而不仅仅作为修饰符使用。

需要注意:

STATEMENT XXX EXPRESSION;

XXX in (if,unless,while,until)

STATEMENT 中不能写复杂的表达式,即用{}包围起来的语句块,会报语法错误。