Как 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;
Другие вопросы по тегам