4

我想知道,在 Moose 中存储哈希哈希的最佳方法是什么。让我们以这样的哈希为例:

my %hash = ('step1' => {'extraction' => \$object1,
                         'analysis' => \$object2},
            'step2' => {'extraction' => \$object3,
                         'analysis' => \$object4});

但我想把这个保存在驼鹿属性中。我应该如何组织对此的访问(阅读,写作)。网络上的示例主要用于“平面”哈希。但是你可以使用像 Moose::Meta::Attribute::Native::Trait::Hash 这样的助手。散列的散列有类似的东西吗?

这样做的原因是,我想遍历步骤键并访问其中的对象实例。还是有更好的、更像 Moose 的方法来做到这一点?

提前致谢!!!

4

2 回答 2

10

您可以在 Moose 对象中存储散列的散列,其方式与存储任何其他散列的方式几乎相同:

has steps => ( is => 'ro', isa => 'HashRef' );

但是,您可以更具体地将其声明为您需要存储的特定类型的哈希,以验证存储在该插槽中的任何内容是否正确:

has steps => ( is => 'ro', isa => 'HashRef[HashRef[Object]]' );

根据数据,我也可能Object在此处更改为类名。您可以变得更花哨,并使用MooseX::TypesMooseX::Types::Structured来指定更精确的结构。

至于跨过您的结构的助手,我不知道 Moose 或 MooseX 中有什么可以做到这一点。如果您知道数据的结构,最好只实现一个子例程来自己做您需要的事情。与任何通用遍历相比,您的代码可能会表现得更好,并能更好地完成您需要的工作。

编辑/附加信息:每个 Moose 属性都会在您的类中创建一个访问器方法,该方法返回存储的值,因此访问数据是:

# Assuming we put the attribute in a package named StepTool
my $step_tool = StepTool->new(
    steps => { 'step1' => {'extraction' => \$object1,
                             'analysis' => \$object2},
               'step2' => {'extraction' => \$object3,
                             'analysis' => \$object4} },
);

# To do something one of the values
do_something($step_tool->steps->{step1}{extraction});

# To iterate over the structure, could be done in a method on StepTool
for my $step_name (keys %{ $step_tool->steps }) {
    my $step = $step_tool->steps->{ $step_name };

    for my $action_name (keys %$step) {
        my $object = $step->{ $action_name };

        do_something($object);
    }
}

# If doing the above as a method, $self is the Moose object, so...
sub traverse_steps {
    my ($self) = @_;

    for my $step_name (keys %{ $self->steps }) {
        ... # just like above
    }
}

还有一点需要注意的是,如果你愿意,你仍然可以使用traits => [ 'Hash' ]并添加一些句柄来给自己一些额外的帮助。

如果数据结构比这更自由,您可能需要查看Data::Visitor之类的东西来在子例程中迭代您的结构。(我在 Data::Visitor 上遇到了一些难以调试的奇怪问题,所以我尽量避免它。)

于 2012-08-02T11:38:13.573 回答
0

还有一种受Moose 启发的类型安全方法:如何获取对象数组?特质?

有一个类来保存具有traits => ['Hash']. 这种方法可以使用例如Arrays 和Hashes 无限深地嵌套:

package StepTool;

use Moose;

has 'steps' => (
    'is' => 'rw',
    'isa' => 'StepTool::Steps',
    'default' => sub { StepTool::Steps->new() },
);

package StepTool::Steps;

use Mouse;

has '_steps' => (
    is => 'ro',
    isa => 'HashRef[StepTool::Step]',
    traits => ['Hash'],
    default => sub { {} },
    handles => {
        # You'll probably want a fuller set here...
        get => 'get',
        set => 'set',
        keys => 'keys',
    }
);

package StepTool::Step;

use Mouse;

has 'extraction' => (
    is => 'rw',
);

has 'analysis' => (
    is => 'rw',
);

package main;

my $object1 = bless {}, 'Foobar1';
my $object2 = bless {}, 'Foobar2';
my $object3 = bless {}, 'Foobar3';
my $object4 = bless {}, 'Foobar4';

my $stepTool = StepTool->new();

# set up step1 one field at a time.
$stepTool->steps->set('step1', StepTool::Step->new());
# I have no idea why the OP wants references to objects
# everywhere but he does...
$stepTool->steps->get('step1')->extraction(\$object1);
$stepTool->steps->get('step1')->analysis(\$object2);

# set up step2 all at once
$stepTool->steps->set('step2', StepTool::Step->new(
    extraction => \$object3,
    analysis => \$object4
));

# or, less elegantly, initialize an entire StepTool:
my $stepTool2 = StepTool->new(
    steps => StepTool::Steps->new(
        _steps => {
            step1 => StepTool::Step->new(
                extraction => \$object1,
                analysis => \$object2
            ),
            step2 => StepTool::Step->new(
                extraction => \$object3,
                analysis => \$object4
            ),
        }
    ),
);

printf "step1->analysis is a ref to an instance of class: %s\n",
    ref(${$stepTool->steps->get('step1')->analysis});
于 2015-01-25T19:23:24.923 回答