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

58

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

  • 12
    Строка "0E0" другая похожа на "0 but true" . Вместо того, чтобы быть жестко закодированным, это следствие экспоненциальной записи Perl. Как непустая, ненулевая строка, это правда. Как число, это 0. DBI использует его как возвращаемое значение из таких вещей, как execute чтобы указать, что оператор SQL работал, но на строки не влияли.
  • 0
    Я понимаю причину специальной обработки «0, но верно» для предупреждений при преобразовании в число, но я все еще думаю, что look_like_number должен возвращать false.
Теги:
integer
boolean

14 ответов

52
Лучший ответ

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

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

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

  • 0
    Nit: «0, но правда» не только для системных вызовов.
  • 14
    Некоторые модули используют строку «0E0», которая оценивается как 0 как число, но true как логическое значение.
Показать ещё 4 комментария
49

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

  • 12
    Также используется msgctl, semctl, sysseek и различными модулями CPAN. «рассматривать это как число» вводит в заблуждение; «0 xxx», «foo» или «123profit» также рассматриваются как числа в числовом контексте; Особенность «0, но факт» заключается в том, что оно намеренно не вызывает предупреждение.
  • 0
    Вы обнаружите, что специальная определенная нулевая строка, возвращаемая из таких вещей, как relops, также является допустимым числом: perl -wle 'printf "%d\n", 4 > 5' вызывает жалобу 0 без .
Показать ещё 2 комментария
42

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

Значение 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 сработало бы.

23

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

11

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

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

  • 1
    Некоторые библиотеки C используют «Infinity» (или «+ Infinity» или «-Infinity») в качестве строкового определения бесконечности с плавающей точкой, а не вариации «Inf».
9

В целочисленном контексте он вычисляет 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.

  • 0
    Было ли значение по умолчанию для 0 быть истинным или ложным предварительно запрограммированным на языках? Я не понимаю, почему кто-то хотел бы, чтобы это было по-разному на разных языках.
  • 0
    Разве 0 не ложно, а 1 верно в большинстве языков?
6

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

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

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

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

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

  • 3
    Но это не объясняет, почему looks_like_number( "0 but true" ) имеет значение true, тогда как looks_like_number( "0 but foobar" ) имеет значение false.
  • 0
    @friedo, Perl не возвращает «0, но foobar» как число.
Показать ещё 4 комментария
3

Я только что нашел доказательство того, что строка "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
3

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

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

3

"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";
}
  • 0
    Вы уверены, что это ложное слово? Это не то, что я получаю, когда делаю $ perl -wle 'print "true\n" if false;'
  • 0
    MarkHu, вы правы, в Perl нет ни ключевого слова true, ни false. Я отредактировал оригинальный ответ.
2

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

1

Строка `` 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. ...

Ещё вопросы

Сообщество Overcoder
Наверх
Меню