Wie entscheidet Perl eine skalare als String oder eine Zahl zu behandeln?
Frage
Betrachten Sie den folgenden Code ein, und sein Ausgang:
Code
#!/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 );
Output
$VAR1 = 24;
$VAR1 = '1.7';
$VAR1 = 1000;
$VAR1 = 480;
Wie Sie sehen können, ist die zweite Variable als Strings behandelt, während die ersten und die viert diejenigen als Zahlen behandelt werden. Jeder hat eine Vorstellung davon, was die zugrunde liegende Logik ist?
Bearbeiten arithmetische Berechnungen, die hinzugefügt wurden nicht vollständig das Problem lösen (siehe $ BSA Variable).
$ 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
Lösung
Data :: Dumper Aufgabe ist es Daten serialisiert werden und man kann nicht viel sagen über das, was Perl intern mit den Daten auf seinem Ausgang auf Basis tun. Die Devel :: Peek Modul kann Dump die zugrunde liegenden Fahnen und in den Variablen gespeicherten Werte. Die Devel :: Peek POD erklärt die Bedeutung der Fahnen.
#!/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
Andere Tipps
Ihr gesamtes Konzept der Perl-Variablen als Strings oder Zahlen Behandlung ist fehlerhaft. Perl wird Ihre Variablen die richtige Art und Weise zu behandeln, wenn Sie es brauchen beispielsweise arithmetische Operatoren immer , um ihre Argumentation als Zahlen behandeln (vorausgesetzt, Sie missbrauchen Bediener nicht oder so eine Überlastung).
Sie sollten sich keine Sorgen darüber. Perl weiß, was es tut,
Data :: Dumper ist ein einfaches Muster auf der String-Darstellung der Variablen, um festzustellen, ob es eine Zahl ist. Aus dem Quellcode:
...
elsif ($val =~ /^(?:0|-?[1-9]\d{0,8})\z/) { # safe decimal number
$out .= $val;
}
else { # string
...
Dies gilt nicht Zahlen überein, die eine Dezimalstelle, die das Verhalten erklären Sie beobachtet.
Schnell schmutzige Art und Weise einen numerischen Kontext zu erzwingen:
print Dumper( $HOURS_DURATION + 0.0 );
Wenn Ihr Anliegen ist, wie die Daten dann angezeigt werden, die saubere Art und Weise ist: -
printf "%5.2d",$HOURS_DURATION;