Perl 操作符和优先级 |
|---|
| 作者:devel 2005-01-28 11:13:31 来自:Linux先生 |
|
* 左 -> * 不定 ++ -- * 右 ** * 右 ! ~ \ 和 一元操作符 + 及 - * 右 =~ !~ * 左 * / % 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; 255) + 1, &quot;\n&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 &quot;\t&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($<))[7] || die "You're homeless!\n"; 为了增加程序的可读性, Perl 提供了 ``and'' 和 ``or'' 操作符(见下). 快速操作的特点是一样的. 但 ``and'' 和 ``or'' 的优先级要低很多, 所以在不用括号也可以安全地用在列表操作符后: unlink &quot;alpha&quot;, &quot;beta&quot;, &quot;gamma&quot; or gripe(), next LINE; 用 C 风格操作符就要写成这样: unlink(&quot;alpha&quot;, &quot;beta&quot;, &quot;gamma&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/^/&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; 15]; 表示所有16进制数字, 或者 @z2 = ('01' .. '31'); print $z2[$mday]; 打印两位格式的日期. 如果最后指定的值不在算法能产生的范围内, 那么一直计算到下一个值的长度比最后的值大为止. 条件操作符 三元 ``?:'' 是条件操作符, 和 C 里的一样. 它的意思很象一个 if-then-else. 如果 ? 前面的参数为真, 返回 : 前面的参数, 否则返回 : 后面的参数. 例如: printf &quot;I have %d dog%s.\n&quot;, $n, ($n == 1) ? '' : &quot;s&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; (编辑:nuthead)
|