在 Perl Moo 对象中自动将空字符串转换为 undef
Automatic conversion of empty string to undef in Perl Moo objects
对于 Perl Moo 对象的某些字段,我想在将空字符串分配给具有 undef
的字段时替换空字符串。
我想要:$obj->x("")
使字段 x
未定义。
请帮助开发一个执行此操作的 Moo 扩展。
一种可行的方法:
sub make_field_undef {
my ($class, $field_name) = @_;
eval "package $class";
around $field_name => sub {
my $orig = shift;
my $self = shift;
my @args = @_;
if(@args >= 1) {
$args[0] = undef if defined $args[0] && $args[0] eq '';
}
$orig->($self, @args);
};
}
但是有 "more structured" 或 "more declarative" 方法可以做到这一点吗?还有其他方法吗?
下面是我实现的完整示例。但是 运行 它会产生我不理解的错误:
package UndefOnEmpty;
use Moo;
sub auto_undef_fields { () }
sub make_fields_undef {
my ($class) = @_;
eval "package $class";
around [$class->auto_undef_fields] => sub {
my $orig = shift;
my $self = shift;
my @args = @_;
if(@args >= 1) {
$args[0] = undef if defined $args[0] && $args[0] eq '';
}
$orig->($self, @args);
};
around 'BUILD' => {
my ($self, $args) = @_;
foreach my $field_name ($class->auto_undef_fields) {
$args->{$field_name} = undef if defined $args->{$field_name} && $args->{$field_name} eq "";
}
};
}
1;
用法示例:
#!/usr/bin/perl
package X;
use Moo;
use lib '.';
extends 'UndefOnEmpty';
use Types::Standard qw(Str Int Maybe);
use Data::Dumper;
has 'x' => (is=>'rw', isa=>Maybe[Str]);
has 'y' => (is=>'rw', isa=>Maybe[Str]);
sub auto_undef_fields { qw(x y) }
__PACKAGE__->make_fields_undef;
my $obj = X->new(x=>"");
$obj->y("");
print Dumper $obj->x, $obj->y;
错误如下:
$ ./test.pl
"my" variable $class masks earlier declaration in same scope at UndefOnEmpty.pm line 20.
"my" variable $args masks earlier declaration in same statement at UndefOnEmpty.pm line 21.
"my" variable $field_name masks earlier declaration in same statement at UndefOnEmpty.pm line 21.
"my" variable $args masks earlier declaration in same statement at UndefOnEmpty.pm line 21.
"my" variable $field_name masks earlier declaration in same statement at UndefOnEmpty.pm line 21.
syntax error at UndefOnEmpty.pm line 20, near "foreach "
Compilation failed in require at /usr/share/perl5/Module/Runtime.pm line 317.
请帮助了解错误的原因。
为什么不对 coerce
属性 in has
使用强制转换?这似乎是最简单直接的方法。
package Foo;
use Moo;
has bar => (
is => 'rw',
coerce => sub { $_[0] eq q{} ? undef : $_[0] },
);
这是对象当时的样子。
package main;
use Data::Printer;
p my $foo1 = Foo->new( bar => q{} );
p my $foo2 = Foo->new( bar => 123 );
p my $foo3 = Foo->new;
__END__
Foo {
Parents Moo::Object
public methods (2) : bar, new
private methods (0)
internals: {
bar undef
}
}
Foo {
Parents Moo::Object
public methods (2) : bar, new
private methods (0)
internals: {
bar 123
}
}
Foo {
Parents Moo::Object
public methods (2) : bar, new
private methods (0)
internals: {}
}
在 Moose 中,您还可以定义自己的类型,该类型派生自您的 Str
并具有内置强制转换。然后你可以使你的所有属性都成为那种类型并打开强制转换。
要让 Moo 表现得像那样,请查看 has
的文档和 isa
的属性,它就在 coerce
的正上方(上面已链接)。
对于 Perl Moo 对象的某些字段,我想在将空字符串分配给具有 undef
的字段时替换空字符串。
我想要:$obj->x("")
使字段 x
未定义。
请帮助开发一个执行此操作的 Moo 扩展。
一种可行的方法:
sub make_field_undef {
my ($class, $field_name) = @_;
eval "package $class";
around $field_name => sub {
my $orig = shift;
my $self = shift;
my @args = @_;
if(@args >= 1) {
$args[0] = undef if defined $args[0] && $args[0] eq '';
}
$orig->($self, @args);
};
}
但是有 "more structured" 或 "more declarative" 方法可以做到这一点吗?还有其他方法吗?
下面是我实现的完整示例。但是 运行 它会产生我不理解的错误:
package UndefOnEmpty;
use Moo;
sub auto_undef_fields { () }
sub make_fields_undef {
my ($class) = @_;
eval "package $class";
around [$class->auto_undef_fields] => sub {
my $orig = shift;
my $self = shift;
my @args = @_;
if(@args >= 1) {
$args[0] = undef if defined $args[0] && $args[0] eq '';
}
$orig->($self, @args);
};
around 'BUILD' => {
my ($self, $args) = @_;
foreach my $field_name ($class->auto_undef_fields) {
$args->{$field_name} = undef if defined $args->{$field_name} && $args->{$field_name} eq "";
}
};
}
1;
用法示例:
#!/usr/bin/perl
package X;
use Moo;
use lib '.';
extends 'UndefOnEmpty';
use Types::Standard qw(Str Int Maybe);
use Data::Dumper;
has 'x' => (is=>'rw', isa=>Maybe[Str]);
has 'y' => (is=>'rw', isa=>Maybe[Str]);
sub auto_undef_fields { qw(x y) }
__PACKAGE__->make_fields_undef;
my $obj = X->new(x=>"");
$obj->y("");
print Dumper $obj->x, $obj->y;
错误如下:
$ ./test.pl
"my" variable $class masks earlier declaration in same scope at UndefOnEmpty.pm line 20.
"my" variable $args masks earlier declaration in same statement at UndefOnEmpty.pm line 21.
"my" variable $field_name masks earlier declaration in same statement at UndefOnEmpty.pm line 21.
"my" variable $args masks earlier declaration in same statement at UndefOnEmpty.pm line 21.
"my" variable $field_name masks earlier declaration in same statement at UndefOnEmpty.pm line 21.
syntax error at UndefOnEmpty.pm line 20, near "foreach "
Compilation failed in require at /usr/share/perl5/Module/Runtime.pm line 317.
请帮助了解错误的原因。
为什么不对 coerce
属性 in has
使用强制转换?这似乎是最简单直接的方法。
package Foo;
use Moo;
has bar => (
is => 'rw',
coerce => sub { $_[0] eq q{} ? undef : $_[0] },
);
这是对象当时的样子。
package main;
use Data::Printer;
p my $foo1 = Foo->new( bar => q{} );
p my $foo2 = Foo->new( bar => 123 );
p my $foo3 = Foo->new;
__END__
Foo {
Parents Moo::Object
public methods (2) : bar, new
private methods (0)
internals: {
bar undef
}
}
Foo {
Parents Moo::Object
public methods (2) : bar, new
private methods (0)
internals: {
bar 123
}
}
Foo {
Parents Moo::Object
public methods (2) : bar, new
private methods (0)
internals: {}
}
在 Moose 中,您还可以定义自己的类型,该类型派生自您的 Str
并具有内置强制转换。然后你可以使你的所有属性都成为那种类型并打开强制转换。
要让 Moo 表现得像那样,请查看 has
的文档和 isa
的属性,它就在 coerce
的正上方(上面已链接)。