LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1607|回复: 0

Perl 操作符和优先级

[复制链接]
发表于 2003-12-9 23:19:23 | 显示全部楼层 |阅读模式
*  左 ->
    * 不定 ++ --
    * 右 **
    * 右 ! ~ \ 和 一元操作符 + 及 -
    * 右 =~ !~
    * 左 * / % x
    * 左 + - .
    * 左 <<>>
    * 不定 named 一元操作符
    * 不定 <> <=>= lt gt le ge
    * 不定 == != <=> eq ne cmp
    * 左 &
    * 左 | ^
    * 左 &&
    * 左 ||
    * 不定 ..
    * 右 ?:
    * 右 = += -= *= etc.
    * 左 , =>
    * 不定 列表操作符 (靠右)
    * 左 not
    * 左 and
    * 左 or xor

下面按优先级的顺序解释每一个操作符.

描述

词语和列表操作符(靠左)
词语在 Perl 里有着最高的优先级别. 词语包括变量, 引号或类似引号的操作符, 任何括号里的表达式, 用括号括起参数的函数. 实际上, 这不是函数, 而是一些列表操作符和一元操作符, 当用括号括起它们的参数时, 它们就象是函数一样. 这些都在记录在文档 perlfunc 中.

如果任何列表操作符 (比如 print() ) 或任何一元操作符 (比如 chdir() ) 后面跟了一个左括号, 该操作符和它所有在括号中参数就有最高的优先级, 就象普通的函数调用一样.

如果没有括号对, 象 print , sort , 或 chmod 这些列表操作符的优先级别要么很高, 要么很低, 取决于看向操作符的左边还是右边. 例如:

@ary = (1, 3, sort 4, 2); print @ary; # prints 1324

sort 右边的逗号在 sort 被计算前被计算, 而左边的逗号则在之后计算. 换句话说, 列表操作符总是要把其后的所有参数组合起来, 相对它前面的表达式整体作为一个词语. 要注意括号的使用:

# 在这些计算被执行之前程序就会退出: print($foo, exit); # 这明显不是想要的结果 print $foo, exit; # 这样也不行 # 这样可以在退出前打印: (print $foo), exit; # 这是对的 print($foo), exit; # 这也对 print ($foo), exit; # 甚至这也对

也请注意

print ($foo &amp;amp; 255) + 1, &amp;quot;\n&amp;quot;;

可能不会产生和一眼看上去应该有的运行结果. 参看 Named Unary Operators 查找更多有关的信息.

结构 do {} 和 eval {} , 也被当作词语处理, 情况和调用子过程及方法一样, 匿名结构 [] 和 {} 也一样.

参看 Quote and Quotelike Operators 和 I/O Operators .

箭头操作符
和在 C/C++ 里一样, ``->'' 操作符取消引用. 如果它的右边是 [...] 或 {...} 下标, 它的左边必须是对数组或哈希表的直接或符号化引用(如果不是一个左值(可被赋值), 要是一个存放直接引用的单元). 参看 perlref .

否则, 右边就是一个方法的名字或是一个存放方法名字的简单数值变量, 而左边必须是一个个对象(一个 blessed reference)或是一个类名(一个包名). 参看 perlobj .

自动增量减量
``++'' 和 ``--'' 和 C 里面的作用是一样的, 如果出现在变量之前, 在返回变量的值前进行增量或减量操作, 如果出现在变量之后, 操作在返回变量的值后进行.

自动增量操作符还有一个小小的特别功能. 如果对一个数字变量进行增量操作, 或者只要在数字上下文里使用, 增量的结果没有什么特别. 但如果对一个字符串变量增量, 或者是在字符串上下文里使用增量操作, 对象是满足模式 /^[a-zA-Z]*[0-9]*$/, 那么增量操作是针对整个字符串, 结果保持在模式范围内, 操作是带进位的:

print ++($foo = '99'); # prints '100' print ++($foo = 'a0'); # prints 'a1' print ++($foo = 'Az'); # prints 'Ba' print ++($foo = 'zz'); # prints 'aaa'

自动减量操作没有这个特性.


二元 ``**'' 是幂操作符. 优先级比一元减操作符高, 所以 -2**4 等于 -(2**4), 不是 (-2)**4. (该操作符号是用 C 的 pow(3) 函数实现的, 该函数是对 double 类型操作)

符号一元操作符
一元 ``!'' 代表逻辑非, 即 ``not''. 参看 not , 这是个优先级稍低的版本.

一元 ``-'' 对数字操作数是算术的负号. 作用于字符串时, 如果字符串是标识符, 返回负号后跟标识符组成的字符串. 否则返回以负号开头的字符串. 这些规则的意思是 -bareword 就等于 ``-bareword'' .

一元 ``~'' 代表按位取反, 即 1 的补码.

一元 ``+'' 不起任何作用, 不管是对数字或字符串. 它的用处是在语法上把函数名和后面带括号的表达式隔开, 避免后者被当做参数处理. (参看 List Operators 中的例子)

一元 ``\'' 代表引用它后面的东西. 参看 perlref . 这个含义和字符串里的反斜杠的含义不同, 虽然两者都有避免后随被解释的作用.

