Как я могу заставить Perl хранить целые числа в виде чисел вместо строк? - PullRequest
3 голосов
/ 03 июля 2019

Я разбираю много чисел из текстового файла в хеш-записи, состоящие из ключа и соответствующей ссылки на массив значений. Используя Devel :: Peek и Devel :: Size, я заметил, что строковое представление чисел хранится в этой структуре данных, которая тратит память. Как я могу избавить память от этих строковых представлений (другими словами, как я могу превратить PVIV в IV)?

Ответы [ 2 ]

4 голосов
/ 03 июля 2019

Применить к ним оператор нумерации 0+.

use strict;
use warnings;
use Devel::Peek;

# PVIVs (strings that were used in a numeric context)
my @values = grep 0+$_, qw/123 234/;
my %hash = ( "key" => [ @values ] );
Dump \%hash;
# make them just IVs
%hash = ( "key" => [ map 0+$_, @values ] );
Dump \%hash;

Выход:

SV = IV(0x7fcaf401d9d0) at 0x7fcaf401d9e0
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x7fcaf4025290
  SV = PVHV(0x7fcaf400ac60) at 0x7fcaf4025290
    REFCNT = 2
    FLAGS = (SHAREKEYS)
    ARRAY = 0x7fcaf3c1ad00  (0:7, 1:1)
    hash quality = 100.0%
    KEYS = 1
    FILL = 1
    MAX = 7
    Elt "key" HASH = 0x11e2db55
    SV = IV(0x7fcaf401d928) at 0x7fcaf401d938
      REFCNT = 1
      FLAGS = (ROK)
      RV = 0x7fcaf401d908
      SV = PVAV(0x7fcaf4005c58) at 0x7fcaf401d908
        REFCNT = 1
        FLAGS = ()
        ARRAY = 0x7fcaf3c04550
        FILL = 1
        MAX = 1
        FLAGS = (REAL)
        Elt No. 0
        SV = PVIV(0x7fcaf4021080) at 0x7fcaf401d920
          REFCNT = 1
          FLAGS = (IOK,POK,IsCOW,pIOK,pPOK)
          IV = 123
          PV = 0x7fcaf3c04900 "123"\0
          CUR = 3
          LEN = 10
          COW_REFCNT = 2
        Elt No. 1
        SV = PVIV(0x7fcaf4021098) at 0x7fcaf401d950
          REFCNT = 1
          FLAGS = (IOK,POK,IsCOW,pIOK,pPOK)
          IV = 234
          PV = 0x7fcaf3c0e2b0 "234"\0
          CUR = 3
          LEN = 10
          COW_REFCNT = 2
SV = IV(0x7fcaf401d9d0) at 0x7fcaf401d9e0
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x7fcaf4025290
  SV = PVHV(0x7fcaf400ac60) at 0x7fcaf4025290
    REFCNT = 2
    FLAGS = (SHAREKEYS)
    ARRAY = 0x7fcaf3c1ad00  (0:7, 1:1)
    hash quality = 100.0%
    KEYS = 1
    FILL = 1
    MAX = 7
    Elt "key" HASH = 0x11e2db55
    SV = IV(0x7fcaf40252f8) at 0x7fcaf4025308
      REFCNT = 1
      FLAGS = (ROK)
      RV = 0x7fcaf401d9f8
      SV = PVAV(0x7fcaf4005ca8) at 0x7fcaf401d9f8
        REFCNT = 1
        FLAGS = ()
        ARRAY = 0x7fcaf3c0c6d0
        FILL = 1
        MAX = 1
        FLAGS = (REAL)
        Elt No. 0
        SV = IV(0x7fcaf401da78) at 0x7fcaf401da88
          REFCNT = 1
          FLAGS = (IOK,pIOK)
          IV = 123
        Elt No. 1
        SV = IV(0x7fcaf401da60) at 0x7fcaf401da70
          REFCNT = 1
          FLAGS = (IOK,pIOK)
          IV = 234
3 голосов
/ 04 июля 2019

Прежде всего, если вы пытаетесь сохранить память на этом уровне, Perl, вероятно, не инструмент для вас. Perl бессмысленно «тратит» память, когда обеспечивает выигрыш в скорости.

$ perl -e'
   use feature qw( say );
   use Devel::Size qw( size );

   sub f {
      my $x;
      say size($x);
      $x = "x" x 100;
      say size($x);
   }

   f() for 1..2;
'
24
134
134
134

И 0+$scalar, и int($scalar) возвращают скаляр типа SVt_IV или SVt_NV. Любой из них подойдет.

$ perl -e'
   use feature qw( say );
   use Devel::Size qw( size );
   my $x = 1234567890;
   my $y = "1234567890";
   say size($x);
   say size($y);
   say size($0+$y);
   say size(int($y));
'
24
44
24
24

Невозможно понизить версию существующего скаляра, но вы можете заменить его с помощью «псевдонимов».

$ perl -e'
   use feature qw( say );
   use experimental qw( refaliasing );
   use Devel::Size qw( size );
   my $x = 1234567890;
   my $y = "1234567890";
   say size($x);
   say size($y);
   \$y = \(0+$y);
   say size($y);
'
24
44
24
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...