簡體   English   中英

Perl 定義-或在列表上下文中,為什么是標量?

[英]Perl defined-or in a list context, why a scalar?

use strict;
use warnings;
use Test::More;

subtest 'explicit array' => sub  {
    my @row = (1,2,3);
    # let's disassamble the array.
    # without default it works:
    my ($one, $two, $three) =  @row;
    is($one, 1, 'one');
    # this works too:
    ($one, $two, $three) =  @row ? @row : (10,20,30);
    is($one, 1, 'one');
    # and the default hits
    my @emptyness;
    ($one, $two, $three) = @emptyness ? @emptyness : (10,20,30);
    is($one, 10, 'one default');
    # however, this squashes the array to a scalar
    ($one, $two, $three) =  @row // (10,20,30);
    is($one, 3, 'scalar, length');
    is($two, undef, 'nothing else');
    # shouldn't 'defined-or' be equivalent to a ternary with a check against undef?
    # ($one, $two, $three) = defined @emptyness ? @emptyness : (10,20,30); # fails!
    # "Can't use 'defined(@array)' (Maybe you should just omit the defined()?)"
    # Probably @array // ... should fail in the same way, but instead it returns @array
    # in a scalar context.
    # so maybe this is a bug
};


done_testing();

或者有人可以對這種行為給出合理的解釋嗎?

defined(@array)是一個有點奇怪的結構,Perl 正試圖擺脫它。 perldoc -f defined

不再支持在聚合(散列和數組)上使用“定義”。 它用於報告該聚合的內存是否曾經被分配過。

這不是測試它當前是否有任何元素! 要檢查大小,只需在標量上下文(例如條件)中使用數組變量:

if( @array ) { ... }

而且,達達已經解釋了定義或運算符的作用,這增加了它自己的扭曲。

//必須在標量上下文中評估其左側運算符,因為它需要標量來評估定義性。

@a返回數組在標量上下文中包含的元素數。

所以@a // ...總是返回@a中元素的數量(因為所有數字都是定義的值)。


定義性或真實性的概念不是為整個標量序列(“列表”)定義的。 它們僅適用於單個標量。 因此, // , && , and , || , or , ! , not?:需要來自其最左側操作數的標量,因此它們在標量上下文中對其進行評估。 xor需要測試其兩個操作數的真值,因此在標量上下文中評估兩者。

$ perl -M5.010 -e'
   sub cx { print wantarray ? " list  " : " scalar"; $_[0] }

   print "// ";  @a =   cx($u) //  cx();     say "";
   print "&& ";  @a =   cx(0)  &&  cx();     say "";
   print "and";  @a = ( cx(1)  and cx() );   say "";
   print "|| ";  @a =   cx(0)  ||  cx();     say "";
   print "or ";  @a = ( cx(0)  or  cx() );   say "";
   print "xor";  @a = ( cx(0)  xor cx(0) );  say "";
   print "!  ";  @a =   !   cx();            say "";
   print "not";  @a =   not cx();            say "";
   print "?: ";  @a =  cx() ? 0    : 0;
                 @a =  1    ? cx() : 0;
                 @a =  0    ? 0    : cx();   say "";
'
//  scalar list
&&  scalar
and scalar list
||  scalar list
or  scalar list
xor scalar scalar
!   scalar
not scalar
?:  scalar list   list

您可能會有這樣的錯誤印象,即@a總是返回其元素的列表,並且在標量上下文中進行評估時,這會被強制轉換為計數。 但事實並非如此。

根本就沒有列表這樣的東西。 當我們說“對列表求值”或“返回列表”時,我們只是指“向堆棧添加零個或多個標量”。 返回標量和返回“一個標量的列表”之間絕對沒有區別。 兩者都是指向堆棧添加標量。 由於只有標量被添加到堆棧中,所以沒有什么可以證明的

由於沒有返回列表數據結構,因此在標量上下文中沒有任何東西可以神奇地強制轉換為標量; 當在標量上下文中計算時,它取決於每個運算符返回單個標量。 這允許每個運算符選擇他們想要在標量上下文中返回的內容。 它變化很大

簡而言之, @a返回標量上下文中元素的數量,而不是它在列表上下文中包含的元素。

         +-------------------------- (Scalar context) Returns 3
         |            +------------- (List context) Returns three scalars
         |            |
      vvvv     vvvvvvvv
() =  @row // (10,20,30);
         +-------------------------- (Scalar context) Returns 3
         |      +------------------- (List context) Returns three scalars
         |      |           +------- (List context) Returns three scalars
         |      |           |
      vvvv   vvvv    vvvvvvvv
() =  @row ? @row : (10,20,30);

最后,讓我們分析@row // ...

我們已經確定@row在上面的標量上下文中被評估,並且當它執行時它返回數組中數組中的元素數。

好吧,數值不一定是undef ,所以它們都是定義的。 所以這意味着@row // ...的右側大小永遠不會被評估。 你也可以寫scalar(@row)

您正在觀察的行為是預期的行為。 這在perlop中的Logical Defined-Or部分有記錄:

EXPR1 // EXPR2如果定義了EXPR2則返回EXPR1的值,否則返回EXPR2的值。 EXPR1在標量上下文中計算, EXPR2在 // 本身的上下文中計算)。

並且,perldoc 稍后提供了以下示例:

特別是,這意味着您不應該使用它在兩個聚合之間進行選擇以進行分配:

 @a = @b || @c; # This doesn't do the right thing @a = scalar(@b) || @c; # because it really means this. @a = @b ? @b : @c; # This works fine, though.

//|| 首先在他們的左側參數上強加標量上下文。 //檢查是否定義了該參數。 || 檢查該參數是否“不假”。 Perl 中的false是任何值undef 、0、“0”或“”。

數組的標量值始終是定義的,因此您不能像以前那樣在檢查中使用它。 @row // (10,20,30)defined(scalar(@row)) or (10,20,30)

有關上下文的詳細討論,請參閱Want模塊的文檔。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM