Вопрос

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

Это было полезно?

Решение

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

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

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

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

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

В дополнение к тому, что говорили другие, "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, предполагается, что процедура завершилась с ошибкой или вернула значение false.

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

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 оговорка сработала бы.

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

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

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

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

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

    (нет выходных данных)

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

    (выводит значение true)

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

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

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

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

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

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

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

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

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

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

Еще один пример "0, но истинно":

Модуль DBI использует "0E0" в качестве возвращаемого значения для запросов на ОБНОВЛЕНИЕ или УДАЛЕНИЕ, которые не повлияли ни на какие записи.Он принимает значение true в логическом контексте (указывая, что запрос был выполнен правильно) и 0 в числовом контексте, указывая, что никакие записи не были изменены запросом.

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

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

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

И строка не обязательно должна быть "0, но true"."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, но 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. ...
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top