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

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

Ответ 1

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

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

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

Ответ 2

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

Возвращаемое значение ioctlfcntl) выглядит следующим образом:

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 жалоб о неправильных числовых преобразованиях.

Ответ 3

В дополнение к тому, что говорили другие, "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

Ответ 4

Значение 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));

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

И, третий оператор?

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

Чтобы обойти это, Perl считает, что 0 but true является числом. Если моя подпрограмма добавления возвращает не просто 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";

Yup, это ноль!

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

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

В последнем статусе возвращается a -1. Это означает, что если я сделал это:

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

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

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

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

    (нет вывода)

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

    (выводит true)

Ответ 8

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

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

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

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

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

Ответ 9

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

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

"0 but true" не является одним из них, поэтому он не является ложным.

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

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

Ответ 10

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

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

рассмотреть следующие вопросы:

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";
}

Ответ 11

Другой пример "0, но true":

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

Ответ 12

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

$ 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

Ответ 13

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

Ответ 14

Строка `` 0, но 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

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

'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. ...