Ответ 1
Различные логические операторы не возвращают пустую строку, они возвращают ложное или истинное значение во всех трех простых скалярных типах. Кажется, что он возвращает пустую строку, потому что print
заставляет контекст строки в своих аргументах:
#!/usr/bin/perl
use strict;
use warnings;
use Devel::Peek;
my $t = 5 > 4;
my $f = 5 < 4;
Dump $t;
Dump $f;
Вывод:
SV = PVNV(0x100802c20) at 0x100827348
REFCNT = 1
FLAGS = (PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK)
IV = 1
NV = 1
PV = 0x100201e60 "1"\0
CUR = 1
LEN = 16
SV = PVNV(0x100802c40) at 0x100827360
REFCNT = 1
FLAGS = (PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK)
IV = 0
NV = 0
PV = 0x100208ca0 ""\0
CUR = 0
LEN = 16
Для тех, кто не знаком с внутренними элементами Perl 5, a PVNV
представляет собой скалярную структуру, которая содержит все три простых скалярных типа (integer IV
, double precision float NV
и string PV
). Флаги IOK
, NOK
и POK
означают, что целочисленные, двойные и строковые значения находятся в синхронизации (для некоторого определения синхронизации), поэтому любой из них может быть использован (т.е. никакие преобразования не должны если вы используете его как целое, двойное или строковое).
Я предполагаю, что пустая строка была выбрана для ложной строки, потому что она меньше, а больше соответствует идее ложной строки, чем "0"
. Игнорируйте мое утверждение о том, что оно меньше, оба ""
и "1"
имеют одинаковый размер: шестнадцать символов. Это так прямо на свалке. Perl 5 добавляет дополнительное пространство для строк, чтобы они быстро расширялись.
О, и я тебя ненавижу. Изучая это, я обнаружил, что я лгал в perlopquick
и теперь должен найти способ его исправить. Если бы вы были похожи на всех других овец и просто приняли поверхностную поверхностность Perl 5 как факт, у меня было бы меньше работы.
Ответы на вопросы в разделе EDIT:
Как использовать строку, которая истинна (например, "false" ) в качестве строкового представления ложных значений, изменяет значение существующего кода?
Единственное, что касается PL_sv_yes и PL_sv_no (канонически истинные и ложные значения, возвращаемые операторами сравнения), - это то, что они доступны только для чтения и создаются perl
не запущенной программой. Если вы измените их, это не изменит критерий правдивости, поэтому PL_sv_no, установленный на "false"
, будет считаться истинным. Вы даже можете сделать это самостоятельно (этот код перестает работать в какой-то момент между Perl 5.18 и последним Perl), используя недокументированные функции perl
:
#!/usr/bin/perl
use strict;
use warnings;
use Scalar::Util qw/dualvar/;
BEGIN {
# use the undocumented SvREADONLY function from Internals to
# modify a reference to PL_sv_no readonly flag
# note the use of & to make the compiler not use SvREADONLY's
# prototype, yet another reason prototypes are bad and shouldn't
# be used
&Internals::SvREADONLY(\!!0, 0);
# set PL_sv_no to a dualvar containing 0 and "false"
${\!!0} = dualvar 0, "false";
}
if (5 < 4) {
print "oops\n";
}
выходы
opps
Это потому, что тест правности сначала смотрит на строки.
Можно ли сказать, что код, который изменяет семантику после такого изменения, менее надежный/правильный, чем он мог быть?
Он будет сломан. Даже если вы ограничиваете себя установкой на int 0 или строку "0" (оба из которых являются ложными), он сломает некоторый действительный код.
Я предполагаю, что строковый контекст настолько распространен в Perl, что единственный параметр, приводящий к разумной семантике, заключается в том, что если логическое значение сохраняет свое значение после округления в строку и из строки...
Да.