Подтвердить что ты не робот

Что делают функции Perl, которые возвращают Boolean, действительно возвращают

Функция Perl defined (и многие другие) возвращает "логическое значение".

Учитывая, что Perl на самом деле не имеет логического типа (и использует значения, подобные 1 для true, а 0 или undef для false), язык Perl точно определяет, что возвращается для логических значений? Например, может ли defined(undef) вернуть 0 или undef и может ли он быть изменен?

4b9b3361

Ответ 1

Почти во всех случаях (т.е. если нет причин для этого делать иначе), Perl возвращает один из двух статически распределенных скаляров: &PL_sv_yes (для true) и &PL_sv_no (для false). Это они подробно:

>perl -MDevel::Peek -e"Dump 1==1"
SV = PVNV(0x749be4) at 0x3180b8
  REFCNT = 2147483644
  FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 1
  NV = 1
  PV = 0x742dfc "1"\0
  CUR = 1
  LEN = 12

>perl -MDevel::Peek -e"Dump 1==0"
SV = PVNV(0x7e9bcc) at 0x4980a8
  REFCNT = 2147483647
  FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 0
  NV = 0
  PV = 0x7e3f0c ""\0
  CUR = 0
  LEN = 12

yes является тройным var (IOK, NOK и POK). Он содержит целое число со знаком (IV), равное 1, число с плавающей запятой (NV), равное 1, и строку (PV), равную 1.

no также является тройным var (IOK, NOK и POK). Он содержит целое число со знаком (IV), равное 0, число с плавающей запятой (NV), равное 0, и пустую строку (PV). Это означает, что он строит пустую строку, и ее число равно 0. Это не эквивалентно пустой строке

>perl -wE"say 0+(1==0);"
0

>perl -wE"say 0+'';"
Argument "" isn't numeric in addition (+) at -e line 1.
0

или 0

>perl -wE"say ''.(1==0);"


>perl -wE"say ''.0;"
0

Там нет гарантии, что это всегда останется. И нет оснований полагаться на это. Если вам нужны конкретные значения, вы можете использовать что-то вроде

my $formatted = $result ? '1' : '0';

Ответ 2

Они возвращают специальное ложное значение, которое является "" в контексте строки, но 0 в числовом контексте (без нечислового предупреждения). Истинное значение не столь особенное, так как оно 1 в любом контексте. defined() не возвращает undef.

(Вы можете создавать похожие значения самостоятельно, например, Scalar::Util::dualvar(0,"").)

Ответ 3

С тех пор официальная страница руководства я бы сказал, что ее точное возвращаемое значение не указано. Если в документации Perl говорится о логическом значении, тогда он почти всегда говорит об оценке указанного значения в булевом контексте: if (defined ...) или print while <> и т.д. В таких контекстах несколько значений оцениваются как false: 0, undef, "" (пустые строки), даже строки, равные "0".

Все остальные значения оцениваются как истинные в булевом контексте, включая печально известный пример "0 but true".

Поскольку документация такова, что я не полагался бы на defined(), возвращающее какое-либо конкретное значение для случая undefined. Тем не менее, вы всегда будете в порядке, если просто используете defined() в булевом контексте, не сравнивая его с определенным значением.

ОК: print "yes\n" if defined($var)

Не переносимое/будущее доказательство: print "yes\n" if defined($var) eq '' или что-то подобное

Ответ 4

Вероятно, он никогда не изменится, но perl не указывает точное логическое значение, возвращаемое defined(...).

При использовании логических значений хороший код не должен зависеть от фактического значения, используемого для true и false.

Пример:

# not so great code:
my $bool = 0;   #
...
if (some condition) {
  $bool = 1;
}

if ($bool == 1) { ... }

# better code:
my $bool;       # default value is undef which is false

$bool = some condition;

if ($bool) { ... }

99,9% времени, когда нет причин заботиться о значении, используемом для булевых. Тем не менее, есть некоторые случаи, когда лучше использовать явное 0 или 1 вместо булевой величины. Пример:

sub foo {
    my $object = shift;
    ...
    my $bool = $object;
    ...
    return $bool;
}

предполагается, что foo() вызывается с ссылкой или undef и должен возвращать значение false, если $object не определено. Проблема в том, что если $object определен foo(), он вернет сам объект и, таким образом, создаст другую ссылку на объект, и это может помешать его сборке мусора. Поэтому здесь было бы лучше использовать явное логическое значение здесь, то есть:

  my $bool = $object ? 1 : 0;

Поэтому будьте осторожны с использованием самой ссылки для представления ее правдоподобия (т.е. ее определяемой) из-за возможности создания нежелательных ссылок на ссылку.