Расширение вывода Perl Data::Dumper

У меня есть несколько вложенных структур данных, которые ссылаются на элементы друг друга. Я хотел бы иметь возможность проверять эти ссылки, поэтому я ищу что-то, что будет печатать адрес памяти вложенных структур. Вариант для Data::Dumper был бы в порядке.

Вот несколько примеров того, что я имею в виду:

my @a = ( [1,2,3], [4,5,6] );
print \@a;

Даст вам что-то вроде:

ARRAY(0x20071dc8)

Когда вы запускаете тот же код через отладчик и проверяете массив с помощью x \@a, он напечатает это:

0  ARRAY(0x20070668)
   0  ARRAY(0x2006c0d8)
      0  1
      1  2
      2  3
   1  ARRAY(0x2006c1b0)
      0  4
      1  5
      2  6

Но используя Data::Dumper

print Dumper \@a;

Это выглядит так

$VAR1 = [
          [
            1,
            2,
            3
          ],
          [
            4,
            5,
            6
          ]
        ];

Что мне действительно нужно, так это смесь вывода Data::Dumper и деталей, которые предоставляет отладчик. Возможно это

$VAR1 = [ ARRAY(0x20070668)
          [ ARRAY(0x2006c0d8)
            1,
            2,
            3
          ],
          [ ARRAY(0x2006c1b0)
            4,
            5,
            6
          ]
        ];

Изменить

Рассмотрим этот код. Вывод не объясняет, что $b[1] является той же ссылкой, что и в $a[0].

use Data::Dumper;

my @a = ( [1,2,3], [4,5,6] );
my @b = ( ["a","b","c"], $a[0] );

print Dumper \@b

print $b[1], "\n";
print $a[0], "\n";

вывод

$VAR1 = [
          [
            'a',
            'b',
            'c'
          ],
          [
            1,
            2,
            3
          ]
        ];


ARRAY(0x2002bcc0)
ARRAY(0x2002bcc0)

Кроме того, считается ли такой подход, когда одна структура ссылается на содержимое другой, хорошей практикой программирования? Возможно, это слишком общий вопрос и сильно зависит от конкретного кода, но я хотел бы знать ваше мнение.


person Wakan Tanka    schedule 11.08.2014    source источник


Ответы (2)


Data::Dumper уже сообщит, используется ли ссылка повторно.

В следующем примере 2-й и 3-й элементы AoA идентичны. Это представлено в выводе Dumper:

use strict;
use warnings;

my @array1 = (1..3);
my @array2 = (4..6);

my @AoA = (\@array1, \@array2, \@array2);

use Data::Dumper;
print Dumper \@AoA;

Выходы:

$VAR1 = [
          [
            1,
            2,
            3
          ],
          [
            4,
            5,
            6
          ],
          $VAR1->[1]
        ];

Ответ на ваше редактирование

Если вы хотите найти связь между двумя разными структурами данных, просто сделайте один вызов Dumper с обеими структурами данных.

Вы можете сделать это, передав их как список или как значения в другой анонимной структуре данных, такой как хэш или массив:

use strict;
use warnings;

my @a = ([1,2,3], [4,5,6]);
my @b = (["a","b","c"], $a[0]);

use Data::Dumper;

print Dumper(\@a, \@b);

Выходы:

$VAR1 = [
          [
            1,
            2,
            3
          ],
          [
            4,
            5,
            6
          ]
        ];
$VAR2 = [
          [
            'a',
            'b',
            'c'
          ],
          $VAR1->[0]
        ];
person Miller    schedule 11.08.2014
comment
Да, но когда у вас есть перекрестные ссылки между другими вложенными структурами, это ничего не говорит об этом. - person Wakan Tanka; 11.08.2014
comment
Dumper($var1, $var2) на самом деле будет достаточно - person ikegami; 12.08.2014
comment
Вы можете найти $Data::Dumper::Purity = 1; полезным. - person ikegami; 12.08.2014
comment
Да, оба эти совета полезны. Последнее напоминает мне, что это еще одна причина, по которой я предпочитаю Data::Dump, так как это делает Purity по умолчанию. - person Miller; 12.08.2014
comment
Значения Data::Dumper по умолчанию ужасны :( Useqq, Sortkeys, Purity должны быть 1. - person ikegami; 12.08.2014
comment
@Miller: Data::Dump также довольно точно отвечает на этот вопрос. - person Borodin; 12.08.2014
comment
@Borodin: Хорошее решение. Да, мне определенно нравится продвигать Data::Dump, но я постараюсь сбалансировать это, позволив ОП также указать некоторые предпочтения. Ваше решение хорошо отвечает на конкретный вопрос ОП. Должен сказать, однако, что цель перечисления ссылок на массив кажется мне проблемой XY, и что более читаемый формат позволяет Data::Dumper или Data::Dump показывать связь между структурами данных, просто сбрасывая их вместе. - person Miller; 12.08.2014

Я считаю, что слишком мало внимания уделяется Data::Dump. Он написан Gisle Aas, автором замечательного LWP набора модулей.

Это поможет вам в этом случае, потому что есть сопутствующий модуль Data::Dump::Filtered, который позволяет вам предоставить обратный вызов, чтобы точно указать, как каждый элемент должен отображаться в дампе.

Эта программа использует данные в вашем вопросе в качестве примера. Он использует обратный вызов, который добавляет строковую версию ссылки в качестве комментария Perl перед отображением каждого массива. Дамп очень похож на ваше требование, и в качестве бонуса это все еще действующий код Perl, который при необходимости можно передать через eval.

Обратите внимание, что весь вывод дампа отправляется в STDERR, поэтому я вызвал select STDERR, чтобы синхронизировать вывод print с дампами.

use strict;
use warnings;

use Data::Dump::Filtered qw/ dump_filtered /;

my @a = ( [1,2,3], [4,5,6] );
my @b = ( [ qw/ a b c / ], $a[0] );

select STDERR;

dump_filtered(\@a, \&filter);
print "\n";

dump_filtered(\@b, \&filter);
print "\n";

print '$b[1] is ', $b[1], "\n";
print '$a[0] is ', $a[0], "\n";

sub filter {
  my ($thing, $ref) = @_;
  return { comment => "$ref" } if $thing->is_array;
}

вывод

# ARRAY(0x45179c)
[
  # ARRAY(0xa2d36c)
  [1, 2, 3],
  # ARRAY(0x44adc4)
  [4, 5, 6],
]

# ARRAY(0x4e6964)
[
  # ARRAY(0xa2d534)
  ["a", "b", "c"],
  # ARRAY(0xa2d36c)
  [1, 2, 3],
]

$b[1] is ARRAY(0xa2d36c)
$a[0] is ARRAY(0xa2d36c)
person Borodin    schedule 11.08.2014