Получение списка полей назад от 'полевой прагмы' использования?

Таким образом, я знаком с полевой прагмой в Perl, который может использоваться для ограничения полей, которые хранятся в классе:

package Fruit;
use fields qw( color shape taste );

sub new {
  my ( $class, $params ) = @_;
  my $self = fields::new( $class ) unless ref $class;
  foreach my $name ( keys %$params ) {
    $self->{ $name } = $params->{ $name };
  }
  return $self;
}

После того как я объявил поля наверху, как я могу вернуть список, сказать, потому что я хочу генерировать средства доступа динамично? keys %FIELDS единственный путь?

Во вторую очередь существует ли более эффективный способ предварительно заполнить поля в конструкторе, чем цикличное выполнение через и присваивающий каждый параметр, как я делаю выше?

6
задан Sinan Ünür 31 March 2010 в 11:13
поделиться

3 ответа

Если вы работаете в Perl 5.10 и выше (на самом деле 5.9 и выше, но я не считаю релизы разработчиков), fields создает ограниченный хэш. См. Hash::Util для получения информации об ограниченных хэшах.

Чтобы получить все поля, доступные для ограниченного хэша, используйте функции legal_keys или legal_ref_keys:

use Hash::Util qw( legal_ref_keys );

my $froot = Fruit->new();
my @attribs = legal_ref_keys($froot);

Вы можете сделать несколько вещей для автоматической генерации ваших методов:

  1. Создать временный объект во время конструирования и запросить у него легальные ключи, чтобы вы могли создать атрибуты --- UGLY
  2. AUTOLOAD атрибуты, запросив у объекта список легальных ключей. CODE SMELL ALERT: это предполагает, что все подклассы будут использовать одну и ту же базовую структуру данных.
  3. Доступ к хэшу %FIELDS в модуле для генерации методов во время компиляции или через AUTOLOAD. MORE PROBLEMS - предполагает, что неопубликованный бит прагмы fields останется.
  4. Определить массив атрибутов во время компиляции и автогенерировать методы и устанавливать поля на основе значения.
  5. Отказаться от написания всего этого шаблона и использовать Moose.

Вариант 4:

package Fruit;
use strict; 
use warnings;

my @ATTRIBUTES;
BEGIN { @ATTRIBUTES =  qw( color shape taste ); }

use fields @ATTRIBUTES;

for my $attrib ( @ATTRIBUTES ) {
    my $getset = sub {
        my $self = shift;

        if( @_ ) {
            $self->{$attrib} = shift;
        }

        return $self->{$attrib};
    };

    {    no strict 'refs';
         *{$attrib} = $getset;
    }
}


sub new {
  my ( $class, $params ) = @_;
  my $self = fields::new( $class ) unless ref $class;
  foreach my $name ( keys %$params ) {
    $self->{ $name } = $params->{ $name };
  }
  return $self;
}

Вариант 5.

package Fruit;
use Moose;

has 'color' => (
    is => 'rw',
    isa => 'Str',
);

has 'shape' => (
    is => 'rw',
    isa => 'Str',
);

has 'taste' => (
    is => 'rw',
    isa => 'Str',
);
6
ответ дан 16 December 2019 в 21:37
поделиться

Прямо сейчас лучшее рабочее решение, которое у меня есть, это что-то вроде этого:

# Return the fields for this object
sub fields {
    my ( $self ) = @_;
    my $class = ref( $self ) || $self;
    return [ keys %{ "${class}::FIELDS" } ];
}
1
ответ дан 16 December 2019 в 21:37
поделиться

Каждый объект, созданный с использованием прагмы fields , будет иметь эти поля (и только эти поля), даже если вы их не инициализируете. Таким образом, вам не нужно беспокоиться о том, что таблица %FIELDS устарела.

  DB<1> $apple = Fruit->new( {qw(color red shape apple taste like-an-apple)} )

  DB<2> p join' ',keys %$apple
color taste shape
  DB<3> $kiwi = Fruit->new()

  DB<4> p join' ',keys %$kiwi
color taste shape
1
ответ дан 16 December 2019 в 21:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: