【问题标题】:Is there such a thing as a list in scalar context?在标量上下文中是否存在列表之类的东西?
【发布时间】:2012-01-04 04:47:38
【问题描述】:
my $mind = ( 'a', 'little', 'confused' );

这是因为perldoc perlfaq4 将上面的行解释如下(强调添加):

由于您要分配给标量,因此右侧是标量 语境。标量上下文中的逗号运算符(是的,它是一个运算符!) 评估其左侧,丢弃结果,并评估 它在右手边并返回结果。实际上,那 list-lookalike 分配给$scalar 它是最右边的值。很多人 搞砸了,因为他们选择了一个 list-lookalike,其最后一个元素 也是他们期望的计数:

my $scalar = ( 1, 2, 3 );  # $scalar gets 3, accidentally

我理解这意味着在标量上下文中没有列表这样的东西。

但是,ikegami 坚持认为它是"result[s] in a list operator, so it is a list literal."

那么,它是不是一个列表?

【问题讨论】:

  • 这不就是“天使在针头上跳舞”吗?如果程序员认为“$a=('foo','bar') 是在标量上下文中评估列表,它评估最右边的元素等”,后果是什么?这种错误的信念将如何再次困扰着他(除了与布赖恩·德·福伊(brian d foy)发生激烈的战争)?对于我能想到的所有其他关于 Perl 的常见“误解”,有一些简单的 sn-p 代码——经验证据——​​以一种或另一种方式证明一个观点。这个问题有这样的实验吗?甚至是查看内部结构或操作码?
  • @mob => 如果有人认为它是标量上下文中的列表,他们可能会认为将@a 定义为qw(a b c) 然后在标量上下文中的列表文字(11, 22, @a) 中, list 扩展它的参数,所以它变成(11, 22, 'a', 'b', 'c'),然后它返回最后一个参数c。这当然是错误的,它返回3,即标量上下文中的@a
  • 一个代码 sn-p 可以是:perl -E '@a = qw(a b c); sub list {@_[0..$#_]} $x = (11, @a); $y = list (11, @a); say "$x, $y"' 打印3, c
  • @ikegami => 请不要再这么迂腐了,这真的无助于谈话。在我的评论中,我清楚地解释了一个新手可能遇到的错误。在 perldata 中阅读此内容后可能会说:LISTs do automatic interpolation of sublists. That is, when a LIST is evaluated, each element of the list is evaluated in list context, and the resulting list value is interpolated into LIST just as if each individual element were a member of LIST. Thus arrays and hashes lose their identity in a LIST...
  • @ikegami => 当然是错的,这就是重点。如果有人不理解上下文是如何传播的,并在 perldata 中读取它怎么办?然后他们可能会得出我对 mob 的回答中所表达的结论,他要求举例说明误解。在撰写本文时,似乎至少有其他 4 人理解这一点。我猜你不是其中之一? This is of course wrong 和以下代码示例对您来说是否不够清楚? (讽刺的是,我并没有忘记讨论您似乎如何错过了此评论链中的上下文传播……)

标签: perl list scalar-context


【解决方案1】:

列表文字实际上是用代码写出的列表,因此(1, 2, 3) 是列表文字,而caller 例如是一个可以根据上下文返回列表或标量的函数。

在一行中:

my $x = ...;

... 看到标量上下文,因此如果 ... 是一个列表文字,那么您将在标量上下文中拥有一个列表文字:

my $x = (1, 2, 3);

但是列表文字不会产生列表,因为它包含的逗号运算符会看到标量上下文,这会导致它返回列表文字的最后一项,并在评估它们后丢弃剩余的值。

就函数而言,函数本身会看到调用它的任何上下文,然后将其传播到该函数中返回的任何行。因此,您可以在标量、列表或 void 上下文中使用函数,并且如果该子项的最后一行恰好是列表文字,则该列表文字将看到任何这些上下文并会正常运行。

所以基本上这是一个术语区别,list literal 指的是实际源代码中以逗号分隔的值列表*,list 指的是放置在 perl 堆栈中的一系列值。

您可以编写带有返回值的子例程,这些子程序的行为类似于数组或就上下文而言类似于列表文字。

sub returns_like_array  {my @x = 1..5; return @x}

