2. Perl6 — Операции над переменными, анонимные блоки
3. Perl6 — Условные операторы, циклы
4. Perl6 — Работа с функциями
Последние несколько дней я читал раздел по работе с объектами в Perl6. К сожалению я так и не смог понять некоторые моменты, и надеюсь что те кто уже смог их понять подскажут, в чем же дело. Как и раньше, все описанные возможности будут сопровождаться небольшими экспериментами или примерами, чтобы пояснить как это работает, или как нужно использовать.
Приступим:
В Perl6 есть два возможных способа объявить класс:
-сделать весь файл описанием класса
class Name; has $.field; ... method Func() {...};
-объявить класс с помощью конструкции
class Name { has $.field; }
Можно как и в языке C++ указать лишь имя класса, дав его описание позднее:
class Name {...}; my $var = Name.new; class Name {has $.elem};
Если последней строчки не будет то произойдет ошибка при компиляции
Так же есть возможность сделать следующее:
my $className = class Name { has $.field is rw; } my $var1 = Name.new; my $var2 = $className.new; $var1.field = 10; $var2.field = 5; say $var1.field, ' ', $var2.field;
В результате увидим строку ’10 5′
Можно создать анонимный класс с помощью конструкции
my $anonClass = class :: {has $.field}; my $var = $anonClass.new;
Уже созданные переменные могут быть использованы для создания новых переменных:
my $var1 = ClassName.new; my $var2 = $var1.new;
Однако создание происходит без копирования данных.
Теперь подробнее о том что можно указывать при объявлении:
для указания поля используется ключевое слово has:
class Name { has Int $.publicMember; has $!privateMember; has @.publicArray is rw; has %!privateHash; has $.a is rw; has $.b is rw = 'Значение по умолчанию'; } my $v = Name.new; say $v.publicMember; #выведет "Int()" #$v.publicMember = 10 - Ошибка, переменная readonly #say $v!privateMember - Ошибка $v.mas = 1, 2, 3; #say $v.privateHash - Ошибка $v.a = 'new value'; say $v.b #Выведет "Значение по умолчанию"
Так же стоит отметить, что в теле метода можно изменять приватные переменные, даже если указано is readonly (Однако я не могу сказать, это так и задумано, или сказывается незаконченность вирт. машины)
Методы у классов указываются ключевым словом method:
class Name { has $!privateMember = 5; method GetPrivateMember() { return $!privateMember; } method SetPrivateMember($value) { $!privateMember = $value if $value > 0; } } my $var = Name.new; say $var.GetPrivateMember; $var.SetPrivateMember(10); $var.SetPrivateMember: 20;
Методы могут быть объявлены приватными:
method !PrivateMethod() { say 'Hello!'; }
Можно указать через какую переменную будет доступен объект (инвокант), у которого вызывается метод:
method Func($self: $param1, $param2) { $self.Func2($param1); }
Имя переменной не обязательно должно быть $self
method Func($someName: $param1, $param2) { $someName!PrivateMethod($param1); }
Если эту переменную не указывать то сам объект будет доступен как ‘self’
method Func($param1, $param2) { self.PublicMethod($param1); self!PrivateMethod($param2); }
Для вызова в теле метода другого метода этого класса используется следующая конструкция
self!PrivateMethod(); self.PublicMethod();
Например
class Name { method !A() { say "!A"; } method A($s:) { $s!A(); } method B() { self!A; self.C; say "B"; } method C() { say "C"; } }
При этом возможно делать вызовы self.A и self!A
Для доступа к полям класса в теле метода используется теже самые имена, что и при объявлении:
class Name { has $.a; has $!b; method PrintValues() { say $.a; say $!b; } }
Также можно написать self.a но нельзя написать self!b, т.к. в этом случае будет подразумеваться вызов приватного метода b, а не обращение к переменной b
Если имени класса при объявлении указать is rw то все поля, которые будут содержаться в этом классе станут доступны для записи без указания is rw для каждого поля в отдельности:
class Name is rw { has $.a; has $.b; }
Также в классах можно объявлять submethod’ы. Отличие их от обычных методов в том, что submethod наследоваться дочерним классом не будет.
Теперь о конструкторах
Можно указать какие действия выполнить при создании нового экземпляра класса:
class Name { has $.arg1 is rw = 10; has $!arg2; submethod BUILD(:$namedArg1, :$namedArg2) { self.arg1 = $namedArg1 if $namedArg1>0; $!arg2 = $namedArg2; } } my $var = Name.new(:namedArg2(200), :namedArg1<Hello>);
Есть одна вещь которая мне непонятна: мне пришлось писать self.arg1 а не $.arg1, т.к. мне выдавалась ошибка «Virtual call $.a may not be used on partially constructed objects».
Я не могу понять, так и задумано или же это просто ещё не до конца проработанная часть. Но в любом случае, такой конструктор работает нормально.
Также можно указывать деструктор, который будет вызываться автоматически GarbageCollector’ом.
submethod DESTROY() { say 'DESTROY'; }
Но на этот раз, вышеуказанной надписи при проведении экспериментов я так и не смог увидеть. Подозреваю что эта часть тоже ещё не доделана.
В Perl6 наследование организуется следующей конструкцией:
class Name {has $.a}; class Name2 is Name {has $.b}; my $var = Name2.new; say $var; #Name2.new(b => Any, a => Any)
Возможно множественное наследование, в результате которого может получиться что имена функций или полей в классах будут совпадать:
class Name { has $.a is rw = 10; has $.c is rw = 15; method A() {say "Name ", $.a;} } class Name2 { has $.b is rw = 20; has $.c is rw = 25; method A() {say "Name2 ", $.b;} } class Name3 is Name is Name2 { method A() { self.Name2::A(); say $.c; } } my $var = Name3.new; $var.a = 100; $var.b = 200; $var.A;
В данном случае будут выведены на экран две строчки:
Name2 200 15
Если не переопределять функцию A в дочернем класе, то функция Name::A перекроет функцию Name2::A, также происходит с переменной $.c
Как я понимаю строка self.Name2::A(); выполняет метод Name2::A() для объекта self, однако все мои догадки, как это работает портит тот факт, что на имя self.Name2 выдается ошибка, а так же нельзя написать self.(&Name2::A) или что-то вроде этого. Буду рад если кто-нибудь из знающих людей подскажет.
Конечно описанные здесь возможности это лишь часть из того что можно делать с объектами (например я даже не упомянул о делегировании, ролях — аналогов интерфейсов в с++), но пока что я не хотел бы так сильно углубляться в эту тему, а продолжить изучение других возможностей Perl6. А пока что для начала освоения языка хватит и описанного.
ссылка на оригинал статьи http://habrahabr.ru/post/155571/
Добавить комментарий