在哈希中存储哈希的名称

时间:2016-04-11 20:51:27

标签: perl

假设我有哈希哈希:

my %hash_of_hashes = (
    FOO => {
        BAR => "BAZ",
    },
    ALICE => {
        BOB => "CHARLIE",
    },
);

现在我想添加一些元数据:即哈希的名称:

%hash_of_hashes = (
    FOO => {
        BAR => "BAZ",
        name => "hash_of_hashes",
    },
    ALICE => {
        BOB => "CHARLIE",
        name => "hash_of_hashes",
    },
);

我看到了this question,我可以这样做:

use Data::Dumper::Simple;
my ($var) = split /=/, Dumper(%hash_of_hashes);

但我认为该调用应该封装在自己的sub中(因为这是一个奇怪的操作)。但如果我将其放在sub中,则$var不包含'%hash_of_hashes'

sub get_hash_name{
    my $h_ref = shift;
    my ($name) = split /=/, Dumper($href);
    return $name;
}
my $name = get_hash_name(\%hash_of_hashes); # $name contains $h_ref!

有没有办法将哈希的名称添加到哈希中? (我意识到it's stupid to use a variable name in a variable,但我递归地解析哈希并需要知道“父”哈希是什么)。

2 个答案:

答案 0 :(得分:2)

Data::Dumper::Simple通过应用源过滤器来工作。它使用Filter::Simple在编译源代码之前对其进行修改,以便调用Dumper来传递参数的名称以及

我建议您错过中间人并直接使用Data::Dumper::Simple

,而不是弄乱Filter::Simple的输出。

我会写一些示例代码,但是你没有充分说明你想做什么

更新

这是一些示例代码。我假设你只是想要一个子程序,给定一个哈希,将该哈希的名称放在其中的二级哈希的元素中

模块AddName包含源过滤器和导出的子例程add_name。主程序中add_name(%xxx)add_name(\%xxx)的所有调用都转换为add_name(\%xxx, 'xxx'),因此子例程知道哈希的名称并可以轻松插入

谨防源过滤器:它们是一种非常粗略和准备好的方法,可以让你的代码按照自己的意愿行事,虽然我已经编写了一些可能出现空白的余地,但它并不是一门精确的科学,没有什么比这更简单了完全模拟perl解析器本身

AddName.pm

package AddName;

use strict;
use warnings;

use Exporter 'import';
our @EXPORT = qw/ add_name /;

use Filter::Simple sub {
    s/ \b add_name \s* \( \s* \\? %(\w+) \s* \) /add_name(\\\%$1, '$1')/gx;
};

sub add_name {
    my ($hash, $name) = @_;
    $_->{name} = $name for values %$hash;
}

1;

test.pl

use strict;
use warnings 'all';

use AddName;
use Data::Dump;

my %hash_of_hashes = (
    FOO => {
        BAR => "BAZ",
    },
    ALICE => {
        BOB => "CHARLIE",
    },
);

add_name(\%hash_of_hashes);

dd \%hash_of_hashes;

输出

{
  ALICE => { BOB => "CHARLIE", name => "hash_of_hashes" },
  FOO => { BAR => "BAZ", name => "hash_of_hashes" },
}

答案 1 :(得分:1)

当您传递对子的引用时,它所获得的全部内容 - 引用。 (如果您要传递一个完整的哈希值,它将获得一个列表。)我们无法直接从子内部的封闭范围中读取一个名称。

然而,有些模块可以完成这项工作。例如,可以使用PadWalker查看变量名称。请注意他们建议不要直接在生产代码中使用它" "。

有一个功能var_name完全符合这一特定目的。

use warnings;
use strict;
use PadWalker qw(var_name);

sub get_var_name { return var_name(1, $_[0]) }

my %hash_of_hashes = ( FOO => { BAR => "BAZ" }, ALICE => { BOB => "CHARLIE", } );

my $hash_name = get_var_name(\%hash_of_hashes);

$hash_name的字符串为%hash_of_hashes。因为你不想使用sigil

sub get_var_name { return substr var_name(1, $_[0]), 1 };

var_name(1, $_[0])返回其引用是第二个参数的变量的名称,只要该变量位于调用此函数的sub上方1级别的范围内(因此调用者&#39} ; S)

这是模块通常提供的特殊情况 - 它在给定级别(相对于调用其函数的位置)读取范围内所有变量的名称和值。参见文档。