1. Особенности работы с переменными и литералами в Perl6
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. А пока что для начала освоения языка хватит и описанного.
Автор: WarFair