sub returns_like_list   {my @x = 1..5; return @x[0 .. $#x]}

*或导致逗号分隔值列表的内容,例如 qw() 或粗逗号 => 或哈希或数组切片。

您也可以在这里查看我的答案:How do I get the first item from a function that returns an array in Perl?,其中详细介绍了列表。

【讨论】:

  • 我在接受您的回答和 ikegami 的回答之间左右为难。两者都让我对这一点有了更好的理解。谢谢!
【解决方案2】:

我同意你和perlfaq4。引用perldata,这可能是关于这一点的权威文档:

在不需要列表值的上下文中,看似列表文字的值只是最终元素的值,就像 C 逗号运算符一样。

(强调我的)。

也就是说,ikegami 有权使用他想要的任何术语。不同的人用不同的术语思考不同的语言结构,只要最终结果相同,我认为他们的术语与文档中的术语不同并不重要。 (不过,在公共论坛上坚持使用特殊术语并不是一个好主意!)

【讨论】:

  • 列表运算符和逗号运算符是同一个运算符的两个名字,所以perlfaq4其实并不真实。
  • 我不使用那个术语,但它非常常用,并且是 Perl 使用的。 (见我的回答。)
  • 最后,是 Zaid 坚持使用特殊术语(“没有标量上下文中的列表”)。我只是指出他不应该使用什么(因为它令人困惑和/或错误),而不是他应该使用什么(所以我根本没有使用任何术语)。
【解决方案3】:

问 Perl!

>perl -MO=Concise,-exec -e"my $s = ($x, $y, $z);"
1  <0> enter
2  <;> nextstate(main 1 -e:1) v:{
3  <0> pushmark v
4  <#> gvsv[*x] s
5  <#> gvsv[*y] s
6  <#> gvsv[*z] s
7  <@> list sKP                      <--- list in (s)calar context.
8  <0> padsv[$s:1,2] sRM*/LVINTRO
9  <2> sassign vKS/2
a  <@> leave[1 ref] vKP/REFC

所以是的,可以在标量上下文中拥有一个列表。

不能返回标量上下文中的列表。 (嗯,可以从 XS 中获得,但程序会崩溃,可能会出现“Bizarre copy”错误。)


不可能是其他方式。如果存在不同的列表操作和逗号操作,则无法编译以下内容:

sub f { "a", "b", "c" }

这会导致列表操作还是逗号操作?实际上,没有这样的区别,所以是的,它导致了那个操作。

【讨论】:

  • +1 :我希望得到这种“布丁证明”的答案
【解决方案4】:

这不是一个列表。由于您要分配给标量,因此它是逗号运算符 - 评估左侧,评估右侧,返回右侧,并从左到右解析。 $scalar 将是 'confused' :)

【讨论】:

  • @Zaid:ikegami 说“正式地说,它是一个列表 Perl 表达式,根据上下文返回一个二元素列表或一个标量。”
  • 这意味着在标量上下文中存在列表之类的东西,这与您的答案相矛盾。
  • @Zaid:不,这并不意味着。
  • 也许我在这里遗漏了一些东西。需要解释一下吗?
  • “列表运算符”和“逗号运算符”是同一个运算符的两个名称。与您所说的相反,它不是二进制操作,即使在标量上下文中也不是。 (见我的回答。)
【解决方案5】:

这是一个术语和观点的问题。术语在这里很棘手,因为您可以在源代码中编写列表、返回值列表或在列表上下文中评估某些内容。“列表”一词在每种情况下的含义都略有不同!

从技术上讲,列表不能存在于标量上下文中,因为 perl(解释器)不会为以下内容创建值列表:

my $x = ('a', 'b', 'c');

pedantic 精确时,这被解释为标量上下文中逗号运算符的行为。同样,qw 被定义为返回标量上下文中的最后一个元素,因此这里也没有列表:

my $x = qw(a b c);

在这两种情况下(以及我们可以收集的任何其他运算符示例),我们所说的是解释器不会创建值列表。这是一个实现细节。 perl 不能创建一个值列表并丢弃除最后一个之外的所有值是没有理由的;它只是选择不这样做。

Perl 语言是抽象的。在源代码级别('a', 'b', 'c') 是一个列表。您可以在对其施加标量上下文的表达式中使用该列表,因此从这个角度来看,列表可以存在于标量上下文中。

最后,这是在 [Pp]erl 如何运作的心智模型之间做出选择。 “标量上下文中的列表返回其最后一个值”模型稍微不准确,但更容易理解。据我所知,没有任何功能不正确的极端情况。 “标量上下文中没有列表之类的东西”模型更准确但更难使用,因为您需要考虑标量上下文中每个运算符的行为。

【讨论】:

    【解决方案6】:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-10
    • 2013-09-21
    相关资源
    最近更新 更多