Это странно. Следующее:
$sum = !0;
print $sum;
выводит 1, как и следовало ожидать. Но это
$sum = !1;
print $sum;
ничего не выводит. Почему?
Это странно. Следующее:
$sum = !0;
print $sum;
выводит 1, как и следовало ожидать. Но это
$sum = !1;
print $sum;
ничего не выводит. Почему?
Будьте осторожны: то, что вы написали, не делает то, что вы думаете. Помните, что perl не имеет реального булевского типа данных. Он получил скаляры, хеши, списки и ссылки. То, как он обрабатывает истинные/ложные значения, тогда является контекстуальным. Все оценивает значение "true" в perl, за исключением переменных undefined, пустого списка, пустой строки и числа 0.
Таким образом, ваш код делает обратное значение, которое оценивается как "ложное", что может быть любым, что отсутствует в списке выше. По соглашению и для простоты perl возвращает 1 (хотя вы не должны полагаться на это, он вполне может вернуть список, содержащий серию случайных чисел, потому что это тоже будет оцениваться как "true" .)
Аналогичная ситуация возникает, когда вы запрашиваете обратное значение, которое оценивается как "true" . То, что на самом деле распечатывается, не "ничего", это пустая строка (''), которая, как я упоминал, оценивает "false" в булевых выражениях. Вы можете проверить это:
print "This evaluates to false\n" if( (!1) eq '');
Если вы спрашиваете, почему perl выплескивает пустую строку вместо одного из других значений "false", это, вероятно, потому, что perl создается для обработки строк и что вполне разумная строка для обратной связи.
Операторы, которые возвращают только логический результат, всегда будут возвращать 1 для true и специальное ложное значение, которое "" в строковых контекстах, но 0 в числовых контекстах.
Здесь добавлено дополнение к другим замечательным ответам, которые вы уже получили.
Рассмотрим следующий код, который проверяет каждый из операторов Perl 'not':
#!/usr/bin/perl
use strict;
use warnings;
for( '!1', 'not 1', '~0' ) {
my $value = eval;
my $zero_plus = 0 + $value;
print join "\n",
"\nExpression: $_",
"Value: '$value'",
"Defined: " . defined $value,
"Length: " . length($value),
"Plus: " . +$value,
"Plus Zero: '$zero_plus'",
'';
}
print "\nTest addition for a literal null string: ";
print 0+'', "\n";
use Scalar::Util qw(dualvar);
{ # Test a dualvar
my $value = dualvar 0, '';
my $zero_plus = 0+$value;
print join "\n",
"\nExpression: dualvar",
"Value: '$value'",
"Defined: " . defined $value,
"Length: " . length($value),
"Plus: " . +$value,
"Plus Zero: '$zero_plus'",
'';
}
Выполнение этого результата приводит к следующему. Обратите внимание на предупреждающее сообщение:
Argument "" isn't numeric in addition (+) at test.pl line 21.
Expression: !1
Value: ''
Defined: 1
Length: 0
Plus:
Plus Zero: '0'
Expression: not 1
Value: ''
Defined: 1
Length: 0
Plus:
Plus Zero: '0'
Expression: ~0
Value: '4294967295'
Defined: 1
Length: 10
Plus: 4294967295
Plus Zero: '4294967295'
Test addition for a literal null string: 0
Expression: dualvar
Value: ''
Defined: 1
Length: 0
Plus:
Plus Zero: '0'
Из этого мы узнаем несколько вещей.
Первые два элемента не так уж захватывают:
!1
и not 1
ведут себя в основном одинаково.~1
отличается (побитовое).Теперь интересный элемент:
0+''
), при добавлении 0+!1
предупреждения не генерируется предупреждение.Происходит что-то подозрительное, и эта ловкость связана со специальными скалярными контекстами в Perl. В этом случае различие между числовыми и строковыми контекстами. И возможность создания переменной, которая имеет разные значения в каждом контексте, а также двойную переменную.
Похоже, что !1
возвращает двойную переменную, которая возвращает 0 в числовом контексте и пустую строку в контексте строки.
Тест на двойную проверку в конце показывает, что самодельный двойник работает так же, как !1
.
Как и многие функции Perl, двойные переменные, по-видимому, сначала бросают вызов ожиданиям и могут сбивать с толку. Однако, как и те другие функции, которые они используют, они значительно облегчают жизнь.
Насколько мне известно, двойным символом 0
и ''
является единственное определенное значение, которое вернет false во всех скалярных контекстах. Таким образом, это очень разумное возвращаемое значение для !1
. Можно утверждать, что undef
является хорошим ложным результатом, но тогда неинициализированная переменная не отличается от ложного значения. Кроме того, попытки распечатать или добавить результаты логических значений будут затем изнуряться из-за ненужных предупреждений.
Другим известным двойным символом является $!
или $OS_ERROR
, если вы use English
. В числовой форме вы получаете код ошибки, в строковой форме код ошибки переводится для вас.
Итак, в общем, вы ничего не получаете, вы не получаете пустую строку, и вы не получаете нуль.
Вы получаете переменную, которая одновременно является пустой строкой и 0.
Оператор !
выполняет логические операции. ""
(Пустая строка) равно как false
как 0
. 1
является удобным значением true
. !
не следует полагаться на то, чтобы делать что-либо другое, кроме какого-либо значения true
/false
. Опираясь на точное значение, выходящее за рамки этого, опасно и может меняться между версиями Perl.
См. perldoc perlsyn:
Истина и ложь
Число 0, строки '0' и '', пустой список() и undef - все false в булевом контексте. Все остальные значения истинны. Отрицание истинного значение by! или не возвращает специальный ложное значение. Когда оценивается как строка обрабатывается как '', но как число, оно обрабатывается как 0.
Там, если вы напечатаете значение как число, вы получите 0
, а не пустую строку:
printf "%d\n", $_ for map { !$_ } (1, 0);
или
print 0 + $_, "\n" for map { !$_ } (1, 0);
Сравните их с
printf "%s\n", $_ for map { !$_ } (1, 0);
и
print $_, "\n" for map { !$_ } (1, 0);