Perl6 — Классы

от автора

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. А пока что для начала освоения языка хватит и описанного.

ссылка на оригинал статьи http://habrahabr.ru/post/155571/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *