【问题标题】:Can the empty list be in scalar context?空列表可以在标量上下文中吗?
【发布时间】:2011-08-06 17:20:05
【问题描述】:

有一个谎言,标量上下文中的列表产生列表的最后一个元素。这是一个谎言,因为(俗话说)你不能在标量上下文中拥有一个列表。标量上下文中看起来像列表的东西实际上是标量上下文中的逗号运算符,它在标量上下文中具有不同的行为。

但是,这个逻辑似乎有一个漏洞:空列表(有时称为空列表)。字符()defined to be the null list by perldoc perlglossary。构造

my $s = ();

是有效代码并返回undef$s。这似乎没有在perldoc 中的任何地方记录(我没有检查过骆驼),但是很多代码都依赖它,所以我认为它会继续存在。

既然序言已经完成,那么问题来了:如果我们不能在标量上下文中拥有一个列表,那么我们在标量上下文中将什么称为空列表以及不将其称为列表的原因是什么(因为标量上下文中没有逗号)?

如果你喜欢这个问题,你可能也会喜欢discussion going on in P5P

【问题讨论】:

  • 有趣的问题。只是推测,所以我将其放在评论中:您示例中的括号是否真的是一个空列表,或者它们只是这样的括号:my $x = (4 * 3) + 1;?我问,因为当我跟踪 perlglossary 中的超链接(空列表 > 列表值 > 列表上下文)时,即使是空列表似乎也取决于列表上下文的存在。
  • @FMc 一个有效点。 my $s = () 中的括号可能不是一个空列表,而是一个无值表达式(为 null)。
  • 应该是报错吧?奇怪,是的,但是......看起来是一个足够明智的结果,而不是突然终止程序。
  • @pst 诀窍是在布尔上下文中大量使用空列表来表示假。 perldoc perlsyn 甚至说“数字 0、字符串 '0' 和 '' 、空列表 () 和 undef 在布尔上下文中都是错误的。”这是问题的症结所在。 perlsyn 说你可以在标量上下文中有一个空列表,但你不能在标量上下文中有一个列表(它们在 Perl 5 中不存在)。

标签: perl list scalar-context


【解决方案1】:

列表是一个非常通用的词。您可能指的是列表运算符或列表值。

代码中没有逗号,所以没有列表运算符。

代码中没有列表上下文,所以没有列表值。

因此,

中没有列表
my $s = ();

括号永远不会创建列表

(仅在赋值运算符的 LHS 上时间接使用。)

我们在标量上下文中将空列表称为什么

Perl 称它为“存根”(如下所示),这就是它的真正含义。它是代码中的一个占位符,不允许放置任何内容。

存根由“空括号”表示,因此这是它的另一个名称。

我称之为糟糕的代码。如果要分配undef,请分配undef

存在一个谎言,即标量上下文中的列表产生列表的最后一个元素。

不,这是真的。列表值不能存在于标量上下文中,因此留下列表运算符。

列表运算符又名逗号运算符返回标量上下文中列表的最后一个元素。


比较以下。没有提到列表:

>perl -MO=Concise -e"my $s = ();"
6  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
5     <2> sassign vKS/2 ->6
3        <0> stub sP ->4
4        <0> padsv[$s:1,2] sRM*/LVINTRO ->5
-e syntax OK

提到了一个列表

>perl -MO=Concise -e"my @a = ();"
7  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
6     <2> aassign[t2] vKS ->7
-        <1> ex-list lK ->4
3           <0> pushmark s ->4
-           <0> stub lP ->-
-        <1> ex-list lK ->6
4           <0> pushmark s ->5
5           <0> padav[@a:1,2] lRM*/LVINTRO ->6
-e syntax OK

...与括号无关

>perl -MO=Concise -e"my @a = 's';"
8  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
7     <2> aassign[t2] vKS ->8
-        <1> ex-list lK ->5
3           <0> pushmark s ->4
4           <$> const[PV "s"] s ->5
-        <1> ex-list lK ->7
5           <0> pushmark s ->6
6           <0> padav[@a:1,2] lRM*/LVINTRO ->7
-e syntax OK

【讨论】:

  • 我认为您误用了 list operator 一词。这不是坏代码($s = () 可能是,但if ( f() ) 其中f 返回一个空列表是标准做法)。谎言是一个列表可以在列表上下文中(它不能,因为在 Perl 5 中没有这样的野兽),而不是它产生最后一个项目。 perl 可以称它为stub,但 Perl 称它为空列表或空列表。有趣的是,在第二个示例中,() 仍然是存根,而不是列表(存根是列表中的(非)值)。 perl -MO=Concise -e '((),5,())'也很有意思。
  • @Chas。欧文斯,关于“谎言是列表可以在列表上下文中”,不,不是。列表运算(又名逗号运算)绝对可以在标量上下文中使用。它只是不会返回列表。执行 `perl -MO=Concise -e "scalar('a','b')"` 你会看到list s。 “s”代表“标量”。
  • @Chas。欧文斯,至于if (f()),这似乎也很错误。如果f 正在返回(),这意味着它可以将undef 作为“真”值返回。 if (f()) 应该是 if (() = f())f() 不应该返回 ()。再次,糟糕的代码。
  • @Chas。 Owens,关于“我认为您在滥用术语列表运算符”,我指的是 the 列表运算符,而不是处理任意列表的运算符的这个俚语。见 perlop。
  • 自己重读perlop,逗号操作符就是逗号操作符(它从来不被称为列表操作符)。没有“列表运算符”。列表运算符是不使用括号的 n 元函数调用的技术术语。
【解决方案2】:

它更像是一个无值表达式,相当于undef。更多示例:

$ perl -we 'print scalar( () )'
Use of uninitialized value in print at -e line 1.

$ perl -we 'print 0+()'
Use of uninitialized value in addition (+) at -e line 1.

【讨论】:

  • FMc 在 cmets 中提出了这一点,并且令人信服。我想我应该深入了解perl 的内部情况。
  • @Chas。 Owens,它创建了一个 stub 运算符(但没有列表运算符)。看我的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-07
  • 2011-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-30
  • 2010-09-27
相关资源
最近更新 更多