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()?:" на скалярном, но не массиве (или хэше)?
Спасибо!!!
Ответы
Ответ 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.