2016-12-02 2 views
3

Как и большинство вещей в Perl5, существует множество способов создания класса, который поддерживает принудительные типы пользовательских типов для своих атрибутов. Вот простой один из ссылки на массив в хэш:Тип принуждения в атрибуте класса Perl6

#!/usr/bin/env perl 

package Local::Class { 
    use Moo; 
    use Types::Standard qw(HashRef ArrayRef); 

    has set => (
    is => 'ro', 
    coerce => 1, 
    isa => HashRef->plus_coercions(
     ArrayRef, sub { return { map { $_ => 1} @{$_[0]} } }, 
    ), 
); 
} 

my $o = Local::Class->new({ set => [qw(a b b c)] }); 
# $o->set now holds { a => 1, b => 1, c => 1} 

я пытался портировать что-то вроде этого в Perl6, где, кажется, нравится то, что мне нужно, это способ заставить в Array к SetHash , До сих пор единственным способом я был в состоянии сделать это так:

#!/usr/bin/env perl6 

class Local::Class { 
    has %.set; 
    ## Wanted to have 
    # has %.set is SetHash; 
    ## but it dies with "Cannot modify an immutable SetHash" 

    submethod TWEAK (:$set) { 
    self.set = $set.SetHash; 
    } 
} 

my $o = Local::Class.new(set => [< a b b c >]); 
# $o.set now holds {:a, :b, :c} 

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

Итак, как это делается на Perl6? Каковы рекомендуемые способы (потому что я уверен, что существует более одного) для реализации принудительных типов пользовательских типов для атрибутов класса?

ответ

3

TWEAK запускается после того, как объект был проиндексирован BUILD, и именно здесь будет взорваться массив с нечетным номером.

Перемещение принуждения к BUILD времени, и все должно работать, как ожидалось:

class Local::Class { 
    has %.set; 
    submethod BUILD (:$set) { 
    %!set := $set.SetHash; 
    } 
} 

Было бы хорошо, если бы вы могли использовать Принуждение типа SetHash() параметров в сочетании с автоматической инициализацией атрибутов, но это не получится, как сигил является частью имени атрибута, а параметр не может быть % -знак, если вы хотите принять неассоциативные типы.

Однако, он отлично работает, если вы используете $ -sigilled атрибут вместо:

class Local::Class { 
    has $.set; 
    submethod BUILD (SetHash() :$!set) {} 
} 

Как @smls указывает на то, следующий вариант

class Local::Class { 
    has %.set is SetHash; 
    submethod BUILD (:$set) { 
    %!set = $set.SetHash; 
    } 
} 

, вероятно, должны работать, а вместо того, чтобы умереть с Невозможно изменить неизменяемый SetHash.

Как обходной путь для SetHash не будучи назначаемыми, вы могли бы использовать

class Local::Class { 
    has %.set is SetHash; 
    submethod BUILD (:$set) { 
    %!set{$set.SetHash.keys} = True xx *; 
    } 
} 
+2

Я думаю, что это на самом деле должен работать с 'имеет% .set является SetHash;' а, и «Невозможно изменить неизменяемый SetHash «это просто ошибка Rakudo. – smls

+1

@smls: согласовано; cf edit – Christoph

+1

'submethod BUILD (SetHash(): $ set) {%! set: = $ set}' работает также –

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