2010-03-31 3 views
6

Так что я знаком с fields pragma в Perl, которые могут быть использованы для ограничения поля, которые хранятся в классе:Получение списка полей из прагмы «use fields»?

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 единственный способ?

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

+1

Почему вы используете 'fields'? –

ответ

6

Если вы работаете в 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 attri но запрашивает объект для списка юридических ключей. CODE SMELL ALERT: это предполагает, что все подклассы будут использовать одну и ту же базовую структуру данных.
  3. Доступ к хешу %FIELDS в модуле для генерации методов во время компиляции или через AUTOLOAD. БОЛЬШЕ ПРОБЛЕМ - предполагает, что неопубликованный бит 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', 
); 
+1

Если они все идентичные устройства доступа к свойствам, вы можете передать arrayref в лося: package Fruit; использование Moose; моего @attrs = дш/цвета вкус форма /; имеет \ @attrs => ( есть => 'RW', иш => 'Str', ); нет лосей; – Oesor

+1

Класс :: Аксессуар в сочетании с полями прагма хорош, но в современную эпоху я просто все это запустил и пошел с Мусом. – Ether

+0

Второй и третий «Gi на поле и использовать Лось ». –

1

Каждый объект, созданный там, где используется pragma 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

Привет, mobrule - что вы используете в своем примере? Это похоже на интерактивную оболочку perl, такую ​​как irb для ruby? – makenai

+1

Хм .. только что заметил, что я не получаю такое же поведение, как и вы в соответствии с 5.10.1 - вызов ключей на% $ self или% $ apple дает мне неопределенное значение, если я специально не установил что-то.:( – makenai

+1

Это отладчик perl –

1

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

# Return the fields for this object 
sub fields { 
    my ($self) = @_; 
    my $class = ref($self) || $self; 
    return [ keys %{ "${class}::FIELDS" } ]; 
} 
+0

Я предлагаю вернуть список, а не listref, но в противном случае да, это работает. – Ether

Смежные вопросы