2012-08-02 241 views
4

我在想,什麼是在哈斯存儲哈希哈希的最佳方式。讓我們拿這樣的哈希爲例:如何在哈希中存儲哈希哈希?

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

但我想保存這個在駝鹿屬性。我應該如何組織訪問(閱讀,寫作)。網上的例子大多是用於「平坦」的散列。但是,你可以使用像Moose :: Meta :: Attribute :: Native :: Trait :: Hash這樣的助手。哈希值是否有類似的散列值?

這樣做的原因是,我想迭代步進鍵並訪問其中的對象實例。還是有更好的,更駝鹿般的方式來做到這一點?

在此先感謝!

回答

10

可以在幾乎相同的方式在一個木對象存儲哈希散列,你會存儲任何其他哈希:

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

你可以,但是,更具體到其聲明爲特定的那種你需要存儲的方式來驗證存儲在插槽任何散列是正確的那種東西:

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

根據數據,我也可以在這裏改變Object類名。你可以更有趣,並使用MooseX::TypesMooseX::Types::Structured指定一個更嚴格的結構。

至於助手要跨越你的結構,我不知道在Moose或MooseX中做任何事情。如果你知道數據的結構,最好只實現一個子程序來完成你自己需要的功能。你的代碼可能會表現得更好,並且比任何泛型遍歷都做得更好。

編輯/附加信息:每個駝鹿屬性創建一個訪問方法無類返回存儲的值,所以訪問的數據是:

# 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這樣的東西來迭代你的子程序中的結構。 (我有一些難以調試,使用數據::遊客怪異的問題,所以我儘量避免它時,我可以。)

+0

和訪問此我必須做這樣的事'$對象 - >步驟() - > { '第一步} - > {' 提取'}'?但後來我可以改變價值,不是嗎? – user1571117 2012-08-02 12:46:12

+0

上面的編輯有幫助嗎? – zostay 2012-08-02 13:53:59

+0

是的,非常感謝 – user1571117 2012-08-02 14:23:47

0

還有一種類型安全的方法,通過Moose: How to get an array of objects? Traits?

啓發有一個類來保存具有traits => ['Hash']的外部散列(StepTool :: Steps)。這種方法可以使用例如無限深嵌套。 Array S和Hash ES:

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});