2010-10-01 63 views
5

我是一個絕對新手Moose到目前爲止,我已經閱讀MooseCookbook的大部分。如何訪問Moose對象的只讀屬性?

有幾件事我不明白。我創建了以下包:

package MyRange; 

use Moose; 
use namespace::autoclean; 

has [ 'start', 'end' ] => (
    is  => 'ro', 
    isa  => 'Int', 
    required => 1, 
); 

__PACKAGE__->meta->make_immutable; 

1; 

然後:

use MyRange;  
my $br = MyRange->new(
    start    => 100, 
    end     => 180 
); 

現在,我可以使用例如訪問我的領域$br->{start},但我也可以使用它們修改它們(雖然它們是「只讀」的)。 $br->{start}=5000。我還可以添加新的密鑰,如$br->{xxx}=111

我錯過了什麼?不是以某種方式保護對象嗎? ro是什麼意思?

回答

14

當你說is => 'ro'時,你告訴Moose爲你創建只讀訪問器,也就是讀者方法。你叫,作爲

$br->start; 

$br->end; 

使用這些方法會導致異常設置屬性:

$br->start(42); 

如果您用過is => 'rw',然後上面會工作,更新屬性的值。

你在做什麼是對對象的直接散列訪問,這違反了封裝並且在使用Moose時不應該是必需的。

Moose手冊即Moose::Manual命名空間下的所有文檔都詳細解釋了這一點。這樣的問題很好的起點可能是Moose::Manual::Attributes

+0

+1謝謝!後續行動,如果我可以:我有一些不需要的領域。如果它們沒有設置,並且我嘗試訪問那些'undef'值,我想得到一個錯誤。我應該爲他們每個人設置一個閱讀器嗎?或者也許在'default'中使用一些'die'類的sub? – 2010-10-01 13:57:28

+1

您可能希望爲此更詳細的回答創建一個新問題,但是:您是否有一種設計,其中最初不需要值,但用戶可以稍後使用編寫器方法填寫它們,並且必須在調用之前執行此操作一些使用它的功能?大多數情況下,您應該重新考慮您的設計,但在極少數情況下,我的'MooseX :: LazyRequire'擴展可能會有所幫助。所做的一切都是要求一個屬性,但是將異常從施工時間推遲到訪問attr的時間。 – rafl 2010-10-01 14:02:12

+0

另外請注意,您可以要求Moose爲您生成謂詞方法。那些可以用來明確檢查是否已經通過構造函數或寫入方法爲某個屬性設置了值的函數。這對於不需要的屬性以及'undef'是有效值的屬性來說尤其方便。 – rafl 2010-10-01 14:03:24

3

當您訪問$br->{start}的屬性時,您繞過了訪問器,並且您正在直接調用底層的Moose實現。你可以做到,但你不應該這樣做。另外,如果Moose更改了實現,您的代碼將會中斷。

你應該使用存取方法,而不是訪問屬性:

my $start = $br->start; 

當你說的屬性爲「RO」,這意味着你不能使用訪問更改的屬性值:

$br->start(32);