【问题标题】:How can I make all lazy Moose features be built?如何构建所有惰性 Moose 功能?
【发布时间】:2011-05-12 15:48:50
【问题描述】:

我在 Moose 对象中有一堆惰性特性。

有些建造者需要一些时间才能完成。

我想调用所有的构建器(转储“bomplete”对象)。 我可以一次构建所有惰性功能,还是必须手动调用每个功能以使其构建器运行?

【问题讨论】:

  • 你不应该使用default吗?我认为lazy 的目的是将创建属性值推迟到第一次使用。如果您需要在对象构造时设置所有属性,default 似乎更有用。或者,您可以提供自己的BUILD 方法。
  • 这是一个相当普遍的成语,有一些正当的理由。
  • 基本上,您可以在BUILD 中完成所有工作,但最好为每个属性设置一个方法。而且,如果您要为每个属性使用一个方法来计算值,那么它也可能是一个构建器。但是,如果构建器要访问其他属性,则构建的属性需要惰性以确保它们已被初始化。并且没有“懒惰,但只有 一点点 懒惰”属性选项 :)
  • FWIW,这已经在#moose 上出现过几次,并且提出了一个新的 MX 模块来处理这个问题,有点类似于 MooseX::LazyRequire。它将允许标记属性“这是懒惰的,因为它依赖于要构建的其他属性值,但我希望它在构建完成之前被戳。”

标签: perl moose


【解决方案1】:

如果您想在构建器中使用“惰性”属性,但要确保它们的值在 new 返回之前构建,通常的做法是调用 BUILD 中的访问器。

sub BUILD {
    my ($self) = @_;

    $self->foo;
    $self->bar;
}

足以完成工作,但最好添加注释以及向不知道该习语的人解释这段看似无用的代码。

【讨论】:

    【解决方案2】:

    也许您可以使用元类来获取“惰性”属性列表。例如:

    package Test;
    
    use Moose;
    
    
    has ['attr1', 'attr2'] => ( is => 'rw', lazy_build => 1);
    has ['attr3', 'attr4'] => ( is => 'rw',);
    
    sub BUILD {
        my $self = shift;
    
    
        my $meta = $self->meta;
    
             foreach my $attribute_name ( sort $meta->get_attribute_list ) {
    
             my $attribute =  $meta->get_attribute($attribute_name);
    
            if ( $attribute->has_builder ) {
                my $code = $self->can($attribute_name);
                $self->$code;
    
            }
        }
    
    }
    
    
        sub _build_attr1 { 1 }
        sub _build_attr2 { 1 }
    

    【讨论】:

      【解决方案3】:

      过去我曾多次提出过这个确切的要求,而今天我实际上必须从元类中完成,这意味着不允许进行 BUILD 调整。无论如何,我觉得分享一下会很好,因为它基本上完全符合以太所提到的:

      '这将允许标记属性“这是懒惰的,因为它取决于 在要构建的其他属性值上,但我希望它被戳 在施工完成之前。”'

      但是,derp derp 我不知道如何制作 CPAN 模块,所以这里有一些代码: https://gist.github.com/TiMBuS/5787018

      把上面的内容放到 Late.pm 中,然后就可以这样使用了:

      package Thing;
      use Moose;
      use Late;
      
      has 'foo' => (
          is      => 'ro',
          default => sub {print "setting foo to 10\n"; 10},
      );
      
      has 'bar' => (
          is      => 'ro',
          default => sub {print 'late bar being set to ', $_[0]->foo*2, "\n"; $_[0]->foo*2},
          late    => 1,
      );
      
      #If you want..
      __PACKAGE__->meta->make_immutable;
      1;
      
      
      package main;
      
      Thing->new();
      #`bar` will be initialized to 20 right now, and always after `foo`.
      #You can even set `foo` to 'lazy' or 'late' and it will still work.
      

      【讨论】:

        猜你喜欢
        • 2021-02-07
        • 2018-09-11
        • 1970-01-01
        • 2017-08-09
        • 2012-02-21
        • 2018-11-19
        • 2018-08-29
        • 1970-01-01
        相关资源
        最近更新 更多