Это старая версия документа!
Компонетный Паскаль предлагает инструкции выбора 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).