在this answer中,我找到了一个简单的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代码。;(
我需要TO_JSON
,但会过滤掉:
has_${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}
这样的哈希切片,但它没有用。因此我创造了那个可怕的TO_JSON
。$self
是hashref,为什么keys %$self
只返回具有值的属性,而不是所有声明的属性(例如nn
) - 请参阅has
)?答案 0 :(得分:8)
sub TO_JSON { return { %{ shift() } }; }
| | |
| | L_ 1. pull first parameter from `@_`
| | (hashref/blessed or not)
| |
| L____ 2. dereference hash (returns key/value list)
|
L______ 3. return hashref assembled out of list
在TO_JSON()
函数{ %h }
中返回浅哈希副本,而\%h
返回对%h
的引用(不复制)。
答案 1 :(得分:5)
Perl通过简单地使引用可以知道它来自哪个包(使用bless
)来实现面向对象。知道引用来自Foo
包意味着方法实际上是在该包中定义的函数。
Perl允许任何类型的引用获得祝福; 不仅仅是哈希引用。保佑哈希引用很常见;很多文档都说明了这一点;并且Moose
做到了;但是,可以祝福数组引用,子程序引用,文件句柄或对标量的引用。语法%{$self}
仅适用于哈希引用(祝福与否)。它接受哈希引用,并将其解引用为哈希。原始参考可能已被祝福的事实已经丢失。
我需要TO_JSON,但会过滤掉什么:
- 不受欢迎的属性
- 和取消设置属性(例如,对于那些_ $ {attr}谓词返回false。
5.20之前,散列片仅为您提供值,而不是原始散列中的键。你想要键和值。
假设您有一个哈希值,并希望过滤掉undef
值并且不在白名单上的键,则有几个选项。这是我的所有内容,使用JSON
模块:
use strict; # well, I used "use v5.18", but I don't know which version of Perl you're using
use warnings;
use JSON;
my $foo = { foo => undef, bar => 'baz', quux => 5 };
my %whitelist = map { $_, 1 } qw{foo bar};
my %bar = map { $_ => $foo->{$_} }
grep { defined $foo->{$_} && exists $whitelist{$_} }
keys %$foo;
print to_json(\%bar) . "\n";
# well, I used say() instead of print(), but I don't know which version of Perl you're using
map
和grep
并不一定非常漂亮,但这是我能想到的最简单的方法来过滤不在白名单上的键和没有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";