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

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

Строка "0E0" другая похожа на "0 but true". Вместо того, чтобы быть жестко запрограммированным, это следствие экспоненциальной записи Perl. Как непустая ненулевая строка, это правда. В качестве числа это 0. DBI использует его в качестве возвращаемого значения от таких вещей, как execute, чтобы указать, что оператор SQL работал, но никакие строки не были затронуты.

Schwern 16.03.2011 11:58

Я понимаю причину специальной обработки «0, но истинно» для предупреждений при преобразовании в число, но я все еще думаю, что look_like_number должен возвращает false.

bart 17.03.2011 15:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
60
2
20 550
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

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

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

    (нет вывода)

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

    (печатает верно)

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

Ответ принят как подходящий

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

The number 0, the strings '0' and "", the empty list (), and undef are all false in a boolean context. All other values are true. Negation of a true value by ! or not returns a special false value. When evaluated as a string it is treated as "", but as a number, it is treated as 0.

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

Nit: «0, но верно» не только для системных вызовов.

Michael Carman 25.09.2008 02:06

Некоторые модули используют строку «0E0», которая принимает значение 0 как число, но истинно как логическое значение.

Mathieu Longtin 20.07.2009 17:20

OMG Perl такой неоднозначный: O

Andrei Rînea 08.11.2010 02:22

@ Андрей: это не двусмысленно; это очень ясно. Это может вас сбить с толку, но это совсем другое.

Ether 02.03.2011 21:04

@Mathieu Longtin - мне это нравится. Мне это очень нравится.

Dan Lugg 10.08.2011 00:23

«0, но правда» - особенное. Когда вы его используете, он не выдает каких-либо предупреждений: perl -wle'print 0+"0 but false"' печатает «Аргумент« 0, но ложь »не является числовым дополнительно (+) в -e строке 1.», а perl -wle'print 0+"0 but true"' - нет.

Ark-kun 19.09.2014 23:20

В дополнение к тому, что говорили другие, "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, но истина» - это строка, такая же, как и любая другая, но из-за синтаксиса perl она может служить полезной цели, а именно возвращать целое число ноль из функции без результата «ложь» (в глазах Perl).

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

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

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

Вы уверены, что это голое слово ложно? Это не то, что я получаю, когда делаю $ perl -wle 'print "true\n" if false;'.

MarkHu 06.02.2013 23:15

MarkHu, вы правы, в perl нет ни истинного, ни ложного ключевого слова. Я отредактировал исходный ответ.

Frosty 19.02.2013 21:12

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

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

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

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

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

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

John Odom 16.12.2015 01:50

Разве 0 ложно, а 1 истинно в большинстве языков?

bobtheboy 18.12.2015 08:59

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

Другой пример «0, но правда»:

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

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

Вещи, которые ложны:

  • "".
  • "0".
  • Вещи, которые привязаны к тем.

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

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

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

Но это не дает ответа на вопрос, почему looks_like_number( "0 but true" ) истинно, а looks_like_number( "0 but foobar" ) - ложно.

friedo 16.03.2011 00:09

@friedo, Perl не возвращает "0, но foobar" в виде числа.

ikegami 16.03.2011 00:16

@friedo, вы действительно спрашиваете, почему Perl должен возвращать что-то, что равно нулю, но оценивается как истина? Это позволяет легко оценить успешность выполнения функции, если возвращаемое значение равно нулю. sysseek - это пример.

ikegami 16.03.2011 00:21

Нет, я спрашиваю, почему 0 but true выглядит как число, а 0 but anything else - нет. Все они будут оценивать 0 в числовом контексте. Я знаю, для чего нужен 0 but true.

friedo 16.03.2011 06:34

@friedo, почему "0, кроме всего остального", "123abc", "foo bar" и т. д. должны быть числами?

ikegami 16.03.2011 14:21

@friedo Потому что это решили люди, пишущие perl. Они чувствовали, что им нужна строка, которая численно равна нулю, но также верна, и забыли, что у них уже есть "0E0" (или решили объяснить, почему это правда, а число 0 было слишком трудным для новичков). Что касается того, почему «0, но истинно» должно выглядеть как число, то есть предупреждение о том, что в числовых контекстах используются не числа.

Chas. Owens 18.07.2011 23:47

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

The return value of ioctl (and fcntl) is as follows:

if OS returns:      then Perl returns:

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

Thus Perl returns true on success and false on failure, yet you can still easily determine the actual value returned by the operating system:

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

The special string "0 but true" is exempt from -w complaints about improper numeric conversions.

Также используется msgctl, semctl, sysseek и различными модулями CPAN. «относиться к нему как к числу» вводит в заблуждение; «0 xxx», «foo» или «123profit» также рассматриваются как числа в числовом контексте; Особенность «0, но верно» заключается в том, что оно намеренно не вызывает предупреждения.

ysth 16.03.2011 00:21

Вы обнаружите, что специально определенный возврат пустой строки из таких вещей, как повторные операции, также является допустимым числом: perl -wle 'printf "%d\n", 4 > 5' выдает 0 жалобу без.

tchrist 16.03.2011 04:21

FWIW: модуль Perl DBI использует «0E0» как вариант «0, но верно».

Jonathan Leffler 17.03.2011 10:02

На самом деле это не вариант, это просто 0 в экспоненциальном формате.

geekosaur 17.03.2011 10:16

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

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

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

hobbs 16.03.2011 01:40

Значение 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 числом. Если моя подпрограмма добавлять возвращает не просто 0, но 0 но правда, моя третья инструкция будет работать.

Но является ли 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";

Ага, это ноль!

Подпрограмма показатель является очень старой частью 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», как во втором выражении, предложение else было бы выполнено, но если бы я использовал «barfoo» и «fu», как в третьем, предложение if было бы выполнено. Не то, что я хочу.

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

Строка `` 0, но верно '' по-прежнему является особым случаем:

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

Другие вопросы по теме