【问题标题】:Perl: precedence (Leftward list operator)Perl:优先级(左列表运算符)
【发布时间】:2011-02-17 17:47:56
【问题描述】:

来自 Programming Perl pg 90,他说:

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

排序右边的逗号在排序之前计算,但左边的逗号在排序之后计算。 ...列表运算符倾向于吞噬..然后像一个简单的术语一样行事”

  1. 分配结果是否会导致排序被处理,或者当@ary被打印扩展时是否会发生这种情况?
  2. 他所说的所有“逗号”是什么意思?我的理解是,在赋值语句中,逗号的优先级低于列表运算符,因此排序首先运行并吞噬它的参数(4 and 2).. 到底是如何评估逗号的?因此,该语句然后变成 (1, 3, 2, 4) 一个分配的列表.. 逗号只是充当列表分隔符而不是运算符!事实上,在 pg:108 中,他说:不要将逗号的标量上下文使用与列表上下文使用混淆..
  3. 什么是左右列表运算符? print @ary 是右列表运算符??所以它的优先级很低?

    打印($foo,退出);

这里,如何评估优先级? print 是一个列表运算符,看起来像一个函数,所以它应该首先运行!它有两个参数 $fooexit.. 那么为什么 exit 不被视为字符串呢?毕竟优先级打印(列表运算符)具有更高的优先级??

print $foo, exit;

在这里,您有 print 和 , 运算符,但列表运算符具有更高的优先级.. 所以.. exit 应该被视为字符串 - 为什么不呢??

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

这里因为它是一个列表运算符,所以它打印$foo & 255 上面提到的exit 东西不应该发生类似的事情..

【问题讨论】:

  • 为什么不像我们凡人那样只用括号?

标签: perl


【解决方案1】:

如果对 Perl 如何解析结构有疑问,您可以通过 B::Deparse 模块运行代码,该模块将从编译后的内部表示生成 Perl 源代码。对于您的第一个示例:

$ perl -MO=Deparse,-p -e '@ary = (1, 3, sort 4, 2); print @ary;'
(@ary = (1, 3, sort(4, 2)));
print(@ary);
-e syntax OK

如您所见,sort 将两个参数置于其右侧。

就执行顺序而言,您可以通过B::Concise 模块找到它(我已经添加了 cmets):

