Что означает “0, но true” в Perl?
Вопрос
Кто-нибудь может объяснить, что именно означает строка "0, но true" в Perl?Насколько я понимаю, оно равно нулю при сравнении целых чисел, но принимает значение true при использовании в качестве логического значения.Правильно ли это?Является ли это нормальным поведением языка или это специальная строка, рассматриваемая в интерпретаторе как особый случай?
Решение
Это нормальное поведение языка.Цитируя perlsyn
справочная страница:
Число
0
, струны'0'
и""
, пустой список()
, иundef
все они являются ложными в логическом контексте.Все остальные значения являются истинными.Отрицание истинного значения с помощью!
илиnot
возвращает специальное значение false.При вычислении в виде строки она обрабатывается как""
, но как число, оно рассматривается как0
.
Из-за этого должен быть способ вернуться 0
из системного вызова, который ожидает возврата 0
в качестве (успешного) возвращаемого значения и оставьте способ сигнализировать о сбое, фактически возвращая значение false. "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, предполагается, что процедура завершилась с ошибкой или вернула значение 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. ...