Perl中标量上下文和列表上下文有什么区别?

5
Perl中标量上下文和列表上下文有什么区别?其他语言如Java或Javascript是否存在类似情况?
3个回答

11

Perl 中的各种操作符都受上下文影响,在列表和标量上下文中会产生不同的结果。

例如:

my(@array) = (1, 2, 4, 8, 16);
my($first) = @array;
my(@copy1) = @array;
my @copy2  = @array;
my $count  = @array;

print "array: @array\n";
print "first: $first\n";
print "copy1: @copy1\n";
print "copy2: @copy2\n";
print "count: $count\n";

输出:

array: 1 2 4 8 16
first: 1
copy1: 1 2 4 8 16
copy2: 1 2 4 8 16
count: 5

现在:

  • $first 包含 1(数组的第一个元素),因为 my($first) 中的括号提供了一个数组上下文,但是在 $first 中只有一个值的空间。
  • @copy1@copy2 都包含 @array 的副本,
  • 而且 $count 包含 5,因为它是一个标量上下文,并且在标量上下文中,@array 求值为数组中元素的数量。

也可以构建更复杂的示例(结果留给读者练习):

my($item1, $item2, @rest) = @array;
my(@copy3, @copy4) = @array, @array;

据我所知,其他语言中没有直接对应于列表和标量上下文的概念。


谢谢。我喜欢你的例子,只有一个小问题:如果您使用除1、2、3之外的值填充数组,则$copy2的值将是其他数字而不是3,并且它不会与数组本身的大小混淆。一开始我有点困惑,但是你解释得很清楚。没问题。 - user47145
我认为如果你将 $count 更改为 $copy1,@copy1 更改为 @copy2,$copy2 更改为 $count,那么变量名称将与其内容匹配,这样会更清晰明了。 - Mr. Muskrat
变量命名有很大的改进空间。我会重新命名:$count -> $first; $copy1 -> $acopy; $copy2 -> $count。 - Jonathan Leffler

4

当你寻找单个值时,标量上下文是你得到的结果。当你寻找多个值时,列表上下文是你得到的结果。在处理数组时,最常见的区别就是这个:

@x = @array;  # copy an array
$x = @array;  # get the number of elements in an array

其他运算符和函数也是上下文相关的:

$x   = 'abc' =~ /(\w+)/;  # $x = 1
($x) = 'abc' =~ /(\w+)/;  # $x = 'abc'
@x   = localtime();       # (seconds, minutes, hours...)
$x   = localtime();       # 'Thu Dec 18 10:02:17 2008'

在给定的上下文中,操作符(或函数)的行为取决于操作符本身。没有通用规则来确定事物的行为方式。
您可以使用wantarray函数来确定调用上下文,从而使您自己的子例程具有上下文敏感性。您可以使用scalar关键字强制将表达式在标量上下文中求值。
除了标量和列表上下文外,文档中还提到了“空”(不需要返回值)和“布尔”(期望一个真/假值)上下文。

我喜欢你的“其他运算符”示例,特别是在标量和列表上下文中=~运算符的显着行为。我从未猜到过那种行为。 - user47145
是的,在标量上下文中,=~ 告诉你是否匹配了某些内容。在列表上下文中,它返回一个包含捕获文本的列表。 - Michael Carman

0

这意味着数据类型将根据操作的模式进行评估。例如,对标量的赋值意味着右侧将作为标量进行评估。

我认为理解上下文的最佳方法是学习 wantarray。因此,想象一下 = 是实现 wantarray 的子例程:

sub = {
  return if ( ! defined wantarray ); # void: just return (doesn't make sense for =)
  return @_ if ( wantarray ); # list: return the array
  return $#_ + 1; # scalar: return the count of the @_
}

这篇文章 中的示例就好像通过将右侧作为参数来调用上述子程序一样工作。

至于其他语言中的并行,是的,我仍然认为几乎每种语言都支持类似的东西。 多态在所有面向对象的语言中都很相似。 另一个例子,Java会在某些情况下将对象转换为字符串。 而我使用过的每种无类型脚本语言都有类似的概念。


问题涉及标量/列表上下文,而不是标量/数组变量。据我所知,这个概念是Perl独有的。 - Michael Carman
是的,我误解了问题。已经编辑过了。 - nicerobot
更好。如果可以的话,我会取消投反对票,但是SO告诉我它“太旧了”。 - Michael Carman

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