如何编写惰性访问器

时间:2016-08-03 19:32:19

标签: perl6

懒惰地构建属性的最佳方法是什么?

class I {
    has $!cheezeburger;

    method cheezeburger {
        given $!cheezeburger {
            when .so {return $_}
            default { 
                # build $cheezeburger, set attribute to it, return 
            }
        }
    }
}

这是很多cheezeburger。什么可能是一个不那么冗长的方式?

3 个答案:

答案 0 :(得分:5)

现有模块

有两个lazy attribute modules

普通代码

布拉德的$!cheezeburger //= do { ... };似乎是一个相当简单的解决方案,足以满足许多用例。

更好的东西?

您可能会发现#perl6民众想要或可以提供更好的东西。

最近一次严肃的#perl6讨论我在2015年5月5日,7日,20日和6月5日,8日和20日发生了关于懒惰属性初始化的讨论。搜索"将懒惰"在pages of #perl6 log with at least one "will lazy" match。这些讨论的 TL; DR 是rjbs,mst和其他Moose用户习惯了很好的延迟属性初始化,并且为Rakudo添加了一个解决方案;然后它被退出了,因为masak和其他人认为它有问题,他们认为可以在模块空间中创建好的解决方案,然后如果/当这看起来很明智的话,又回到核心。

答案 1 :(得分:4)

class A {
    has $!lazy;
    method BUILD { $!lazy := Nil };
    method lazy { $!lazy := (my $a = 42) if $!lazy =:= Nil; $!lazy }
};
my $a = A.new;
say [$a.lazy, $a.lazy];

如果$!lazy意味着保留未定义的值,则需要跳过几个循环。首先,我们将Nil绑定到$!lazy以保存容器无法容纳的值。如果$!lazy仍绑定到Nil,我们会创建一个新容器并为其分配值。如果值是不可变的,则不需要额外的容器。 $!lazy所需的任何类型约束都需要在$a上,因为约束是容器的属性而不是变量/ class-property。

答案 2 :(得分:2)

Brad给出的实用解决方案,如果属性未定义,则初始化属性应该足以满足许多情况:

class Foo {
    has $!cheezeburger;
    method cheezeburger {
        $!cheezeburger //= do { ... }
    }
}

另一种方法是使用does通过在第一次调用期间混合角色来替换访问器方法,使用黑魔法(也就是NQP操作)来访问私有属性:

class Foo {
    has $!cheezeburger;
    method cheezeburger {
        self does role {
            method cheezeburger {
                use nqp;
                nqp::getattr(self, Foo, '$!cheezeburger');
            }
        }
        $!cheezeburger = do { ... }
    }
}