2010-05-26 55 views
4

我有幾個變量的一類,其中之一是一個散列(_runs):如何與具有散列屬性的Perl對象進行交互?

sub new 
{ 
    my ($class, $name) = @_; 
    my $self = { 
     _name => $name, 
     ... 
     _runs =>(), 
     _times => [], 
     ... 
    }; 
    bless ($self, $class); 
    return $self; 
} 

現在,所有我想要做的就是創建訪問/突變,以及是推動另一子程序新數據加入散列。但我有一段時間讓所有引用/解引用/ $自調用一起工作。我已經燒了我的眼睛與「不能使用字符串(」等「)作爲HASH參考等等」錯誤。

對於訪問器,返回哈希的「最佳實踐」是什麼?這其中的一個選項,我應該使用(如果有的話)?:

return $self->{_runs}; 
return %{ $self->{_runs} }; 
return \$self->{_runs}; 

此外,當我使用其他子程序中的散列類,我該用什麼語法來複制?

my @runs = $self->{_runs}; 
my @runs = %{ $self->{_runs} }; 
my @runs = $%{ $self->{_runs} }; 
my @runs = $$self->{_runs}; 

也是一樣的遍歷鍵:

foreach my $dt (keys $self->{_runs}) 
foreach my $dt (keys %{ $self->{_runs} }) 

又有怎樣實際添加的數據?

$self->{_runs}{$dt} = $duration; 
%{ $self->{_runs} }{$dt} = $duration; 
$$self->{_runs}{$dt} = $duration; 

你明白了。我一直在閱讀關於使用類的文章,以及關於引用和解引用的文章,但我似乎無法讓我的大腦同時結合知識和使用兩者。我最後得到了我的_times數組,但將我的數組語法模仿爲哈希不起作用。

+1

'_runs =>(),'這已經是錯誤了,這必須是一個hashref。 '_runs => {foo => 1,bar => 2,},' – daxim 2010-05-26 15:17:43

+0

但我在調用構造函數時不知道任何鍵,我需要一個空的散列 – brydgesk 2010-05-26 15:27:08

+3

您需要一個空的hashref。 '_runs => {},' – daxim 2010-05-26 15:30:05

回答

6

您在對象中存儲對數組或散列值的引用。要將它們用於標準函數,您需要對它們進行解引用。例如:

@{ $self->{_array_ref_key} }; 
%{ $self->{_hash_ref_key} }; 

如果您需要將參數傳遞給標準功能:

push(@{ $self->{_array_ref_key} }, $some_value); 
for my $hash_key (keys %{ $self->{_hash_ref_key} }) { 
    $self->{_hash_ref_key}{$hash_key}; ## you can access hash value by reference 
} 

而且$self->{_hash_ref_key}{$hash_key}語法是$self->{_hash_ref_key}->{$hash_key}快捷方式(這可以使意義,如果你看到它第一次)。

也看看corresponding manual page

+0

謝謝,這與上面daxim的評論相結合正是我所需要的。 – brydgesk 2010-05-26 15:39:04

5

不妨拿我的意見,並作出正確的答案。我將詳細說明你的示例代碼失敗的原因。

use warnings; 
my $self = { 
    _name => $name, 
    _runs =>(), 
    _times => [], 
}; 
bless ($self, $class); 

use Data::Dump::Streamer; DumpLex $self; 

__END__ 
Odd number of elements in anonymous hash at … 

$self = bless({ 
    _name    => undef, 
    _runs    => '_times', 
    "ARRAY(0x88dcb8)" => undef, 
}, '…'); 

列表中的所有的元素形成用於其參考散列鍵/值對將是bless編輯。 ()是一個空列表,所以你真正表達的是列表'_name', $name, '_runs', '_times', []。您可以看到_times向上移動以成爲值,並且參考[]被串化爲散列鍵。你得到警告是因爲沒有剩餘的價值;這將被自動強制爲undef。 (始終始終啓用warnings雜注。)

現在,對於內容部分:散列值必須是標量值。數組和哈希不是;但是對它們的引用是。因此:

my $self = { 
    _name => $name, 
    _runs => {}, 
    _times => [], 
}; 
+0

非常有用,感謝您的幫助。我只知道我通常將哈希初始化爲「%var =()」,所以我認爲(我知道,我知道)構造函數應該使用相同的東西。 不要以爲我可以自己發現,再次感謝。 – brydgesk 2010-05-26 16:56:26

+0

你用'my%var;'聲明散列。空列表的分配完全是多餘的。 – daxim 2010-05-27 09:57:58

3

首先,你必須弄清楚你真正想要返回什麼以及你想要更高級別能夠處理的數據。

如果您想要返回數據的副本或對返回數據的任何更改不會影響對象中的副本,則不能執行其他答案告訴您的簡單解決方案,因爲它們會返回淺複製,它仍將共享內部參考。你需要做一個深拷貝然後返回斷開的數據結構。 Storable使得這個容易dclone

use Storable qw(dclone); 

sub some_method { 
     my($self, ...) = @_; 
     ...; 
     my $clone = dclone($self->{_runs}); 
     $clone; 
     } 

如果你想要更高的水平,通過改變返回的數據結構來改變對象,只返回你已經存儲參考。你並不需要爲做任何幻想:

sub some_method { 
     my($self, ...) = @_; 
     ...; 
     $self->{_runs}; 
     } 

除此之外,它是你的工作,以創建一個接口,使人們不必在更高的層次上思考你的數據結構。你封裝的一切,所以你的實現細節不顯示自己。這樣,您可以更改實現而不會干擾較高級別的代碼(只要接口是穩定的)。

您創建一個runs方法,返回運行的列表:

sub get_run_keys { 
     my($self) = @_; 

     keys %{ $self->{_runs} }; 
     } 

或者,也許你只是想值:

sub get_run_values { 
     my($self) = @_; 

     values %{ $self->{_runs} }; 
     } 

或者,也許整個事情:

sub get_run_hash { 
     my($self) = @_; 

     $self->{_runs}; # subject to the cloning stuff I mentioned earlier 
     } 

當您想要獲取特定運行的值時,可以通過其他方法訪問它:

sub get_run { 
     my($self, $key) = @_; 

     $self->{_runs}{$key}; 
     } 

設置一個運行值相似:

sub set_run { 
     my($self, $key, $value) = @_; 

     $self->{_runs}{$key} = $value; 
     } 

現在你的更高水平的不知道在什麼基礎設施和方法名稱描述一下你正在嘗試做的如何的基礎設施,而不是必須這樣做:

foreach my $key ($self->get_run_keys) { 
    my $run = $self->get_run($key); 
    ...; 
    $self->set_run($key, $new_value); 
    } 

面向對象的設計是一個很大的話題,並且你可以做很多事情。這足以讓你開始。您也可以包裝其他操作:

sub does_run_exist { 
     my($self, $key) = @_; 

     exists $self->{_runs}{$key}; 
     } 

sub delete_runs { 
     my($self, @keys) = @_; 

     delete $self->{_runs}{$key} foreach my $keys (@keys); 
     } 

sub reset_runs { 
     my($self, $key) = @_; 

     $self->{_runs} = {}; 
     } 
相關問題