这是我用来学习的一些代码:
# right side gets scalar context,so commas return rightmost item $string = qw(stuff junk things); say $string; # things # right side gets list context,so middle is list assigned in scalar context $string = () = qw(stuff junk things); say $string; # 3 # right side gets list context,so creates a list,assigns an item to $string2,and # evaluates list in scalar context to assign to $string $string = ($string2) = qw(stuff junk things); say $string; # 3 say $string2; # stuff
我认为我已经足够了解所有的列表和标量语境工作.标量上下文中的逗号运算符返回右侧,所以第一个例子只是将逗号表达式中的最后一个项目(没有任何逗号)分配给$string.在其他示例中,将逗号表达式分配给列表将其放在列表上下文中,因此将创建列表,并在标量上下文中计算的列表返回其大小.
有两部分我不明白.
首先,列表应该是不可变的.这是Friedo反复强调的.我猜,从列表到列表的分配从一个列表中的项目分配到另一个列表中的项目,这就是为什么在第二个例子中,$string2获取’stuff’,为什么我们可以通过列表分配来解压缩@_.但是,我不明白作为空列表的()可能如何工作.根据我目前的理解,由于列表是不可变的,所以列表的大小将保持为0,然后在示例2和3中将大小分配给$stuff将给出值0.列表实际上是不可变的吗?
其次,我读了很多次,列表实际上并不存在于标量语境中.但是,goatse操作符的解释是它是标量上下文中的列表分配.这不是列表在标量语境中不存在的语句的反例吗?还是还有其他事情在这里?
更新:在理解答案后,我认为一对额外的括号有助于概念化它的工作原理:
$string = ( () = qw(stuff junk things) );
在括号内,=是对“聚合”的赋值,列表赋值运算符也不同于标量赋值运算符,不能与“列表上下文”混淆;列表和标量赋值可能发生在列表或标量上下文中). ()不会以任何方式改变. =在Perl中有一个返回值,列表分配的结果通过left =分配给$string.赋值给$string给出了RHS(括号中的所有内容)的标量上下文,并且在标量上下文中,列表赋值运算符的返回值是RHS中的项目数.
您可以将RHS列表分配置于列表上下文中:
($string) = ( () = qw(stuff junk things) );
根据perlop列表上下文中的列表分配返回分配的左值列表,这里为空,因为没有任何内容可以分配给in().所以这里$string将是undef.
解决方法
表达式qw(ab)的值在列表上下文中为(‘a’,’b’),在标量上下文中为’b’,但表达式(()= qw(ab))的值为列表中的()上下文和2在标量语境中. (@a = qw(a b))的值遵循相同的模式.这是因为pp_aassign,列表赋值运算符,选择以标量上下文返回计数:
else if (gimme == G_SCALAR) { dTARGET; SP = firstrelem; SETi(lastrelem - firstrelem + 1); }
(pp_hot.c行1257;行号可能会更改,但接近PP(pp_aassign)的结尾.)
那么,除了赋值运算符的值之外,还有赋值运算符的副作用.列表分配的副作用是将值从右侧复制到其左侧.如果右侧的值超出值,左边的剩余元素就会变为undef;如果左侧的值超出值,则右侧的剩余元素不会被复制.当给出()的LHS时,列表分配根本不会复制任何东西.但是,赋值本身的值仍然是RHS中的元素数量,如代码片段所示.