perl :"//" operator?
I have a question about using "//" operator, my testing code is as following:
perl -e '@arr1=();@arr2=(1,2,3);@arr3=defined开发者_开发问答(@arr1)?@arr1:@arr2;print "[@arr3]\n"'
[1 2 3]
perl -e '@arr1=();@arr2=(1,2,3);@arr3=@arr1//@arr2;print "[@arr3]\n"'
[0]
perl -e '$v1=();$v2="123";$v3=defined($v1)?$v1:$v2;print "[$v3]\n"'
[123]
perl -e '$v1=();$v2="123";$v3=$v1//$v2;print "[$v3]\n"'
[123]
my question is, why do using "//" operator give the same results as using "defined()? : " on the scalar, but not array(or hash)?
Thanks!!!
Because the leftmost operand of ?:
, ||
, or &&
— or this newfanglulated //
thingie — is always evaluated in boolean not list context, whereas the other operands inherit the surrounding context.
@a = @b && @c;
means
if (@b) {
@a = @c;
} else {
@a = scalar @b;
}
While
@a = @b || @c;
and also
@a = @b // @c;
both mean
means
if (@b) {
@a = scalar @b;
} else {
@a = @c;
}
The only way to get rid of the scalar
in assigning @b
to @a
is to use ?:
@a = @b ? @b : @c;
which of course means
if (@b) {
@a = @b;
} else {
@a = @c;
}
There is also the property that ?:
can be an lvalue:
(@a > @b ? @a : @b) = @c;
which of course means
if (@a > @b) {
@a = @c;
} else {
@b = @c;
}
EDIT
The implementation of @a // @b
and its definition differ. Bug submitted. Thanks.
This has more to do with defined
than with //
. From perldoc -f defined
:
Use of
defined
on aggregates (hashes and arrays) is deprecated. It used to report whether memory for that aggregate had ever been allocated. This behavior may disappear in future versions of Perl.
So in your first example, defined(@arr1)
is false; in the second, defined(@arr1)
is true, and @arr3
contains scalar(@arr1)
. The difference between //
and defined($a) ? $a : $b
is noted in perldoc perlop
:
Although it has no direct equivalent in C, Perl's
//
operator is related to its C-styleor
. In fact, it's exactly the same as||
, except that it tests the left hand side's definedness instead of its truth. Thus,$a // $b
is similar todefined($a) || $b
(except that it returns the value of$a
rather than the value ofdefined($a)
) and yields the same result asdefined($a) ? $a : $b
(except that the ternary-operator form can be used as a lvalue, while$a // $b
cannot). This is very useful for providing default values for variables. If you actually want to test if at least one of$a
and$b
is defined, usedefined($a // $b)
.
(Emphasis mine.)
So for example:
(defined($a) ? $a : $b) = $c; # This is valid.
($a // $b) = $c; # This is not.
精彩评论