Como é que Perl decidir tratar um escalar como uma string ou um número?
Pergunta
Considere o seguinte código e sua saída:
Código
#!/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 );
saída
$VAR1 = 24;
$VAR1 = '1.7';
$VAR1 = 1000;
$VAR1 = 480;
Como você pode ver, a segunda variável é tratada como cordas, enquanto o primeiro e os mais diante são tratados como números. Alguém tem alguma idéia do que é a lógica subjacente?
Editar cálculos aritméticos que foram adicionados não resolver completamente o problema (ver a variável $ 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
Solução
O trabalho do Data :: Dumper é a dados serializar e você não pode dizer muito sobre o que perl está fazendo internamente com os dados com base em sua saída. A Devel :: Peek módulo pode despejar as bandeiras subjacentes e os valores armazenados nas variáveis. O Devel :: Peek POD explica o significado das bandeiras.
#!/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
Outras dicas
Todo o seu conceito de Perl tratar variáveis ??como strings ou números é falho. Perl irá tratar suas variáveis ??da maneira certa quando você precisa dele para, por exemplo, operadores aritméticos sempre tomar tratar seu argumento como números (supondo que você não está abusando operador de sobrecarga ou algo assim).
Você não deve se preocupar com isso: Perl sabe o que está fazendo
.Data :: Dumper está usando um padrão simples sobre a representação da cadeia da variável para determinar se ele é um número. A partir do código fonte:
...
elsif ($val =~ /^(?:0|-?[1-9]\d{0,8})\z/) { # safe decimal number
$out .= $val;
}
else { # string
...
Esta não coincidir com números que têm um ponto decimal que explica o comportamento que você observou.
Quick sujo maneira de forçar um contexto numérico:
print Dumper( $HOURS_DURATION + 0.0 );
Se a sua preocupação é a forma como os dados serão exibidos, em seguida, a maneira limpa é: -
printf "%5.2d",$HOURS_DURATION;