Что означает "0, но факт" в Perl?

Может кто-нибудь объяснить, что именно означает "0, но true" в Perl? Насколько я понимаю, он равен нулю в целочисленном сравнении, но при использовании в качестве логического значения оценивается как true. Это правильно? Это нормальное поведение языка или это особая строка, интерпретируемая в интерпретаторе как особый случай?

14 ответов

Решение

Это нормальное поведение языка. Цитируя perlsyn страница руководства:

Число 0 Струны '0' а также "", пустой список (), а также undef все ложно в логическом контексте. Все остальные значения верны. Отрицание истинного значения ! или же not возвращает специальное ложное значение. Когда оценивается как строка, это рассматривается как "", но как число, это рассматривается как 0,

Из-за этого должен быть способ вернуться 0 от системного вызова, который ожидает возврата 0 как (успешное) возвращаемое значение, и оставьте способ сообщить об ошибке, фактически вернув ложное значение. "0 but true" служит этой цели.

Потому что он жестко закодирован в ядре Perl, чтобы рассматривать его как число. Это хак, чтобы сделать соглашения Perl и ioctlусловности играют вместе; от perldoc -f ioctl:

Возвращаемое значение ioctl (а также fcntl) как следует:

if OS returns:      then Perl returns:

    -1              undefined value
     0              string "0 but true"
anything else       that number

Таким образом, Perl возвращает true в случае успеха и false в случае сбоя, но вы все равно можете легко определить фактическое значение, возвращаемое операционной системой:

$retval = ioctl(...) || -1;
printf "System returned %d\n", $retval;

Специальная строка "0 but true" освобождается от -w жалобы на неправильные числовые преобразования.

В дополнение к тому, что говорили другие, "0 but true" в особом случае он не предупреждает в числовом контексте:

$ perl -wle 'print "0 but true" + 3'
3
$ perl -wle 'print "0 but crazy" + 3'
Argument "0 but crazy" isn't numeric in addition (+) at -e line 1.
3

Значение 0 but true это особый случай в Perl. Хотя для ваших простых смертных глаз это не похоже на число, мудрый и всем знающий Perl понимает, что это действительно число.

Это связано с тем, что когда подпрограмма Perl возвращает значение 0, предполагается, что подпрограмма завершилась неудачно или вернула ложное значение.

Представьте, что у меня есть подпрограмма, которая возвращает сумму двух чисел:

die "You can only add two numbers\n" if (not add(3, -2));
die "You can only add two numbers\n" if (not add("cow", "dog"));
die "You can only add two numbers\n" if (not add(3, -3));

Первое утверждение не умрет, потому что подпрограмма вернет 1, Это хорошо. Второе утверждение умрет, потому что подпрограмма не сможет добавить корову к собаке.

И третье утверждение?

Хммм могу добавить 3 в -3, Я просто получаю 0, но тогда моя программа умрет, хотя add подпрограмма сработала!

Чтобы обойти это, Perl считает 0 but true быть числом. Если моя подпрограмма add возвращает не просто 0, а 0, но true, мое третье утверждение будет работать.

Но 0, но верно ли числовой ноль? Попробуйте это:

my $value = "0 but true";
print qq(Add 1,000,000 to it: ) . (1_000_000 + $value) . "\n";
print "Multiply it by 1,000,000: " . 1_000_000 * $value . "\n";

Да, это ноль!

Подпрограмма index - это очень старая часть Perl, существовавшая до концепции 0, но верная. Предполагается вернуть позицию подстроки, расположенной в строке:

index("barfoo", "foo");   #This returns 3
index("barfoo", "bar");   #This returns 0
index("barfoo", "fu");    #This returns ...uh...

Последняя запись возвращает -1, Что означает, если бы я сделал это:

if ($position = index($string, $substring)) {
   print "It worked!\n";
}
else {
   print "If failed!\n";
}

Как я обычно делаю со стандартными функциями, это не сработает. Если бы я использовал "barfoo" и "bar", как я сделал во втором утверждении, The else предложение будет выполнено, но если бы я использовал "barfoo" и "fu", как в третьем, if пункт будет выполняться. Не то, что я хочу.

Однако если index подпрограмма вернула 0, но верно для второго оператора и undef для третьего утверждения мой if/else пункт работал бы.

Вы также можете увидеть строку "0E0", используемую в коде Perl, и это означает то же самое, где 0E0 просто означает 0, записанный в экспоненциальной записи. Однако, поскольку Perl рассматривает только "0", "" или undef как false, он оценивается как true в логическом контексте.

Он жестко запрограммирован в исходном коде Perl, в частности в Perl_grok_number_flags в numeric.c.

Читая этот код, я обнаружил, что строка "бесконечность" (без учета регистра) также проходит проверку look_like_number. Я этого не знал.

В целочисленном контексте он оценивается как 0 (числовая часть в начале строки) и равен нулю. В скалярном контексте это непустое значение, так что это правда.

  • if (int("0 but true")) { print "zero"; }

    (нет выхода)

  • if ("0 but true") { print "true"; }

    (печатает правда)