捆绑操作符
二元 ``=~'' 把表达式捆绑到模式匹配上. 有些操作默认是搜索或修改变量 $_ . 这个操作符能对其他字符串进行同样的操作. 右边的参数是一个搜索模式, 替换, 或转换. 左边的参数代替 $_ 进行搜索, 替换, 转换. 返回值表示了操作是否成功. (如果右边的参数是表达式而非搜索模式, 替换或者转换, 在运行时刻会被解释作搜索模式. 这样做在效率上要比显式的使用搜索模式低, 因为每次进行表达式求值时模式会被重新编译, 除非使用了 /o.)

二元 ``!~'' 和 ``=~'' 的用法一样, 但返回值是逻辑上相反的.

乘法操作符
二元 ``*'' 把两个数字相乘.

二元 ``/'' 把两个数字相除.

二元 ``%'' 把两个数字求模.

二元 ``x'' 是重复操作符. 在数值上下文里, 返回一个字符串, 由左边的操作数重复右边操作数指定的次数组成. 在列表上下文里, 如果左边的操作数是括号括住的列表, 就重复这个列表.

print '-' x 80; # 打印一行虚线 print &amp;quot;\t&amp;quot; x ($tab/8), ' ' x ($tab%8); # tab over @ones = (1) x 80; # 包含80个 1 的列表 @ones = (5) x @ones; # 把所有元素设为 5

加法操作符
二元 ``+'' 把两个数字相加.

二元 ``-'' 把两个数字相减.

二元 ``.'' 连接两个字符串.

移位操作符
二元 ``<<'' 把左边的参数向左移位右边参数指定的次数. 参数必须是整数.

二元 ``>>'' 把左边的参数向右移位右边参数指定的次数. 参数必须是整数.

命名一元操作符
命名的一元操作符带上可选的括号被当作单参数的函数. 如文件测试操作符 -f, -M, 等等. 参看 perlfunc .

如果任何列表操作符 ( print() , 等等.) 或者任何一元操作符 ( chdir() , 等等.) 后跟有左括号, 该操作符和括号里的参数一起具有最高的优先级, 就象普通的函数调用一样. 例如:

chdir $foo || die; # (chdir $foo) || die chdir($foo) || die; # (chdir $foo) || die chdir ($foo) || die; # (chdir $foo) || die chdir +($foo) || die; # (chdir $foo) || die

但是, * 的优先级比 || 高:

chdir $foo * 20; # chdir ($foo * 20) chdir($foo) * 20; # (chdir $foo) * 20 chdir ($foo) * 20; # (chdir $foo) * 20 chdir +($foo) * 20; # chdir ($foo * 20) rand 10 * 20; # rand (10 * 20) rand(10) * 20; # (rand 10) * 20 rand (10) * 20; # (rand 10) * 20 rand +(10) * 20; # rand (10 * 20)

参看``List Operators''.

关系操作符
二元 ``<'' 返回真, 如果左边的参数在数字上小于右边的参数.

二元 ``>'' 返回真, 如果左边的参数在数字上大于右边的参数.

二元 ``<='' 返回真, 如果左边的参数在数字上小于或等于右边的参数.

二元 ``>='' 返回真, 如果左边的参数在数字上大于或等于右边的参数.

二元 ``lt'' 返回真, 如果左边的参数在字符顺序上小于右边的参数.

二元 ``gt'' 返回真, 如果左边的参数在字符顺序上大于右边的参数.

二元 ``le'' 返回真, 如果左边的参数在字符顺序上小于或等于右边的参数.

二元 ``ge'' 返回真, 如果左边的参数在字符顺序上大于或等于右边的参数.

相等操作符
二元 ``=='' 返回真, 如果左边的参数在数字上等于右边的参数.

二元 ``!='' 返回真, 如果左边的参数在数字上不等于右边的参数.

二元 ``<=>'' 分别返回 -1, 0, 或 1, 取决于左边的参数在数字上是小于, 等于, 或大于右边的参数.

二元 ``eq'' 返回真, 如果左边的参数在字符顺序上等于右边的参数.

二元 ``ne'' 返回真, 如果左边的参数在字符顺序上不等于右边的参数.

二元 ``cmp'' 分别返回 -1, 0, 或 1, 取决于左边的参数在字符顺序上是小于, 等于, 或大于右边的参数.

按位 与
二元 ``&'' 返回两个操作数按位进行 与 操作的结果

按位 或 和 异或
二元 ``|'' 返回两个操作数按位进行 或 操作的结果

二元 ``^'' 返回两个操作数按位进行 异或 操作的结果

C 风格的 逻辑与
二元 ``&&'' 进行快速的逻辑与操作. 即如果左边操作数是假, 右边的操作数不会被求值. 当右边的操作数被求值, 数值或列表上下文会被传递过去.

C 风格的 逻辑或
二元 ``&&'' 进行快速的逻辑或操作. 即如果左边操作数是真, 右边的操作数不会被求值. 当右边的操作数被求值, 数值或列表上下文会被传递过去.

