[英]How do I interact with a Perl object that has a hash attribute?
我有一個包含多個變量的類,其中一個是散列(_runs):
sub new
{
my ($class, $name) = @_;
my $self = {
_name => $name,
...
_runs => (),
_times => [],
...
};
bless ($self, $class);
return $self;
}
現在,我要做的就是創建一個訪問器/ mutator,以及另一個將新數據推入哈希的子例程。 但我有一段時間讓所有引用/解除引用/ $ self調用一起工作。 我用“不能使用字符串(”blah“)作為HASH ref等等”燒毀我的眼睛“錯誤。
對於訪問者來說,返回哈希的“最佳實踐”是什么? 我應該使用以下哪個選項(如果有的話)?:
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數組,但是模仿我的數組語法到哈希沒有用。
您正在對象中存儲對數組或哈希的引用。 要將它們與標准函數一起使用,您需要取消引用它們。 例如:
@{ $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}
快捷方式(如果您第一次看到它,可能$self->{_hash_ref_key}->{$hash_key}
意義)。
另請查看相應的手冊頁 。
不妨接受我的評論,並從中做出正確的答案。 我將准確說明您的示例代碼失敗的原因。
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
編譯指示。)
現在對於guts部分:哈希值必須是標量值。 數組和散列不是; 但是對它們的引用是。 從而:
my $self = {
_name => $name,
_runs => {},
_times => [],
};
首先,您必須弄清楚您實際想要返回的內容以及您希望更高級別能夠處理數據的內容。
如果要返回數據的副本或對返回的數據的任何更改不影響對象中的副本,則不能執行其他答案告訴您的簡單解決方案,因為它們返回仍將共享的淺副本內部參考。 您需要進行深層復制,然后返回斷開連接的數據結構。 可存儲使這個容易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} = {};
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.