Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

subs in progress

  • Loading branch information...
commit e335f5be4b0fb9b217a33acaf07d185c26a17da0 1 parent e16e43c
@zag authored
Showing with 323 additions and 0 deletions.
  1. +323 −0 src/subs.pod
View
323 src/subs.pod
@@ -0,0 +1,323 @@
+=begin pod
+=NAME Подпрограммы и сигнатуры
+
+X<|подпрограмма;аргументы;сигнатура;возвращаемое значение>
+
+I<Подпрограмма> представляет собой участок кода, выполняющий определенную задачу. Она может оперировать передаваемыми ей при вызове данными I(аргументами) и может производить результаты I(возвращаемые значения). I<Сигнатурой> подпрограммы является описание всех передаваемых при вызове аргументов и любых возвращаемых значений.
+
+Первая глава демонстрирует простые подпрограммы. Операторы, описанные во второй главе, являются подпрограммами, которые Perl 6 обрабатывает необычным способом. Однако, они будут описаны поверхностно насколько это возможно.
+
+=head1 Определение подпрограмм
+
+X<|подпрограммы, определение>
+
+Определение подпрограммы состоит из нескольких частей. Сперва следует декларатор C<sub>, указывающий начало определения подпрограммы. Затем - необязательное имя и необязательная сигнатура. И наконец - тело попрограммы: ограниченный фигурными скобками блок кода. Этот код выполняется каждый раз при вызове подпрограммы.
+
+К примеру, в коде:
+
+=begin code
+
+ sub panic() {
+ say "Oh no! Something has gone most terribly wrong!";
+ }
+
+=end code
+
+... определена попрограмма с именем C<panic>. Ее сигнатура отсутствует, а тело состоит их единственного оператора C<say>.
+
+X<|область видимости, подпрограммы; подпрограммы, область видимости>
+
+По умолчанию, подпрограммы ограничена областью лексической видимости, как и любая переменная объявленная с помощью C<my>. Это подразумевает, что подпрограмма может быть вызвана, только в границах той области видимости I( Как правило это блок кода ), внутри которой она была определена. Чтобы подпрограмма стала доступной внутри всего пакета используется декларатор I<(ключевое слово)> C<our>:
+
+=begin code
+ {
+ our sub eat() {
+ say "om nom nom";
+ }
+
+ sub drink() {
+ say "glug glug";
+ }
+ }
+
+ eat(); # om nom nom
+ drink(); # fails, can't drink outside of the block
+=end code
+
+C<our> также делает подпрограмму видимой вне пакета или модуля:
+
+=begin code
+ module EatAndDrink {
+ our sub eat() {
+ say "om nom nom";
+ }
+
+ sub drink() {
+ say "glug glug";
+ }
+ }
+ EatAndDrink::eat(); # om nom nom
+ EatAndDrink::drink(); # fails, not declared with "our"
+=end code
+
+Чтобы подпрограмма стала доступна в другой области видимости, используется экспорт (см. I<Экспортирование>).
+
+X<| анонимные подпрограммы; подпрограммы, анонимные; подпрограммы, первого класса>
+
+Подпрограммы в Perl 6 представляют собой объекты. Их можно передавать и хранить в составе структур данных, а так производить те же действия, что и по отношению к другим данным. Дизайнеры языков программирования часто называют их I<подпрограммами первого класса>. Они являются такими же основополагающими для использования в языке, как и хэши или массивы.
+
+Подпрограммы первого класса позволяют решать сложные задачи. Например, для создания небольшого ASCII рисунка с изображением танцующих фигур, возможно построение хэша, ключами которого будут названия движений в танце, а значениями - анонимные подпрограммы. Допустим, что пользователи могут вводить названия списки движений I<( возможно с коврика для танцев или другого экзотического устройства)>. Как можно организовать легко изменяемый список движений, а также возможно безопасно сделать проверку вводимых пользователем названий движений на предмет допустимых ? Возможно следующая структура программы станет отправной точкой для достижения результата:
+
+=begin code
+
+ my $dance = '';
+ my %moves =
+ hands-over-head => sub { $dance ~= '/o\ ' },
+ bird-arms => sub { $dance ~= '|/o\| ' },
+ left => sub { $dance ~= '>o ' },
+ right => sub { $dance ~= 'o< ' },
+ arms-up => sub { $dance ~= '\o/ ' };
+
+ my @awesome-dance = <arms-up bird-arms right hands-over-head>;
+
+ for @awesome-dance -> $move {
+ %moves{$move}.();
+ }
+
+ say $dance;
+
+=end code
+
+На основании вывода этой программы, вы сможете убедиться что танец YMCA N< Возможно имеется в виду L<Y.M.C.A.|http://en.wikipedia.org/wiki/Y.M.C.A._%28song%29>> также плохо выглядит в ASCII виде, как и в реальной жизни.
+
+=head1 Добавление сигнатур
+X<|параметры; подпрограммы, синатуры; сигнатуры, подпрограмм>
+
+Сигнатура подпрограммы решает две задачи. Во первых, она объявляет список обязательных и необязательных аргументов, передаваемых при вызове подпрограммы. Во вторых, с помощью сигнатуры объявляются переменные и их связь с аргументами подпрограммы. Эти переменные называются I<параметрами>. Сигнатуры в Perl 6 обладают дополнительными возможностями: они позволяют ограничивать значения аргументов, сравнивать и извлекать сложные структуры данных.
+
+=head2 Основы
+
+В своей простой форме сигнатура - список разделенных запятой имен переменных, с которыми связываются входные аргументы подпрограммы.
+
+=begin code
+
+ sub order-beer($type, $pints) {
+ say ($pints == 1 ?? 'A pint' !! "$pints pints") ~ " of $type, please."
+ }
+
+ order-beer('Hobgoblin', 1); # A pint of Hobgoblin, please.
+ order-beer('Zlatц+ Baе+ant', 3); # 3 pints of Zlatц+ Baе+ant, please.
+
+=end code
+
+Использование термина I<связываются> вместо I<присваиваются> весьма существенно. Переменные в сигнатуре являются ссылками в режиме "чтения" на передаваемые подпрограмме аргументы. Это делает недоступными для модификаций входные значения.
+
+Связывание в режиме "только чтение" можно отменить. Если пометить параметр атрибутом C<is rw>, то передаваемое значение можно будет изменять. Эти изменения будут применены также к оригинальным данным, передаваемым при вызове подпрограммы. В случае, если будет передан литерал или другое константное значение для C<rw> параметра, то связывание завершиться ошибкой в месте вызова подпрограммы, вызвав программное исключение:
+
+=begin code
+
+ sub make-it-more-so($it is rw) {
+ $it ~= substr($it, $it.chars - 1) x 5;
+ }
+
+ my $happy = "yay!";
+ make-it-more-so($happy);
+ say $happy; # yay!!!!!!
+ make-it-more-so("uh-oh"); # Fails; can't modify a constant
+
+=end code
+
+Также возможно создание копии передаваемых значений с помощью C<is copy>. В таком случае, данные вне подпрограммы будут защищены от модификаций, а внутри подпрограммы могут быть изменены:
+
+=begin code
+
+ sub say-it-one-higher($it is copy) {
+ $it++;
+ say $it;
+ }
+
+ my $unanswer = 41;
+ say-it-one-higher($unanswer); # 42
+ say-it-one-higher(41); # 42
+
+=end code
+
+Столь подробная маркировка изменяемых параметров может показать чрезмерной, но скорее всего вы не будете использовать эти модификаторы часто. В то время как некоторые языки требуют пометки параметров C<rw> для эмуляции возврата множественных результатов, Perl 6 позволяет напрямую возвращать несколько значений в ответе без подобных фокусов.
+
+=head2 Передача массивов, хэшей и кода
+
+Сигил переменной указывает на ее предназначение. В сигнатуре, сигил переменной ограничивает типы передаваемых аргументов. Например, сигил C<@> определяет проверку передаваемых значений на соответствие типу C<Positional> I<(Позиционный)>, который включает в себя типы наподобие C<Array> I<(массивов)> и списков. При передаче параметров нарушающих это ограничение на экран будет выведено сообщение об ошибке.
+
+=begin code
+ sub shout-them(@words) {
+ for @words -> $w {
+ print uc("$w ");
+ }
+ }
+
+ my @last_words = <do not want>;
+ shout-them(@last_words); # DO NOT WANT
+ shout-them('help'); # Fails; a string is not Positional
+
+=end code
+
+Соответственно, сигил C<%> указывает, что ожидается нечто C<Associative> I<(Ассоциативное)>, т.е. что-то позволяющее индексирование с помощью операторов C<< <...> >> или
+C<{...}>. В свою очередь сигил C<&> требует указания чего-то вызываемого, например анонимной подпрограммы. В таком случае производить вызов этого параметра можно без указания сигила C<&>:
+
+=begin code
+
+ sub do-it-lots(&it, $how-many-times) {
+ for 1..$how-many-times {
+ it();
+ }
+ }
+
+ do-it-lots(sub { say "Eating a stroopwafel" }, 10);
+
+=end code
+
+Скаляр (сигил C<&>) не имеет ограничений. Что угодно может быть связано с ним, даже если оно может связываться с другими сигилами.
+
+=head1 Интерполяция массивов и хэшей
+
+Иногда требуется заполнить позиционные аргументы значениями из массива.
+Вместо написания C<eat(@food[0], @food[1], @food[2], ...)> и так далее, вы можете линеаризовать I<(flatten)> его в список аргументов предварив вертикальной чертой: C<eat(|@food)>.
+
+Кроме того, можно интерполировать хэши в именованные аргументы:
+
+=begin code
+
+ sub order-shrimps($count, $from) {
+ say "I'd like $count pieces of shrimp from the $from, please";
+ }
+
+ my %user-preferences = ( from => 'Northern Sea' );
+ order-shrimps(3, |%user-preferences)
+
+=end code
+
+=head2 Необязатльные параметры
+
+Иногда аргументы могут быть необязятельными. Например, достаточно других параметров с их значениями по умолчанию. В таких случаях подобные небязательные параметры можно пометить как опциональные. При вызовах таких подпрограмм появляется выбор в наборе передаваемых аргументов.
+
+Либо присвоить значение параметра по умолчанию в сигнатуре :
+
+=begin code
+
+ sub order-steak($how = 'medium') {
+ say "I'd like a steak, $how";
+ }
+
+ order-steak();
+ order-steak('well done');
+
+=end code
+
+... или добавить знак вопроса к имени параметра. В последнем случае параметр получает неопределенное значение, если аргумент не передан:
+
+
+=begin code
+
+ sub order-burger($type, $side?) {
+ say "I'd like a $type burger" ~
+ ( defined($side) ?? " with a side of $side" !! "" );
+ }
+
+ order-burger("triple bacon", "deep fried onion rings");
+
+=end code
+
+=head2 Именованные параметры
+
+Когда подпрограмма имеет много параметров, зачастую, проще приязывать параметры к имени вместо к их позиции в списке передаваемых аргументов. Как следствие, порядок следования аргументов при вызове становиться неактульным:
+
+=begin code
+
+ sub order-beer($type, $pints) {
+ say ($pints == 1 ?? 'A pint' !! "$pints pints") ~ " of $type, please."
+ }
+
+ order-beer(type => 'Hobgoblin', pints => 1);
+ # A pint of Hobgoblin, please.
+
+ order-beer(pints => 3, type => 'ZlatГЅ BaЕѕant');
+ # 3 pints of ZlatГЅ BaЕѕant, please.
+
+=end code
+
+Возможно определить входной аргумент, который может быть передан только по имени, а не позиционно при вызове. Для этого перед именем параметра указывается двоеточие:
+
+=begin code
+
+ sub order-shrimps($count, :$from = 'North Sea') {
+ say "I'd like $count pieces of shrimp from the $from, please";
+ }
+
+ order-shrimps(6); # takes 'North Sea'
+ order-shrimps(4, from => 'Atlantic Ocean');
+ order-shrimps(22, 'Mediterranean Sea'); # not allowed, :$from is named only
+
+=end code
+
+В отличии от позициоанных параметров, именнованные являются необязательными по умолчанию. Чтобы слдеать именованный параметр обязательным необходимо добавить к имени параметра восклицательный знак C<!>.
+
+=begin code
+
+ sub design-ice-cream-mixture($base = 'Vanilla', :$name!) {
+ say "Creating a new recipe named $name!"
+ }
+
+ design-ice-cream-mixture(name => 'Plain');
+ design-ice-cream-mixture(base => 'Strawberry chip'); # missing $name
+
+=end code
+
+=head3 Переименование параметров
+
+Так как требуется указывать имена при передаче именованных параметров, то данные имена ялвляются частью общедоступного API подпрограмм. Выбирайте имена осторожно ! Иногда может оказаться полезным отделить имя параметра от имени переменной подпрограммы, с которой он связан:
+
+=begin code
+
+ sub announce-time(:dinner($supper) = '8pm') {
+ say "We eat dinner at $supper";
+ }
+
+ announce-time(dinner => '9pm'); # We eat dinner at 9pm
+
+=end code
+
+Параметры могут иметь несколько имен ! Если часть пользователей бритацы, а остальные - американцы, то можно написать:
+
+=begin code
+
+ sub paint-rectangle(
+ :$x = 0,
+ :$y = 0,
+ :$width = 100,
+ :$height = 50,
+ :color(:colour($c))) {
+
+ # print a piece of SVG that reprents a rectangle
+ say qq[<rect x="$x" y="$y" width="$width" height="$height"
+ style="fill: $c" />]
+ }
+
+ # both calls work the same
+ paint-rectangle :color<Blue>;
+ paint-rectangle :colour<Blue>;
+
+ # of course you can still fill the other options
+ paint-rectangle :width(30), :height(10), :colour<Blue>;
+
+=end code
+
+=head3 Альтернативный синтаксис Именованных параметров
+
+
+
+
+
+
+
+
+=end pod
Please sign in to comment.
Something went wrong with that request. Please try again.