Smalltalk в примерах/Управляющие структуры

Современные языки программирования предоставляют способы для выполнения кода условно и для повторения блоков кода. В C, есть \verb|if () {},| \verb|if () {} else {},| \verb|do {} while (),| \verb|while () {},| и \verb|for (;;) {}|. Конструкции такого типа обычно являются частью языка.


Однако в Smalltalk сам не содержит эти конструкции. Вместо этого они создаются путём посылки сообщений объектам. В результатом чего появляется возможность изменять работу управляющих сообщений если тебя не устраивает способ их работы (не рекомендуется!). Если тебе нужна новая управляющая структура, ты можешь написать её. Например, в Smalltalk нет сообщения переключатель/случай, таким образом если ты думаешь, что оно тебе нужно, ты можешь написать его (опять же этого не рекомендуется делать по причинам, изложенным в Главе ---, ---). Фактически, ты вероятно не нуждаешься в управляющих структурах, отличных от присутствующих в стандартной библиотеке Smalltalk. Давай рассмотрим эти структуры.


Условное выполнениеПравить

Простейшей из условных структур является выполнение блока кода если некоторое условие истинно (или ложно). В Smalltalk есть два сообщения: одно когда условие истинно и одно когда оно ложно. Оба сообщения посылаются экземпляру класса \emph{Логический} (т.е. \emph{истина} или \emph{ложь}). Есть два основных подхода---

логическоеЗначение истина?: [некоторый код].
логическоеЗначение ложь?: [другой код].
3 < 4 истина?: [Транскрипт пс; показать: 'Истина']

Это означает, что некоторый код выполняется если условие истинно, а другой код выполняется если условие ложно. Блоки \verb|истина?:| и \verb|ложь?:| могут идти в произвольном порядке. Например, если блок \verb|истина?:| достаточно длинный, можно поместить блок \verb|ложь?:| первым.

логическоеЗначение
  истина?: [некоторый код]
  ложь?: [другой код].
логическоеЗначение
  ложь?: [некоторый код]
  истина?: [другой код].

Например,

3 < 4
  истина?: [Транскрипт пс; показать: 'Истина']
  ложь?: [Транскрипт пс; показать: 'Ложь'].

Smalltalk не предоставляет простой конструкции, аналогичной Cшной \verb|if () {}| \verb|else if () {}| \verb|else {}|. Но можно это сделать это при помощи вложенний:

логическоЗначение
  истина?: [некоторый код]
  лож?: [ логическоеЗначение2
           истина?: [некоторый код]
           лож?: [ логическоеЗначение3
                    истина?: [некоторый код]
                    лож?: [некоторый код]
                 ]
        ]

Однако, такой тип кода скорее очень процедурный чем объектно-ориентированный. Если вы заметите, что пишете код в подобном стиле, то возможно настало время подумать о том, как вы пишете программы.


ЦиклыПравить

В Smalltalk нет циклов. Вместо этого он предоставляет эту возможность путём посылки сообщений БлокамКода. Наиболее общий тип цикла это когда цикл продолжается пока некоторое условие истинно. Так долго как значение блока (т.е. последнее предложение в блоке) \emph{истинно}, цикл будет продолжаться. Этот тип цикла подобен циклу \verb|do {} while ();| в C. Далее показан синтаксис такого цикла и пример.

[некоторый код] покаИстинен.
счётчик := 0.
[Транскрипт пс; показать: счётчик строкаДляПечати.
счётчик := счётчик +1.
счётчик < 10 ] покаИстинен.

Условие может быть противоположным так что блок будет выполняться пока его значение \emph{ложно}.

[некоторый код] покаЛож.

Следующий цикл подобен предыдущему, но если первый блок истинен второй блок выполняется. Этот тип цикла отчасти похож на цикл \verb|while () {}| языка C но он более универсальный, потому что он допускает много предложений в первом блоке. Опять рассмотрим синтаксис такого цикла и пример.

[некоторый код]
  покаИстинен:
   [следующий код]
[Dialog confirm: 'Continue']
  покаИстинен:
    [Транскрипт: пс; показать: 'Продолжаю']

Как и в предыдущем цикле ты можешь обратить условие при котором цикл продолжается.

[некоторый код]
  покаЛожен:
     [следующий код]

Последний непосредственный механизм цикла это просто повторение. Это означает что код в блоке должен заканчивать выполнение метода, или что-либо останавливает выполнение иначе ты получишь бесконечный цикл.

[некоторый код] повторять.
[(Диалог подтвердить: 'Продолжение') ложь?: [^сам].
Транскрипт пс; показать: 'Продолжаю'] повторять.

ПовторенияПравить

В Smalltalk есть три способа повторить блок заданное количество раз. Два из них используют индекс, а в оставшемся принимается что ты не беспокоишься о номере итерации. Если в цикле не имеет значения значение индекса, простейшим способом будет послать сообщение \verb|разПовторить:| с блоком в виде параметра. Например:

5 разПовторить: [Транскрипт: пс; показать: 'привет'].

Если в цикле надо знать номер итерации, ты должен послать одно из следующих двух сообщений. Если тебе нужен цикл от одного числа до другого, с единичным шагом, пошли сообщение \verb|до:делать:| с параметром в виде блока. Блок ожидает получения одного параметра --- индекса. Например,

1 до: 5 делать:
  [ :индекс | Транскрипт пс; показать: индекс строкаДляПечати ].

Если тебе нужен цикл подобный данному но тебе надо изменять индекс на единицу, ты можешь определить значение шага с помощью сообщения \verb|до:шаг:делать:|. Опять это сообщение ожидает блок и он должен ожидать получения индекса. Например,

15 до: 1 шаг: -2 делать:
  [ :индекс | Транскрипт пс; показать: индекс строкаДляПечати ].

Вопреки существованию этих сообщений, они менее полезны чем ты можешь предположить. Наиболее часто используемые циклы выполняются для совокупности объектов, и совокупности имеют мощные механизмы для выполнения циклов. Мы поговорим подробнее о циклах для совокупностей в Главе \potom, \potom.


Оптимизированные сообщенияПравить

БлокиКода используются в вышеперечисленных управляющих структурах как параметры, и иногда как получатели сообщений. БлокКода может быть помещён в переменную или может быть записан как литерал --- т.е. как код заключённый в квадратные скобки.


Если все БлокиКода участвующие в сообщениях это литеральные блоки, сообщение компилируется как подстановка т.е. посылка сообщения не используется. С другой стороны, если любой БлокКода участвующий в сообщении как переменная а не литерал, код не будет скомпилирован как подстановка и будет производиться посылка сообщения. Обычно эти сообщения компилируются как подстановка ибо большинство блоков являются литеральными.


Объектно-ориентированное мышление →