|| 和 && 与 C 的不同之处是返回值不一定是 0 或 1, 而是最后的计算结果. 因此, 能正确找出 home 目录(不会是 ``0'')的方法应该是:

$home = $ENV{'HOME'} || $ENV{'LOGDIR'} || (getpwuid($&lt;))[7] || die "You're homeless!\n";

为了增加程序的可读性, Perl 提供了 ``and'' 和 ``or'' 操作符(见下). 快速操作的特点是一样的. 但 ``and'' 和 ``or'' 的优先级要低很多, 所以在不用括号也可以安全地用在列表操作符后:

unlink &amp;quot;alpha&amp;quot;, &amp;quot;beta&amp;quot;, &amp;quot;gamma&amp;quot; or gripe(), next LINE;

用 C 风格操作符就要写成这样:

unlink(&amp;quot;alpha&amp;quot;, &amp;quot;beta&amp;quot;, &amp;quot;gamma&amp;quot;) || (gripe(), next LINE);

范围操作符
二元 ``..'' 是范围操作符, 在不同的上下文中有不同的含义. 在列表上下文中, 返回一个数组, 值的大小是从左边的操作数的右边的操作数(按一递增). 这可以用于编写 for (1..10) 循环, 或者是对数组做分片操作. 由于当前的实现方式中使用了临时数组, 所以下面的代码会浪费很多内存:

for (1 .. 1_000_000) { # code }

在数值上下文里, ``..'' 返回一个布尔值. 操作符是对位的, 象开关一样, 功能类似 sed, awk 等其它编辑器里的行范围(逗号) 操作符. 每个 ``..'' 操作符会维护自己的布尔值状态. 如果左边的操作数是假, 状态为假. 如果左操作数为真, 状态就是真, 直到右边的操作数也为真, 状态变回假. (在范围操作符被再次计算时, 状态才变回假. 它可以测试右操作数并在变成真值的计算过程中变成假值(象在 awk 里一样), 但还是会变到真值一次. 如果不想等到下一次计算才测试右操作数(象在 sed 里一样), 可以用三点 (``...'') 代替两点.) 当操作符处于 ``假'' 状态时, 右操作数不会被计算, 而当状态为 ``真'' 时, 左操作数不会被计算. 操作符的优先级稍低于 || 和 &&. 返回值是空字符串代表假值, 或是一串数字(从 1 开始)代表真值. 当范围到达时这串数字被复位。 范围里最后一个数字有追加的字符串 ``E0'', 但不影响它的数字值, 用来提供到达尾部的信息. 如果要忽略开始点, 可以等待大于 1 的数字. 如果 ``..'' 的左右操作数都不是数字, 操作数隐含地和当前行号变量 $. 进行比较. 例子:

作为数值操作符:

if (101 .. 200) { print; } # 打印第二个一百行 next line if (1 .. /^$/); # 跳过开头的行 s/^/&amp;gt; / if (/^$/ .. eof()); # 引起全体文字

作为列表操作符:

for (101 .. 200) { print; } # 打印 $_ 一百次 @foo = @foo[$[ .. $#foo]; # 耗费资源的空循环 @foo = @foo[$#foo-4 .. $#foo]; # 切出最后 5 个元素

如果操作数是字符串, 范围操作符(在列表上下文里)使用特别的增量算法. 例如用

@alphabet = ('A' .. 'Z');

表示所有英文字母, 或者

$hexdigit = (0 .. 9, 'a' .. 'f')[$num &amp;amp; 15];

表示所有16进制数字, 或者

@z2 = ('01' .. '31'); print $z2[$mday];

打印两位格式的日期. 如果最后指定的值不在算法能产生的范围内, 那么一直计算到下一个值的长度比最后的值大为止.

条件操作符
三元 ``?:'' 是条件操作符, 和 C 里的一样. 它的意思很象一个 if-then-else. 如果 ? 前面的参数为真, 返回 : 前面的参数, 否则返回 : 后面的参数. 例如:

printf &amp;quot;I have %d dog%s.\n&amp;quot;, $n, ($n == 1) ? '' : &amp;quot;s&amp;quot;;

数值上下文或列表上下文会被传送给选中的参数.

$a = $ok ? $b : $c; # 得到数值 @a = $ok ? @b : @c; # 得到数组 $a = $ok ? @b : @c; # 这不对了

如果第2,3参数都是合法的左值, 操作符可以被赋值:

($a_or_b ? $a : $b) = $c;

但这样写的程序读起来不太容易.

赋值操作符
``='' 是普通的赋值操作符.

赋值符和 C 里的作用一样. 即

$a += 2;

等同于

$a = $a + 2;

但不象 tie() 那样会带来反引用左值的副作用. 其他赋值操作符的使用是类似的:

    **=    +=    *=    &=    <<=    &&=
           -=    /=    |=    >>=    ||=
           .=    %=    ^=
                 x=


要注意这些操作符的优先级比等号高.

和 C 不同, 赋值操作符产生一个有效的左值. 对赋值进行修改等于先赋值, 再修改用于赋值的变量. 如: ($tmp = $global) =~ tr [A-Z] [a-z];

还有

($a += 2) *= 3;

等同于

$a += 2; $a *= 3;
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表