在Perl中的标量上下文和列表上下文

3

我在一本O'Reilly的书中发现了一个有点奇怪的例子:

@backwards = reverse qw/ yabba dabba doo /;
print "list context: @backwards\n";
$backward = reverse qw/ yabba dabba doo /;
print "scalar1 context: $backward\n";
$notbackward = qw/ yabba dabba doo /;
print "scalar2 context: $notbackward\n";
print "print context: ",reverse qw/ yabba dabba doo /;
print "\n";

输出结果为:
list context: doo dabba yabba
scalar1 context: oodabbadabbay
scalar2 context: doo
print context: doodabbayabba

我不理解的是标量上下文:scalar1

书中说'reverse something'给出列表上下文,所以我猜qw/ yabba dabba doo /被视为一个列表,reverse qw/ yabba dabba doo /为('doo', 'dabba', 'yabba')。

然后就有了$backward = something,这意味着something是一个标量,所以我期望结果是'doo dabba yabba',但实际结果却不同:'oodabbadabbay'。

我认为原因是不能直接将列表设置为标量。所以我进行了scalar2测试:只打印列表中最后一项。为什么?为什么在scalar1测试中没有这样做?

标量测试输出是如何工作的?

4个回答

10

首先,qw/yabba dabba doo/ 只是 ('yabba', 'dabba', 'doo') 的语法糖。它们的意思相同。

reverse 函数接受一个列表。在列表上下文中,它将反转该列表。在标量上下文中,它会执行 join('', @list) 然后反转该字符串中的字符并返回。

请记住

$backward = reverse qw/ yabba dabba doo /;
$notbackward = qw/ yabba dabba doo /;

意思是

$backward = reverse ('yabba', 'dabba', 'doo');
$notbackward = ('yabba', 'dabba', 'doo');
reverse 函数提供了列表上下文,$notbackward = 给我们标量上下文。这意味着逗号运算符在第一行处于列表上下文,在第二行处于标量上下文。在列表上下文中,逗号运算符创建一个列表。在标量上下文中,它评估两个操作数并返回右边的操作数。这意味着在标量上下文中 ('yabba', 'dabba', 'doo') 的值为 'doo',并且这就是分配给 $notbackward 的值。

7
所有的Perl函数,包括你定义的任何sub都可以检测它们是在“标量”还是“列表”上下文中被调用,并且有许多函数会根据这个上下文改变它们的行为。 除了“做我想要的”,很少有其他约定来确定一个函数何时以及如何处理这两种不同的上下文(这个PerlMonks上的整个主题对这些问题有很好的讨论),因此您需要依靠每个函数的文档来猜测函数在特定上下文中会执行什么操作。
具体针对您提供的四个示例:
1. @backwards = reverse qw/ yabba dabba doo /
2. $backward = reverse qw/ yabba dabba doo /
3. $notbackward = qw/ yabba dabba doo /;
4. print ..., reverse qw/ yabba dabba doo /;

这些行为是:

1. reverse function, list context:     returns list of the elements in reverse order

2. reverse function, scalar context:   concatenate argument list to a string,
                                       return reverse of that string

3. list assignment to scalar:          returns last element in list (*)

4. also reverse function, list context    same as #1

(*) - 注意,将列表分配给标量与将数组分配给标量是不同的 -- 这是列表和数组之间最重要的区别之一:

@a = ("x", "y", "z");  $n = @a;   # array assignment,  $n is array size, or "3"
$n = ("x", "y", "z");             # list assignment,   $n is last element, or "z"

3

对于以下这行代码:

$backward = reverse qw/ yabba dabba doo /;

您在这里从reverse请求一个标量。reverse的perldoc说:

在标量上下文中,连接LIST的元素并返回一个字符串值,该字符串值中所有字符的顺序相反。

因此,它返回每个字母的反转。

对于$notbackward = qw / yabba dabba doo /; qw//的perldoc说:

Evaluates to a list of the words extracted out of STRING, using embedded whitespace as the word delimiters. It can be understood as being roughly equivalent to:

               split(’ ’, q/STRING/);

the differences being that it generates a real list at compile time, and in scalar context it returns the last element in the list.

因此,仅请求标量将返回列表中的最后一项。

0
为了简化其他答案,reverse 实际上执行两个不同的操作,列表反转和字符串反转。
这已经被证明非常令人困惑,因此 perl6 将它们拆分成不同命名的函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接