解除Perl对象的限制并为convert_构建TO_JSON方法

解除Perl对象的限制并为convert_构建TO_JSON方法,perl,moose,moo,Perl,Moose,Moo,在中,我发现了一个简单的TO_JSON方法的建议,它是将受祝福的对象序列化为JSON所必需的 sub TO_JSON { return { %{ shift() } }; } 有人能详细解释一下它是如何工作的吗 我把它改成: sub TO_JSON { my $self = shift; # the object itself – blessed ref print STDERR Dumper $self; my %h = %{

在中,我发现了一个简单的
TO_JSON
方法的建议,它是将受祝福的对象序列化为JSON所必需的

sub TO_JSON { return { %{ shift() } }; }
有人能详细解释一下它是如何工作的吗

我把它改成:

sub TO_JSON {
        my $self = shift;         # the object itself – blessed ref
        print STDERR Dumper $self;

        my %h = %{ $self };       # Somehow unblesses $self. WHY???
        print STDERR Dumper \%h;  # same as $self, only unblessed

        return { %h };    # Returns a hashref that contains a hash.
        #return \%h;      # Why not this? Works too…
}
许多问题…:(简单地说,我无法理解3行Perl代码(

我需要
到_JSON
,但它会过滤掉:

  • 不需要的属性和
  • 也取消设置属性(例如,对于那些
    具有${attr}
    谓词返回false的属性)
这是我的代码-它可以工作,但我真的不明白为什么无偏见的工作

use 5.010;
use warnings;
use Data::Dumper;

package Some;
use Moo;

has $_ => ( is => 'rw', predicate => 1,) for (qw(a1 a2 nn xx));

sub TO_JSON {
    my $self = shift;
    my $href;
    $href->{$_} = $self->$_ for( grep {!/xx/} keys %$self );
    # Same mysterious unblessing. The `keys` automagically filters out
    # “unset” attributes without the need of call of the has_${attr}
    # predicate… WHY?
    return $href;
}

package main;
use JSON;
use Data::Dumper;

my @objs = map { Some->new(a1 => "a1-$_", a2 => "a2-$_", xx=>"xx-$_") } (1..2);
my $data = {arr => \@objs};
#say Dumper $data;
say JSON->new->allow_blessed->convert_blessed->utf8->pretty->encode($data);
编辑:澄清问题:

  • %{$hRef}
    解除了
    $hRef
    的限制(获取引用指向的哈希),但是为什么要从受祝福的对象引用
    $self
    获取普通哈希呢
  • 换句话说,为什么
    $self
    是hashref
  • 我试着制作一个像
    @{$self}{grep{!/xx/}keys%$self}
    这样的散列片,但它不起作用。因此我创建了一个可怕的
    来处理JSON
  • 如果
    $self
    是一个hashref,为什么
    键%$self
    只返回具有值的属性,而不是所有声明的属性(例如
    nn
    也–请参见
    has

在您的
TO_JSON()
函数中,
{%h}
返回一个浅哈希副本,而
\%h
返回一个对
%h
的引用(无复制)。

Perl实现的面向对象方法是简单地让引用知道它来自哪个包(使用
bless
).知道引用来自
Foo
包意味着方法实际上是该包中定义的函数

Perl允许任何类型的引用被祝福;不仅仅是散列引用。祝福散列引用是很常见的;很多文档都显示了这一点;
Moose
做到了;但是,祝福数组引用、子例程引用、文件句柄或标量引用也是可能的tax
%{$self}
仅对哈希引用(受祝福或不受祝福)有效。它接受哈希引用,并将其作为哈希解引用。原始引用可能已受祝福的事实将丢失

我需要TO_JSON,但会过滤掉什么:

  • 不需要的属性
  • 以及unset属性(例如,对于那些has${attr}谓词返回false的属性)
在5.20之前,哈希片只提供原始哈希中的值,而不是键。您需要键和值

假设您有一个散列,并且想要过滤掉不在白名单上的
undef
值和键,那么有几个选项。下面是我使用模块得到的:

map
s和
grep
s并不一定漂亮,但这是我能想到的过滤掉不在白名单上的键和没有
undef
值的元素的最简单方法

您可以使用数组切片:

use strict;
use warnings;
use JSON;

my $foo = { foo => undef, bar => 'baz', quux => 5 };
my @whitelist = qw{foo bar};

my %filtered_on_keys;
@filtered_on_keys{@whitelist} = @$foo{@whitelist};

my %bar = map { $_ => $filtered_on_keys{$_} }
          grep { defined $filtered_on_keys{$_} }
          keys %filtered_on_keys;
print to_json(\%bar) . "\n";
或者,如果您喜欢循环:

use strict;
use warnings;
use JSON;

my $foo = { foo => undef, bar => 'baz', quux => 5 };
my %whitelist = map { $_ => 1 } qw{foo bar};

my %bar;
while (my ($key, $value) = each %$foo) {
    if (defined $value && exists $whitelist{$key}) {
       $bar{$key} = $value;
    }
}

print to_json(\%bar) . "\n";
这似乎是一个很好的时间来提出拉里·沃尔的话,“Perl旨在给你几种方法做任何事情,所以考虑挑选最可读的。” 但是,我强调了一点,即并非所有对象都是散列。从对象获取数据的适当方法是通过其getter函数:

use strict;
use warnings;
use JSON;

my $foo = Foo->new({ foo => undef, bar => 'baz', quux => 5 }); # as an example

my %filtered_on_keys;
@filtered_on_keys{qw{foo bar}} = ($foo->get_foo(), $foo->get_bar());

my %bar = map { $_ => $filtered_on_keys{$_} }
          grep { defined $filtered_on_keys{$_} }
          keys %filtered_on_keys;
print to_json(\%bar) . "\n";

Thanx为您的答案-我编辑了我的问题(我希望)更清楚。无论如何,+1因为返回{%hash}的
浅哈希副本对我来说是新的,需要搜索一些关于它的文档。;)接受这个答案,因为你帮了我处理切片和“浅哈希副本”;)-应在其他问题中提出与Moo相关的问题。请注意::)第二和第四个问题与moose相关(perl OO主要使用hashref进行对象存储)。哈希片只返回值,如果我是正确的,您需要键/值对。
my%h=map{$\=>$self->{$\}}grep{!/xx/}键%$self
my%h=%$self;删除@h{grep/xx/,key%$self}
@mpapec-THANX,你的评论帮我找到了一个bug。我有Perl5.20,因此可以使用
返回{%{$self}{grep{!/xx/}键%$self}-它最终工作:)(键/值哈希片)。问题出现在第一个信号
@
中。在这种形式下,它实际上返回一个值。:)很高兴有你
use strict;
use warnings;
use JSON;

my $foo = { foo => undef, bar => 'baz', quux => 5 };
my %whitelist = map { $_ => 1 } qw{foo bar};

my %bar;
while (my ($key, $value) = each %$foo) {
    if (defined $value && exists $whitelist{$key}) {
       $bar{$key} = $value;
    }
}

print to_json(\%bar) . "\n";
use strict;
use warnings;
use JSON;

my $foo = Foo->new({ foo => undef, bar => 'baz', quux => 5 }); # as an example

my %filtered_on_keys;
@filtered_on_keys{qw{foo bar}} = ($foo->get_foo(), $foo->get_bar());

my %bar = map { $_ => $filtered_on_keys{$_} }
          grep { defined $filtered_on_keys{$_} }
          keys %filtered_on_keys;
print to_json(\%bar) . "\n";