$ perl -MO=Concise,-exec -e '@ary = (1, 3, sort 4, 2); print @ary;'
1  <0> enter 
2  <;> nextstate(main 1 -e:1) v:{
3  <0> pushmark s       # start of list
4  <$> const[IV 1] s    # 1 is added to list
5  <$> const[IV 3] s    # 3 is added to list
6  <0> pushmark s       # start of sort's argument list
7  <$> const[IV 4] s    # 4 is added to sort's argument list
8  <$> const[IV 2] s    # 2 is added to sort's argument list
9  <@> sort lK          # sort is run, and returns its list into the outer list
a  <0> pushmark s
b  <#> gv[*ary] s
c  <1> rv2av[t2] lKRM*/1
d  <2> aassign[t3] vKS/COMMON  # the list is assigned to the array
e  <;> nextstate(main 1 -e:1) v:{
f  <0> pushmark s         # start of print's argument list
g  <#> gv[*ary] s         # the array is loaded into print's argument list
h  <1> rv2av[t5] lK/1
i  <@> print vK           # print outputs it's argument list
j  <@> leave[1 ref] vKP/REFC
-e syntax OK

第二个例子:

$ perl -MO=Deparse,-p -e 'print $foo, exit;'
print($foo, exit);
-e syntax OK

$ perl -MO=Concise,-exec -e 'print $foo, exit;'
1  <0> enter 
2  <;> nextstate(main 1 -e:1) v:{
3  <0> pushmark s
4  <#> gvsv[*foo] s   # add $foo to the argument list
5  <0> exit s         # call `exit` and add its return value to the list
6  <@> print vK       # print the list, but we never get here
7  <@> leave[1 ref] vKP/REFC
-e syntax OK

如您所见,exit 内置函数在尝试为print 组装参数列表时运行。由于exit 导致程序退出,print 命令永远无法运行。

最后一个:

$ perl -MO=Deparse,-p -e 'print ($foo & 255) + 1, "\n";'
((print(($foo & 255)) + 1), '???');  # '???' means this was optimized away
-e syntax OK

$ perl -MO=Concise,-exec -e 'print ($foo & 255) + 1, "\n";'
1  <0> enter 
2  <;> nextstate(main 1 -e:1) v:{
3  <0> pushmark v
4  <0> pushmark s
5  <#> gvsv[*foo] s
6  <$> const[IV 255] s
7  <2> bit_and[t2] sK
8  <@> print sK
9  <$> const[IV 1] s
a  <2> add[t3] vK/2
b  <@> list vK
c  <@> leave[1 ref] vKP/REFC
-e syntax OK

【讨论】:

  • 嗨,谢谢!我发现这两个答案都非常有帮助!并且有用!但它们并不是我想要的。为了完整起见,我已经以自己的方式回答了它,但我会选择 Eric 的回答,因为我不知道那个模块。
【解决方案2】:
  1. sort 在被调用时被评估,它实际上与分配没有任何关系。 sort 返回一个列表。所以你分配的是:

    @ary = (1, 3, (2,4) );

Perl 会忽略第二个括号,因此您最终会得到1,3,2,4,正如您所期望的那样。

  1. 您所指的逗号不再存在。这是要排序的第二个参数。 Perl 将您的列表视为 3 项列表而不是 4 项列表(它在作业中将其扩展为 4)

  2. 向右处理参数(例如打印出来或存储它们),向左处理参数,通常以某种方式修改它们。

print 的行为与 Perl(或我曾经使用过的任何其他语言)中的任何其他函数一样。如果您将函数作为参数调用,则该函数的返回值将作为参数给出。所以你的情况:

print ($foo, exit);

或等效(括号无关紧要)

print $foo, exit;

什么都不做,因为您要求它打印 exit 的返回值。您的程序首先退出,因此您什么也得不到。我不明白您为什么希望 exit 被视为字符串。 exit 在所有上下文中都是一个函数,除非你引用它。

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

来自perlop,它给出了这个例子:

乍一看可能并没有达到您的预期。括号 附上被评估的“打印”的参数列表(打印 “$foo & 255”的结果)。然后将返回值加一 “打印”(通常为 1)。结果是这样的:

1 + 1, "\n";    # Obviously not what you meant.

要正确地做你的意思,你必须写:

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

【讨论】:

  • exit 在许多常见的上下文中可以是有效的裸词:例如,$foo{exit} = ...。但是 Perl 总是将一个裸词参数传递给 print 并尝试将其解析为一个函数。
  • @mob:不是函数;到文件句柄。 perl -Mstrict -le 'print xyzzy'
【解决方案3】:

不确定下面的内容是否完全准确(这是来自 IRC、上述答案、谷歌和我对这本书的解释的混搭)

  1. (operator)(operands) 这被视为向左运算符,因为它位于操作数的左侧。 (operands)(operator) 这被视为向右运算符,因为它位于操作数的右侧。所以, (1, 2, 3, sort 4, 5, sort 6, 7) 这里的第二个排序,既是左字又是右字运算符!排序 6,7 是左字,如 (6,7) 的左侧 - 它是操作数。它也在 sort(4, 5 的右边,所以在这里它是向右的并且优先级很低。

  2. 2.

@ary = (1, 3, 排序 4, 2); 打印@ary;

在这里,sort 是一个向左的列表运算符,所以它的优先级是最高的,正如 'Cfreak' 所说..

  1. 打印($foo,退出);打印 $foo,退出;

在这里,print 是向左列表,因此优先级最高,因此它应该首先执行,但是!执行它应该解决它的参数和裸词“退出”。为了解决它,我猜它会运行 exit, ergo.. Print $foo,... 会吞噬它的所有参数,然后它必须处理它们并在裸词处运行它..

  1. print ($foo & 255) 同上。 print 获得最高优先级,但它现在需要解决其各种参数.. 所以 $foo & 255 等正如“Cfreak”所解释的那样。

非常感谢各位!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2011-10-19
    • 2011-06-21
    • 2013-02-24
    • 2012-08-10
    相关资源
    最近更新 更多