程序员人生 网站导航

Perl 标量上下文中如何得到列表

栏目:php教程时间:2015-05-07 10:03:25

本文由帖子《perl标量上下文和列表上下文的1个问题》整理而来,说明了为何在某些情况下,标量上下文中使用”列表“没法得到本身元素的个数,和如何取得你所期望的结果。


1. “列表”在标量上下文中并不是1定会得到元素的个数

也许你觉得这个标题有1些奇怪:依照Perl 上下文的定义,列表在标量上下文中会得到列表元素的个数。单纯通过这个逻辑来看,下面的语句似乎会让$scalar 被赋值3:

$scalar = qw/a b c/;
但是Perl 总会在1些不起眼的地方强行给你1个大欣喜,如果你打印$scalar 的值,你会发现你得到的是"c"而非"3"。


2. 为何可以被称为真谛的上下文规则“失效”了

似乎对非Perl 程序员,说明这个问题要简单许多。为了理解为何上下文规则在这里“失效”了,我们必须抛开“列表在标量上下文中会得到列表元素的个数”这样1个看似是真谛的结论,而从语言本身再去看待这个问题。

依然是这条语句

$scalar = qw/a b c/;
Perl 中所有的qw 运算符都会被展开成列表情势,所以这条语句和下1条完全等价:

$scalar = ('a', 'b', 'c',);
固然这两条语句都会把$scalar 赋值为"c"。

下面让我们忘掉上下文规则,通过Perl 的眼睛去看看在这里Perl 看到了甚么:

1. 赋值号以后是1个左括号,而括号是1种优先级束缚,括号中的表达式被优先计算。

2. 括号中是由1串被逗号隔开的表达式,所以天经地义的是1个逗号表达式。

3. 逗号表达式的值是最后1个表达式的值,最后1个表达式是'c',它的值也是'c'。

4. 所以全部逗号表达式的值是'c'

5. 将'c' 赋值给$scalar。

这就是Perl 的眼睛所看到的东西,也是为何$scalar 会被赋值为'c' 的缘由。

所以给你1条语句:

$scalar = scalar qw/a b c/;
如果你开始以Perl 的眼睛来看代码,你就会明白上面的语句和下1条语句等价:

$scalar = scalar 'c';
天经地义,你得到的依然是"c" 而非"3"。


3. 我们所熟知的Perl 真谛难道是谬论吗?

对Perl 程序员有1个信条:上下文规则即是绝对的真谛。由于这条规则就是Perl 的思考方式,正确性无可置疑。

固然,这条真谛在上面的语句中依然有效。

之所以会带来上下文规则失效了的错觉,是由于我们常常习惯以自己的眼睛而非Perl 的眼睛去看代码。刚才在解释$scalar 为何会得到'c' 的时候,我们也间接地表达了1个事实,在语句

$scalar = qw/a b c/; $scalar = ('a', 'b', 'c',); $scalar = scalar qw/a b c/;
乃至是语句
$scalar = scalar ('a', 'b', 'c',);
中,都不存在任何列表

上下文规则不可能出错,列表在标量上下文中返回的永久都是列表中元素的个数,但是在我们前面写的所有语句中,的确不曾出现过任何1个列表。


4. 如何在标量上下文中使用列表

如果想这样做,方法就是显式的告知Perl 赋值号右侧是1个列表而非逗号表达式:

$scalar = @{ ['a', 'b', 'c',] };
其中赋值号右侧的方括号告知Perl 这是1个匿名列表的援用,而@{$aref} 则是列表的解援用情势,所以赋值号右侧我们得到了1个列表"('a', 'b', 'c')", 而非逗号表达式"('a', 'b', 'c')"。而根据上下文规则,列表在标量上下文中会得到列表元素的个数。天经地义$scalar 被赋值为3。

回过头来,让我们看另外一条语句:

@array = qw/a b c/;
根据qw 展开规则,这条语句和下面1条语句等价:

@array = ('a', 'b', 'c',);

赋值号左侧是1个列表,所以这条语句是1个列表上下文,Perl 会在列表上下文中将赋值号的右侧理解为1个列表"('a', 'b', 'c',)" 而非逗号表达式"('a', 'b', 'c',)"。这个不难理解――在列表上下文中天经地义Perl 会期望1个列表,而在标量上下文中天经地义Perl 会期望1个标量。所以相同的表达式

('a', 'b', 'c',)
会在标量上下文中被当作1个逗号表达式,而在列表上下文中被认为是1个列表。Perl 只是在寻觅它期望得到的东西。


5. 去理解Perl 而非让Perl 理解你

这件事是2 年前自己学Perl 的时候也非常不解的1件事,在查阅了很多资料后才理解为何我的代码会这样运作。我觉得这也是1个Perl 程序员所必须经历的1个转变:

Perl 和其他语言有些不同――写Perl 的时候需要用Perl 的思惟去思考,你需要理解Perl,而非让Perl 去理解你的代码。


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