2016-08-03 5 views
6

Каков наилучший способ создания атрибутов лениво?Как написать ленивых аксессуаров

class I { 
    has $!cheezeburger; 

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

Это очень много cheezeburger. Что может быть менее верным способом?

+4

'метод cheezeburger {$! Cheezeburger // = ...}' –

ответ

2

Прагматический решение дается Брэда, который инициализирует атрибут, если он не определен должно быть достаточно для многих случаев:

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

Другой подход будет использовать does заменить акцесора путем смешивания в роли в процессе его первый вызов, используя черную магию (ака NQP OPS), чтобы получить доступ к закрытому атрибут:

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

Мне нравится блок 'do' с определенными или равными – beasy

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, потому что ограничения являются свойством контейнера, а не переменной/классом.

+0

: \ все еще работает над этим. thx для материала – beasy

+2

Переменные могут связываться с контейнерами (через оператор присваивания '=') и неизменяемыми значениями (через оператор привязки ': ='). Чтобы понять, какие контейнеры видят https://docs.perl6.org/language/containers#Custom_containers. –

4

Существующие модули

Есть два lazy attribute modules.

Обычный код

Брэд $!cheezeburger //= do { ... }; кажется довольно прямо вперед решение, что будет хватать для многих случаев применения.

Что-то лучше?

Вы можете обнаружить, что люди # perl6 хотят или могут обеспечить что-то лучшее.

Самые последние серьезные обсуждения # perl6, о которых я знаю об инициализации ленивых атрибутов, произошли в 2015 году 5, 7, 20 и 5 июня, 8 и 20 мая. Поиск «будет ленивым» в pages of #perl6 log with at least one "will lazy" match. TL; DR из этих обсуждений состоит в том, что rjbs, mst и другие пользователи Moose были использованы для инициализации ленивых атрибутов и было добавлено решение для Rakudo; он был затем отброшен, потому что масак и другие думали, что у него проблемы, и они думали, что хорошие решения могут быть созданы в пространстве модулей, а затем снова перешли к ядру, если/когда это показалось мудрым.

Смежные вопросы