Perl Moo对象中空字符串到undef的自动转换

Perl Moo对象中空字符串到undef的自动转换,perl,attributes,moo,Perl,Attributes,Moo,对于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

对于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);
  };
}
但是否有“更结构化”或“更声明性”的方法来实现这一点?还有其他方法吗


下面是一个完整的示例及其实现。但运行它会产生我不理解的错误:

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.

请帮助理解错误的原因。

为什么不使用带有
强制
属性的强制?这似乎是最简单、最直接的方法

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
,它就在
强制
(链接在上面)。

这不是代码编写服务。这有助于解决特定的代码问题。请告诉我们您已经得到了什么,并解释您遇到困难的具体问题领域。我很乐意帮助您,但您还没有做任何事情,因此我不知道我能做些什么来帮助您。我已添加了我的解决方案尝试。那么您的解决方案如何无法满足您的要求?“是否有“更结构化”或“更具声明性”的方法来实现这一点?”这一问题听起来非常不清楚;如果您用代码解决了问题,您应该说明不适合您的具体技术原因,或者这变得过于宽泛/基于观点。我在实现中添加了一个完整的示例。但它产生了我不理解的错误。请帮忙