Подтвердить что ты не робот

Perl: "//" оператор?

У меня есть вопрос об использовании оператора "//", мой тестовый код выглядит следующим образом:

perl -e '@arr1=();@arr2=(1,2,3);@arr3=defined(@arr1)[email protected]:@arr2;print "[@arr3]\n"' 

[1 2 3] 

perl -e '@arr1=();@arr2=(1,2,3);@[email protected]//@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]

мой вопрос: почему использование оператора "//" дает те же результаты, что и использование "defined()?:" на скалярном, но не массиве (или хэше)?

Спасибо!!!

4b9b3361

Ответ 1

Поскольку самый левый операнд ?:, || или && - или этот newfanglulated // thingie - всегда оценивается в булевом контексте не в виде списка, тогда как другие операнды наследуют окружающий контекст.

@a = @b && @c;

означает

if (@b) {
     @a = @c;
} else {
     @a = scalar @b;
}

В то время как

@a = @b || @c;

, а также

@a = @b // @c;

оба означают

означает

if (@b) {
     @a = scalar @b;
} else {
     @a = @c;
}

Единственный способ избавиться от scalar при назначении @b - @a - использовать ?:

@a = @b ? @b : @c;

что, конечно, означает

if (@b) {
    @a = @b;
} else {
    @a = @c;
}

Существует также свойство, что ?: может быть lvalue:

(@a > @b ? @a : @b) = @c;

что, конечно, означает

if (@a > @b) {
    @a = @c;
} else {
    @b = @c;
}

ИЗМЕНИТЬ

Реализация @a // @b и ее определение различаются. Исправлена ​​ошибка. Спасибо.

Ответ 2

Это больше связано с defined, чем с //. Из perldoc -f defined:

Использование defined в агрегатах (хэши и массивы) устарело.. Оно использовалось для определения того, была ли выделена память для этого агрегата. Такое поведение может исчезнуть в будущих версиях Perl.

Итак, в вашем первом примере defined(@arr1) - false; во втором, defined(@arr1) истинно, а @arr3 содержит scalar(@arr1). Разница между // и defined($a) ? $a : $b отмечена в perldoc perlop:

Хотя он не имеет прямого эквивалента в C, оператор Perl // связан с его C-style or. Фактически, он точно такой же, как ||, за исключением того, что он проверяет определенность левой стороны вместо ее истины. Таким образом, $a // $b похож на defined($a) || $b (за исключением того, что он возвращает значение $a, а не значение defined($a)), и дает тот же результат, что и defined($a) ? $a : $b (за исключением того, что тернарный оператор форма может использоваться как lvalue, а $a // $b не может). Это очень полезно для предоставления значений по умолчанию для переменных. Если вы действительно хотите проверить, определено ли хотя бы одно из $a и $b, используйте defined($a // $b).

(Подчеркните мой.)

Итак, например:

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