Как Perl решает рассматривать скаляр как строку или число?
Рассмотрим следующий код и его вывод:
Код
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my $HOURS_PER_DAY = 24.0 * 1.0;
my $BSA = 1.7 * 1.0;
my $MCG_PER_MG = 1000.0 * 1.0;
my $HOURS_DURATION = 20.0 * $HOURS_PER_DAY;
my $dummy = $HOURS_PER_DAY * $BSA * $MCG_PER_MG * $HOURS_DURATION;
print Dumper($HOURS_PER_DAY);
print Dumper( $BSA);
print Dumper( $MCG_PER_MG);
print Dumper( $HOURS_DURATION );
Выход
$VAR1 = 24;
$VAR1 = '1.7';
$VAR1 = 1000;
$VAR1 = 480;
Как видите, вторая переменная обрабатывается как строки, а первая и четвертая - как числа. У кого-нибудь есть идеи, что лежит в основе логики?
Редактирование арифметических вычислений, которые были добавлены, не полностью решают проблему (см. Переменную $BSA).
$ perl -v
This is perl, v5.10.0 built for cygwin-thread-multi-64int
(with 6 registered patches, see perl -V for more detail)
Copyright 1987-2007, Larry Wall
4 ответа
Задача Data:: Dumper состоит в том, чтобы сериализовать данные, и вы не можете много рассказать о том, что делает perl внутренне с данными на основе их вывода. Модуль Devel:: Peek может выводить базовые флаги и значения, хранящиеся в переменных. Devel::Peek POD объясняет значение флагов.
#!/usr/bin/perl
use warnings;
use strict;
use Devel::Peek;
my $HOURS_PER_DAY = 24.0 * 1.0;
my $BSA = 1.7 * 1.0;
my $MCG_PER_MG = 1000.0 * 1.0;
my $HOURS_DURATION = 20.0 * $HOURS_PER_DAY;
my $dummy = $HOURS_PER_DAY * $BSA * $MCG_PER_MG * $HOURS_DURATION;
Dump($HOURS_PER_DAY);
Dump($BSA);
Dump($MCG_PER_MG);
Dump($HOURS_DURATION);
__END__
SV = PVNV(0xd71ff0) at 0xd87f90
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,NOK,pIOK,pNOK)
IV = 24
NV = 24
PV = 0
SV = PVNV(0xd71fc8) at 0xd87f60
REFCNT = 1
FLAGS = (PADBUSY,PADMY,NOK,pIOK,pNOK)
IV = 1
NV = 1.7
PV = 0
SV = PVNV(0xd72040) at 0xd87f40
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,NOK,pIOK,pNOK)
IV = 1000
NV = 1000
PV = 0
SV = IV(0xd8b408) at 0xd87f30
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 480
# compare the above output to output without the assignment to $dummy:
SV = IV(0x7b0eb8) at 0x7adf90
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 24
SV = NV(0x7c7c90) at 0x7adf60
REFCNT = 1
FLAGS = (PADBUSY,PADMY,NOK,pNOK)
NV = 1.7
SV = IV(0x7b13d8) at 0x7adf40
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 1000
SV = IV(0x7b1408) at 0x7adf30
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 480
Вся ваша концепция Perl, относящаяся к переменным как к строкам или числам, неверна. Perl будет правильно обрабатывать ваши переменные, когда вам это нужно, например, арифметические операторы всегда воспринимают их аргументы как числа (при условии, что вы не злоупотребляете перегрузкой операторов или чем-то подобным).
Не беспокойтесь об этом: Perl знает, что делает.
Data::Dumper использует простой шаблон строкового представления переменной, чтобы определить, является ли это число. Из исходного кода:
...
elsif ($val =~ /^(?:0|-?[1-9]\d{0,8})\z/) { # safe decimal number
$out .= $val;
}
else { # string
...
Это не соответствует числам с десятичной точкой, которые объясняют поведение, которое вы наблюдали.
Быстрый грязный способ форсировать числовой контекст:
распечатать самосвал ( $HOURS_DURATION + 0.0);
Если вы обеспокоены тем, как данные будут отображаться, то чистый способ: -
printf "% 5.2d", $ HOURS_DURATION;