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

Почему я ничего не даю в Perl?

Это странно. Следующее:

$sum = !0;
print $sum;

выводит 1, как и следовало ожидать. Но это

$sum = !1;
print $sum;

ничего не выводит. Почему?

4b9b3361

Ответ 1

Будьте осторожны: то, что вы написали, не делает то, что вы думаете. Помните, что perl не имеет реального булевского типа данных. Он получил скаляры, хеши, списки и ссылки. То, как он обрабатывает истинные/ложные значения, тогда является контекстуальным. Все оценивает значение "true" в perl, за исключением переменных undefined, пустого списка, пустой строки и числа 0.

Таким образом, ваш код делает обратное значение, которое оценивается как "ложное", что может быть любым, что отсутствует в списке выше. По соглашению и для простоты perl возвращает 1 (хотя вы не должны полагаться на это, он вполне может вернуть список, содержащий серию случайных чисел, потому что это тоже будет оцениваться как "true" .)

Аналогичная ситуация возникает, когда вы запрашиваете обратное значение, которое оценивается как "true" . То, что на самом деле распечатывается, не "ничего", это пустая строка (''), которая, как я упоминал, оценивает "false" в булевых выражениях. Вы можете проверить это:

print "This evaluates to false\n" if( (!1) eq '');

Если вы спрашиваете, почему perl выплескивает пустую строку вместо одного из других значений "false", это, вероятно, потому, что perl создается для обработки строк и что вполне разумная строка для обратной связи.

Ответ 2

Операторы, которые возвращают только логический результат, всегда будут возвращать 1 для true и специальное ложное значение, которое "" в строковых контекстах, но 0 в числовых контекстах.

Ответ 3

Здесь добавлено дополнение к другим замечательным ответам, которые вы уже получили.

Not Not Not

Рассмотрим следующий код, который проверяет каждый из операторов 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 отличается (побитовое).

Теперь интересный элемент:

  • Пока мы получаем предупреждение для строки 21 (0+''), при добавлении 0+!1 предупреждения не генерируется предупреждение.

Он берет два, чтобы завязать

Происходит что-то подозрительное, и эта ловкость связана со специальными скалярными контекстами в Perl. В этом случае различие между числовыми и строковыми контекстами. И возможность создания переменной, которая имеет разные значения в каждом контексте, а также двойную переменную.

Похоже, что !1 возвращает двойную переменную, которая возвращает 0 в числовом контексте и пустую строку в контексте строки.

Тест на двойную проверку в конце показывает, что самодельный двойник работает так же, как !1.

Но это хорошая вещь

Как и многие функции Perl, двойные переменные, по-видимому, сначала бросают вызов ожиданиям и могут сбивать с толку. Однако, как и те другие функции, которые они используют, они значительно облегчают жизнь.

Насколько мне известно, двойным символом 0 и '' является единственное определенное значение, которое вернет false во всех скалярных контекстах. Таким образом, это очень разумное возвращаемое значение для !1. Можно утверждать, что undef является хорошим ложным результатом, но тогда неинициализированная переменная не отличается от ложного значения. Кроме того, попытки распечатать или добавить результаты логических значений будут затем изнуряться из-за ненужных предупреждений.

Другим известным двойным символом является $! или $OS_ERROR, если вы use English. В числовой форме вы получаете код ошибки, в строковой форме код ошибки переводится для вас.

Это не ничего, пусто, но это ничто

Итак, в общем, вы ничего не получаете, вы не получаете пустую строку, и вы не получаете нуль.

Вы получаете переменную, которая одновременно является пустой строкой и 0.

Ответ 4

Оператор ! выполняет логические операции. "" (Пустая строка) равно как false как 0. 1 является удобным значением true. ! не следует полагаться на то, чтобы делать что-либо другое, кроме какого-либо значения true/false. Опираясь на точное значение, выходящее за рамки этого, опасно и может меняться между версиями Perl.

Ответ 5

См. 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);