Это старая версия документа!
Компонентный Паскаль предлагает инструкции выбора
IF ELSIF ELSE
. Их можно комбинировать в произвольной последовательности и глубине. Но довольно часто случается, что выбор происходит больше, чем из одной-двух альтернатив. Бородатые компьютерщики помнят, что в начальных меню ДОСа довольно часто, для выбора пункта меню приходилось выбирать номер пункта и вводить его через клавиатуру. Так происходило интерактивное взаимодействие в эпоху чёрных экранов. Если посмотреть на исходники многих современных программ, выбор что надо сделать до сих пор построен именно так (хотя эта логика скрыта плюшками, приблудами и контролами интерфейса графического пользователя).
Так когда же нужно применять оператор выбора
CASE
? Должно быть выполнено два условия:
Как использовать оператор
CASE
представлено ниже:
Как видно из текста модуля, количество веток с
ELSE
было бы драматически большим, пришлось бы написать больше кода, а значит риск совершения ошибки увеличивается. Кроме того, более компактная форма записи, позволяет сократить занимаемое место на экране, что положительно сказывается на понимании текста программы.
Таких слов на данный момент рассмотрено три:
Читатели знакомые, например, с python, обратят своё внимание, что это очень похоже на специальные методы классов init и del. И такое сходство будет не случайно. Вспоминаем, что основная единица компиляции в КП – модуль! И понятие модуля органически совмещается с понятием класса. [↑]
Здесь будут рассмотрены только обойдённые внимание операции.
Этот оператор занимает промежуточное положение между оператором контекста, оператором приндлежности к типу и оператором множественного выбора. В динамических средах бывает сложно предугадать тип «подсовываемой» переменной. И в зависимости от типа, нужно выполнять различные действия.
Например:
MODULE Test_case; IMPORT Log; TYPE tRecord = EXTENSIBLE RECORD x: INTEGER; y: INTEGER; END; tRecord1 = RECORD (tRecord) z: INTEGER; END; PROCEDURE SelectV (VAR v: tRecord); BEGIN WITH v: tRecord1 DO Log.String("Это тип tRecord1"); Log.Ln; | v: tRecord DO Log.String("Это тип tRecord"); Log.Ln; ELSE Log.String("Нет. Это что-то не то..."); Log.Ln; END; END SelectV; PROCEDURE Start*; VAR v: POINTER TO tRecord; v1: POINTER TO tRecord1; BEGIN NEW(v); NEW(v1); v.x := 6; SelectV(v); v1.z := 3; SelectV(v1); END Start; END Test_case.
Вывод:
компилируется "Test_case" 176 0 старый модуль Test_case выгружен Это тип tRecord Это тип tRecord1
В приведённом примере создаётся тип tRecord и наследующий его tRecord1. Процедура SelectV принимает только тип tRecord, и, теоретически, компилятор должен был грязно выругаться при попытке скомпилировать этот пример. Ведь в процедуре Start видна попытка скормить для SelectV переменную типа tRecord1 (а это уже другой тип). Но компилятор соглашается!!!
После этого в процедуре SelectV использована небольшая хитрость. Так как одна из переменных имеет тип tRecord1, то при первом вызове эта ветка будет пропущена (и это правильно, так как тип переменной – tRecord). А во втором случае выполнение пойдёт именно по первой ветке (и это тоже правильно, так как второй тип – tRecord1 является расширением tRecord). После выполнения одной из веток – другие ветки выполняться не будут.
В тоже время, необходимо обратить внимание, что если в коде попытаться передать переменную типа INTEGER (или вообще любую, не наследующую и не являющуюся типом tRecord) – компилятор просто откажется компилировать такой модуль.
Приведённые особенности Компонентного Паскаля надо знать. Можно поспорить с тем, что, например CASE может и излишняя семантическая конструкция в языке, но опытные программисты на практическом примере покажут вам преимущества того или иного способа. Важно иметь практику, и понимание, что для чего предназначено.
В качестве самостоятельного задания, которое потребует почитать документацию, рекомендуется составить две программы с помощью IF THEN ELSE и CASE, и сравнить быстродействие на 10 ветках исполнения (подсказка: Time).