Возвращение списка полей из прагмы «Использовать поля»? - PullRequest
6 голосов
/ 31 марта 2010

Итак, я знаком с прагмой fields в 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 единственный путь?

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

Ответы [ 3 ]

6 голосов
/ 31 марта 2010

Если вы работаете в 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 атрибутов путем запроса объекта для списка легальных ключей. ПРЕДУПРЕЖДЕНИЕ О КОДЕКСОМ: это предполагает, что все подклассы будут использовать одну и ту же базовую структуру данных.
  3. Доступ к хешу %FIELDS в модуле для генерации методов во время компиляции или через AUTOLOAD. БОЛЬШЕ ПРОБЛЕМ - предполагается, что неопубликованный бит прагмы fields останется.
  4. Определение массива атрибутов во время компиляции и автоматическое создание методов, а также установка полей на основе значения.
  5. Перестань писать все эти шаблоны и используй лося.

Вариант 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',
);
1 голос
/ 31 марта 2010

Сейчас лучшее рабочее решение, которое у меня есть, выглядит примерно так:

# Return the fields for this object
sub fields {
    my ( $self ) = @_;
    my $class = ref( $self ) || $self;
    return [ keys %{ "${class}::FIELDS" } ];
}
1 голос
/ 31 марта 2010

Каждый объект, созданный там, где используется прагма 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...