Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 以哈希形式从Moose类获取所有属性的更好方法_Perl_Moose - Fatal编程技术网

Perl 以哈希形式从Moose类获取所有属性的更好方法

Perl 以哈希形式从Moose类获取所有属性的更好方法,perl,moose,Perl,Moose,我想以散列形式从类中获取所有属性。 还有比这更好的方法吗? 理想情况下(?)我想说: my $hash = \%{ Diag->new( {range =>1, code => 'AB'} ) }; 但将满足于: my $d = Diag->new( {range =>1, code => 'AB'} ); my $hash = $d->hash; package Diag; use Moose; my @attrs = qw/range code

我想以散列形式从类中获取所有属性。 还有比这更好的方法吗? 理想情况下(?)我想说:

my $hash = \%{ Diag->new( {range =>1, code => 'AB'} ) };
但将满足于:

my $d = Diag->new( {range =>1, code => 'AB'} );
my $hash = $d->hash;

package Diag;
use Moose;

my @attrs = qw/range code severity source message/;

has 'range'    => ( is => 'rw', isa => 'Int' );
has 'code'     => ( is => 'rw', isa => 'String' );
has 'severity' => ( is => 'rw', isa => 'Int' );
has 'source'   => ( is => 'rw', isa => 'String' );
has 'message'  => ( is => 'rw', isa => 'String' );

sub hash {
    my $self = shift;
    my $hash = {};
    for (@attrs) {
        $hash->{$_} = $self->$_;
    }
    return $hash;
}

no Moose;
1;
编辑带字符串输出的哈希,用于打包/解包:

# Combining this attribute and the record_format would be great.
# if $self->record->format worked that would be cool.
has 'record' => (
    is => 'ro',
    isa => 'HashRef',
    default => sub {
        {  
            foo => 'A5',
            foo2 => 'A16',
        }
);

sub record_format 
{
    my $self = shift;
    my @fields = qw( foo foo2 );

    return _build_format_string($self->record, \@fields);
}

sub _build_format_string {
    return join '', map { $_[1]->{$_} } @{ $_[2] };
}
EDIT2 我发现,如果我创造了一个属性特质,我可以让它变得更好。这样,散列顺序与属性一起使用,只需要一种格式方法

package Order;
use Moose::Role;

  has order => (
      is        => 'ro',
      isa       => 'ArrayRef',
      predicate => 'has_order',
  );

Moose::Util::meta_attribute_alias('Order');
1;

package Record;
use Moose;

has 'record' => (
    traits  => [qw/Order/],
    is      => 'ro',
    isa     => 'HashRef',
    default => sub {
        {
            foo  => 'A5',
            foo2 => 'A16',
        },
        ;
    },
    order => [qw(foo foo2)]
);

sub format {
    my ( $self, $attr ) = @_;
    my $fields = $self->meta->get_attribute($attr)->order();
    return join '', map { $self->{$attr}{$_} } @$fields;
}

1;


my $r = Record->new();
print $r->format("record");
Outputs: A5A16

我更愿意将其打包成一个方法,但您的“理想”案例几乎就在那里

my $data = { %{ Diag->new( {range =>1, code => 'AB'} ) } };
%{…}
返回一个(键、值,…)列表,因此您希望
{}
从中生成一个hashref,而不是
\
(奇怪的是,这会将它转换回一个对象)

但实际上,这应该隐藏在一个方法中

my $data = Diag->new(...)->get_data;

package Diag;
...
sub get_data { return { %{$_[0]} } };
...
1;

对于纯粹的表象目的——打印出来——考虑使用一个模块,这样你就不用担心(或知道)哪些属性有什么引用作为一个值。我使用它来简化输出

my $obj = Diag->new(...);

say $obj->stringify();                           # whole object serialized

say for $obj->stringify('attr1', 'attr1', ...);  # serialized values for each

package Diag;
...
use Data::Dump qw(pp);
...
sub stringify {
    my $self = shift;
    return map { pp $self->{$_} } @_  if @_;
    return { pp %$self } }
}
如果使用本机OO,而不是
Moo
/
Moose
也会为
重载
,比如$obj使用

use overload q("") => sub { return shift->stringify() }
Moo
Moose
中,提供了
下对象的字符串化(也在打印中暗示)


通过进一步澄清,下面的代码没有解决实际问题。我会编辑,但我现在就把它留下,因为它被认为是普遍有用的

评论和问题编辑中提到,部分目的是能够检索属性的值,并进行打包。添加的代码可以做到这一点,但由于存在显式解引用,因此应添加带有
ref
的检查,以便从arrayref、hashref或string/number中正确检索所有值。比如说

sub record_format {
    my ($self, @attrs) = @_;
    @attrs = qw(attr1 attr2 ...) if not @attrs;  # default list
    my $packed;
    foreach my $attr (@attrs) {
        my $val = $self->{$attr};
        my $rv = ref $val;
        if    (not $rv)        { $packed .= $val }
        elsif ($rv eq 'HASH')  { $packed .= join '', values %$val }
        elsif ($rv eq 'ARRAY') { $packed .= join '', @$val }   
    }
    return $packed;
}
这将打包传递的属性或列出的默认值


所需的
$self->record->format
无法很好地工作,因为
$self->record
不返回对象,因此无法字符串另一个方法调用。你可以编写一个访问器,但如果你让它在任何情况下返回一个对象,这可能是一个令人惊讶的行为,因此不是一个好的设计。

这个方法通常也可以被称为
,以_JSON
,这是像
JSON
这样的模块在序列化对象时所寻找的。@simbabque很好的一点,谢谢——但不能保证它实际上是一个有效的JSON?谢谢@zdim,这正是我想要的。同样相关的是,如果您有一个包含哈希的属性,是否可以添加一个自定义toString()来格式化这些值并返回它们的字符串?因此可以调用$data->myHash->toString()@听到这个消息我很高兴:)。现在,对于这个字符串——首先,您的意思是像
attr=>{…}
(那么,一个hashref)?您显示的界面不起作用,因为
$data
是一个hashref(不是对象,如果您在这个答案中的意思是
$data
),然后
$data->myHash
是一个hashref,所以您不能对它调用方法。但是,您可以为此编写另一个方法。或者,
get_data
方法可以使用参数,例如属性名列表,它将返回序列化的值。@williamt您不能对哈希进行方法调用。您的myHash必须是一个对象。