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





В целочисленном контексте он оценивается как 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(), andundefare all false in a boolean context. All other values are true. Negation of a true value by!ornotreturns a special false value. When evaluated as a string it is treated as"", but as a number, it is treated as0.
Из-за этого должен быть способ вернуть 0 из системного вызова, который ожидает вернуть 0 как (успешное) возвращаемое значение, и оставить способ сигнализировать о случае сбоя, фактически возвращая ложное значение. "0 but true" служит этой цели.
Nit: «0, но верно» не только для системных вызовов.
Некоторые модули используют строку «0E0», которая принимает значение 0 как число, но истинно как логическое значение.
OMG Perl такой неоднозначный: O
@ Андрей: это не двусмысленно; это очень ясно. Это может вас сбить с толку, но это совсем другое.
@Mathieu Longtin - мне это нравится. Мне это очень нравится.
«0, но правда» - особенное. Когда вы его используете, он не выдает каких-либо предупреждений: perl -wle'print 0+"0 but false"' печатает «Аргумент« 0, но ложь »не является числовым дополнительно (+) в -e строке 1.», а perl -wle'print 0+"0 but true"' - нет.
В дополнение к тому, что говорили другие, "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, вы правы, в perl нет ни истинного, ни ложного ключевого слова. Я отредактировал исходный ответ.
0 означает false в Perl (и других языках, связанных с C). По большей части это разумное поведение. Другие языки (например, Lua) обрабатывают 0 как истинное и предоставляют другой токен (часто ноль или ложный) для представления неверного значения.
Один из случаев, когда способ Perl не работает так хорошо, - это когда вы хотите вернуть либо число, либо, если функция по какой-то причине не работает, ложное значение. Например, если вы пишете функцию, которая читает строку из файла и возвращает количество символов в строке. Обычное использование функции может выглядеть примерно так:
while($c = characters_in_line($file)){
...
};
Обратите внимание, что если количество символов в конкретной строке равно 0, цикл пока завершится до конца файла. Таким образом, функция characters_in_line должна использовать специальный регистр 0 символов и вместо этого возвращать '0 но правда'. Таким образом, функция будет работать так, как задумано в цикле пока, но также вернет правильный ответ, если он будет использоваться как число.
Обратите внимание, что это не встроенная часть языка. Скорее он использует способность Perl интерпретировать строку как число. Поэтому вместо этого иногда используются другие укусы. Например, DBI использует «0E0». При оценке в числовом контексте они возвращают 0, но в логическом контексте - ложный.
Было ли предварительно запрограммировано значение по умолчанию для 0, являющееся истиной или ложью? Я не понимаю, почему кто-то хочет, чтобы на разных языках было по-разному.
Разве 0 ложно, а 1 истинно в большинстве языков?
Вы также можете увидеть строку "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, Perl не возвращает "0, но foobar" в виде числа.
@friedo, вы действительно спрашиваете, почему Perl должен возвращать что-то, что равно нулю, но оценивается как истина? Это позволяет легко оценить успешность выполнения функции, если возвращаемое значение равно нулю. sysseek - это пример.
Нет, я спрашиваю, почему 0 but true выглядит как число, а 0 but anything else - нет. Все они будут оценивать 0 в числовом контексте. Я знаю, для чего нужен 0 but true.
@friedo, почему "0, кроме всего остального", "123abc", "foo bar" и т. д. должны быть числами?
@friedo Потому что это решили люди, пишущие perl. Они чувствовали, что им нужна строка, которая численно равна нулю, но также верна, и забыли, что у них уже есть "0E0" (или решили объяснить, почему это правда, а число 0 было слишком трудным для новичков). Что касается того, почему «0, но истинно» должно выглядеть как число, то есть предупреждение о том, что в числовых контекстах используются не числа.
Потому что он жестко запрограммирован в ядре Perl, чтобы рассматривать его как число. Это уловка, позволяющая объединить соглашения Perl и соглашения ioctl; из perldoc -f ioctl:
The return value of
ioctl(andfcntl) is as follows:if OS returns: then Perl returns: -1 undefined value 0 string "0 but true" anything else that numberThus 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-wcomplaints about improper numeric conversions.
Также используется msgctl, semctl, sysseek и различными модулями CPAN. «относиться к нему как к числу» вводит в заблуждение; «0 xxx», «foo» или «123profit» также рассматриваются как числа в числовом контексте; Особенность «0, но верно» заключается в том, что оно намеренно не вызывает предупреждения.
Вы обнаружите, что специально определенный возврат пустой строки из таких вещей, как повторные операции, также является допустимым числом: perl -wle 'printf "%d\n", 4 > 5' выдает 0 жалобу без.
FWIW: модуль Perl DBI использует «0E0» как вариант «0, но верно».
На самом деле это не вариант, это просто 0 в экспоненциальном формате.
Это жестко закодировано в исходном коде Perl, в частности, в Perl_grok_number_flags в numeric.c.
Читая этот код, я обнаружил, что строка «бесконечность» (без учета регистра) также проходит проверку look_like_number. Я этого не знал.
Некоторые библиотеки C используют «Infinity» (или «+ Infinity» или «-Infinity») как строковое определение бесконечности с плавающей запятой, а не вариации «Inf».
Значение 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. ...
Строка
"0E0"другая похожа на"0 but true". Вместо того, чтобы быть жестко запрограммированным, это следствие экспоненциальной записи Perl. Как непустая ненулевая строка, это правда. В качестве числа это 0. DBI использует его в качестве возвращаемого значения от таких вещей, какexecute, чтобы указать, что оператор SQL работал, но никакие строки не были затронуты.