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();
或者有人可以對這種行為給出合理的解釋嗎?
uj5u.com熱心網友回復:
您正在觀察的行為是預期的行為。這在perlop中的Logical Defined-Or部分有記錄:
EXPR1 // EXPR2EXPR1如果已定義則回傳 的值,否則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.
uj5u.com熱心網友回復:
// 必須在標量背景關系中評估其左側運算子,因為它需要標量來評估定義性。
@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).
uj5u.com熱心網友回復:
defined(@array)這是一個有點奇怪的結構,Perl 正試圖擺脫它。來自perldoc -f defined:
不再支持在聚合(散列和陣列)上使用“定義”。它用于報告該聚合的記憶體是否曾經被分配過。
這不是測驗它當前是否有任何元素!要檢查大小,只需在標量背景關系(例如條件)中使用陣列變數:
if( @array ) { ... }
而且,達達已經解釋了定義或運算子的作用,這增加了它自己的扭曲。
uj5u.com熱心網友回復:
//并||首先在他們的左側引數上強加標量背景關系。 //檢查是否定義了該引數。 ||檢查該引數是否“不假”。 falsePerl 中的值undef是 0、"0" 或 "" 中的任何一個。
陣列的標量值始終是定義的,因此您不能像以前那樣在檢查中使用它。 @row // (10,20,30)與 相同defined(scalar(@row)) or (10,20,30)。
有關背景關系的詳細討論,請參閱Want模塊的檔案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/362215.html
標籤:perl