0 означает false в Perl (и других языках, связанных с C). По большей части, это разумное поведение. Другие языки (например, Lua) обрабатывают 0 как true и предоставляют другой токен (часто ноль или false) для представления неверного значения.

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

while($c = characters_in_line($file)){
    ...
};

Обратите внимание, что если количество символов в конкретной строке равно 0, цикл while завершится до конца файла. Таким образом, функция characters_in_line должна использовать символы 0 в специальном случае и возвращать "0, но true". Таким образом, функция будет работать так, как задумано в цикле while, но также будет возвращать правильный ответ, если она будет использоваться в качестве числа.

Обратите внимание, что это не встроенная часть языка. Скорее, он использует способность Perl интерпретировать строку как число. Поэтому вместо этого иногда используются другие укусы. DBI использует "0E0", например. При оценке в числовом контексте они возвращают 0, но в логическом контексте - false.

Вещи, которые являются ложными:

  • "",
  • "0",
  • Вещи, которые относятся к тем.

"0 but true" не один из них, так что это не ложь.

Кроме того, Perl возвращается "0 but true" где число ожидается, чтобы сигнализировать, что функция преуспела, даже если она возвратила ноль. sysseek является примером такой функции. Поскольку ожидается, что значение будет использоваться как число, Perl кодируется, чтобы считать его числом. В результате никакие предупреждения не выдаются, когда он используется как число, и looks_like_number("0 but true") возвращает истину.

Другие "истинные нули" можно найти по адресу http://www.perlmonks.org/?node_id=464548.

Я только что нашел доказательство того, что строка "0, но true" фактически встроена в интерпретатор, как некоторые люди здесь уже ответили:

$ strings /usr/lib/perl5/5.10.0/linux/CORE/libperl.so | grep -i true
Perl_sv_true
%-p did not return a true value
0 but true
0 but true

Еще один пример "0, но факт":

Модуль DBI использует "0E0" в качестве возвращаемого значения для запросов UPDATE или DELETE, которые не влияли на какие-либо записи. Он оценивается как true в логическом контексте (указывая на то, что запрос был выполнен правильно) и в 0 в числовом контексте, указывая, что записи не были изменены запросом.

Если вы хотите написать функцию, которая возвращает либо целочисленное значение, либо false или undef (т.е. для случая ошибки), тогда вы должны следить за нулевым значением. Возвращение его ложно и не должно указывать на условие ошибки, поэтому возвращение "0, но истина" делает возвращаемое значение функции истинным, в то же время возвращая нулевое значение, когда выполняется математическая обработка.

"0, но истина" - это строка, как и любая другая, но из-за синтаксиса perl она может служить полезной цели, а именно возвращать целое число ноль из функции без результата "false"(в глазах perl).

И строка не должна быть "0, но истина". "0, но false" по-прежнему "true" в логическом смысле.

рассматривать:

if(x)

for x:        yields:
1             -> true
0             -> false
-1            -> true
"true"        -> true
"false"       -> true
"0 but true"  -> true
int("0 but true") ->false

Результат всего этого вы можете получить:

sub find_x()

и иметь этот код в состоянии вывести "0" в качестве вывода:

if($x = find_x)
{
   print int($x) . "\n";
}

Строка ``0 but true'' все еще является особым случаем:

for arg in "'0 but true'" "1.0*('0 but true')" \
           "1.0*('0 but false')" 0 1 "''" "0.0" \
           "'false'" "'Ja'" "'Nein'" "'Oui'" \
           "'Non'" "'Yes'" "'No'" ;do
    printf "%-32s: %s\n" "$arg" "$(
        perl -we '
            my $ans=eval $ARGV[0];
            $ans=~s/^(Non?|Nein)$//;
            if ($ans) {
                printf "true:  |%s|\n",$ans
            } else {
                printf "false: |%s|", $ans
          };' "$arg"
        )"
    done

дать следующее: (обратите внимание на `` предупреждение ''!)

'0 but true'                    : true:  |0 but true|
1.0*('0 but true')              : false: |0|
Argument "0 but false" isn't numeric in multiplication (*) at (eval 1) line 1.
1.0*('0 but false')             : false: |0|
0                               : false: |0|
1                               : true:  |1|
''                              : false: ||
0.0                             : false: |0|
'false'                         : true:  |false|
'Ja'                            : true:  |Ja|
'Nein'                          : false: ||
'Oui'                           : true:  |Oui|
'Non'                           : false: ||
'Yes'                           : true:  |Yes|
'No'                            : false: ||

... и не забудьте RTFM!

man -P'less +"/0 but [a-z]*"' perlfunc

       ... "fcntl".  Like "ioctl", it maps a 0 return from the system call
           into "0 but true" in Perl.  This string is true in boolean
           context and 0 in numeric context.  It is also exempt from the
           normal -w warnings on improper numeric conversions. ...
Другие вопросы по тегам