从'use fields'pragma获取字段列表?

时间:2010-03-31 03:49:16

标签: perl

所以我熟悉Perl中的fields pragma,它可以用来限制存储在类中的字段:

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 个答案:

答案 0 :(得分:6)

如果您正在使用Perl 5.10及更高版本(实际上是5.9及更高版本,但我不计算开发版本),fields会创建一个受限制的哈希。有关限制哈希的信息,请参阅Hash::Util

要使所有字段都可用于受限制的哈希,请使用legal_keyslegal_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生成方法。 更多问题 - 假设未发布的fields pragma位将保留。
  4. 在编译时定义属性数组并自动生成方法并根据值设置字段。
  5. 放弃编写所有这些样板并使用Moose。
  6. 选项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 :(得分:1)

fields pragma正在使用的位置创建的每个对象都将定义这些字段(并且只定义那些字段),即使您没有初始化它们也是如此。因此,您不必担心不推荐使用%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

答案 2 :(得分:1)

现在我拥有的最佳解决方案是这样的:

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