开发者

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-style or. 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 to defined($a) || $b (except that it returns the value of $a rather than the value of defined($a)) and yields the same result as defined($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, use defined($a // $b).

(Emphasis mine.)

So for example:

(defined($a) ? $a : $b) = $c;    # This is valid.
($a // $b) = $c;                 # This is not.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