Как я могу создать внутренние (частные) переменные объекта Moose (атрибуты)?
Я бы хотел, чтобы некоторые атрибуты (возможно, это неправильный термин в этом контексте) были частными, то есть только внутренними для использования объекта - не могут быть прочитаны или записаны извне.
Например, подумайте о некоторой внутренней переменной, которая подсчитывает количество раз, когда вызывался какой-либо из множества методов.
Где и как определить такую переменную?
Ответы
Ответ 1
Moose::Manual::Attributes
показывает следующий способ создания частных атрибутов:
has '_genetic_code' => (
is => 'ro',
lazy => 1,
builder => '_build_genetic_code',
init_arg => undef,
);
Настройка init_arg
означает, что этот атрибут не может быть установлен в конструкторе. Сделайте это rw
или добавьте writer
, если вам нужно его обновить.
/I3az/
Ответ 2
Вы можете попробовать что-то вроде этого:
has 'call_counter' => (
is => 'ro',
writer => '_set_call_counter',
);
is => 'ro'
делает атрибут только для чтения. Moose генерирует геттер. Ваши методы будут использовать getter для увеличения значения, например:
sub called {
my $self = shift;
$self->_set_call_counter( $self->call_counter + 1 );
...
}
writer => '_set_call_counter'
генерирует установщик с именем _set_call_counter
. Лось не поддерживает истинные частные атрибуты. Внешний код может, технически, вызвать _set_call_counter
. Однако, по соглашению, приложения не вызывают методы, начинающиеся с подчеркивания.
Ответ 3
Я думаю, что вы хотите MooseX:: Privacy.
Perldoc сообщает вам все, что вам нужно - это добавляет новую черту к вашим атрибутам, позволяя объявить их как конфиденциальными или защищенными:
has config => (
is => 'rw',
isa => 'Some::Config',
traits => [qw/Private/],
);
Ответ 4
Алан У. Смит предоставил переменную частного класса с лексической переменной, но она разделяется всеми объектами класса. Попробуйте добавить новый объект в конец примера script:
my $c1 = CountingObject->new();
printf( "%s\n", $c1->get_count() );
# also shows a count of 10, same as $co
Использование MooseX: конфиденциальность - хороший ответ, хотя, если вы не можете, вы можете одолжить трюк из лагеря объектов с наивысшими возможностями:
package CountingObject;
use Moose;
my %cntr;
sub BUILD { my $self = shift; $cntr{$self} = 0 }
sub add_one { my $self = shift; $cntr{$self}++; }
sub get_count { my $self = shift; return $cntr{$self}; }
1;
При этом каждый счетчик объектов хранится как запись в лексическом хэше. Вышеупомянутое может быть реализовано немного более сложным образом:
package CountingObject;
use Moose;
my %cntr;
sub add_one { $cntr{$_[0]}++ }
sub get_count { return $cntr{$_[0]}||0 }
1;
Ответ 5
Мне не удалось выяснить, как сделать атрибуты Moose полностью закрытыми. Всякий раз, когда я использую has 'name' => (...);
для создания атрибута, он всегда подвергается чтению как минимум. Для элементов, которые я хочу быть действительно частными, я использую стандартные "мои" переменные внутри пакета Moose. Для быстрого примера возьмите следующий модуль "CountingObject.pm".
package CountingObject;
use Moose;
my $cntr = 0;
sub add_one { $cntr++; }
sub get_count { return $cntr; }
1;
Сценарии, которые используют этот модуль, не имеют прямого доступа к переменной $cntr. Они должны использовать методы "add_one" и "get_count", которые действуют как интерфейс для внешнего мира. Например:
#!/usr/bin/perl
### Call and create
use CountingObject;
my $co = CountingObject->new();
### This works: prints 0
printf( "%s\n", $co->get_count() );
### This works to update $cntr through the method
for (1..10) { $co->add_one(); }
### This works: prints 10
printf( "%s\n", $co->get_count() );
### Direct access won't work. These would fail:
# say $cntr;
# say $co->cntr;
Я новичок в Moose, но, насколько я могу судить, этот подход обеспечивает полностью частные переменные.