Инструменты пользователя

Инструменты сайта


bb:redbook:213

2.13 Специфичные ключевые слова

1. Оператор выбора CASE

Компонентный Паскаль предлагает инструкции выбора IF ELSIF ELSE. Их можно комбинировать в произвольной последовательности и глубине. Но довольно часто случается, что выбор происходит больше, чем из одной-двух альтернатив. Бородатые компьютерщики помнят, что в начальных меню ДОСа довольно часто, для выбора пункта меню приходилось выбирать номер пункта и вводить его через клавиатуру. Так происходило интерактивное взаимодействие в эпоху чёрных экранов. Если посмотреть на исходники многих современных программ, выбор что надо сделать до сих пор построен именно так (хотя эта логика скрыта плюшками, приблудами и контролами интерфейса графического пользователя).

Так когда же нужно применять оператор выбора CASE? Должно быть выполнено два условия:

  1. Выбор надлежит сделать из более чем двух величин.
  2. Выбираемые величины должны быть однотипными – целыми или литерными.

Как использовать оператор CASE представлено ниже:

MODULE Test_case;
 
	IMPORT
		Log;
 
	PROCEDURE SelectV (v: INTEGER);
	BEGIN
		Log.String("v:="); Log.Int(v); Log.Ln;
		CASE v OF
			1..10: 	 Log.String("Малое число"); Log.Ln;
		| 11..100: Log.String("Среднее число"); Log.Ln;
		| 101..1000: Log.String("Ого! Большое число!"); Log.Ln;
		ELSE
			Log.String("Нет. Это что-то не то..."); Log.Ln;
		END;
 
	END SelectV;
 
	PROCEDURE Start*;
		VAR
			v: INTEGER;
	BEGIN
		v := 6;
		SelectV(v);
		v := 12;
		SelectV(v);
		v := 102;
		SelectV(v);
		v := - 1;
		SelectV(v);
	END Start;
 
END Test_case.

Вывод:

компилируется "Test_case" 252 0
старый модуль Test_case выгружен
v := 6
Малое число
v := 12
Среднее число
v := 102
Ого! Большое число!
v := - 1
Нет. Это что - то не то...

Как видно из текста модуля, количество веток с ELSE было бы драматически большим, пришлось бы написать больше кода, а значит риск совершения ошибки увеличивается. Кроме того, более компактная форма записи, позволяет сократить занимаемое место на экране, что положительно сказывается на понимании текста программы.

2. Ключевые слова модуля

Таких слов на данный момент рассмотрено три:

  1. MODULE [NameModule]; – обязательное ключевое слово с именем модуля. По другому компилятор никак не сможет определить к чему относится программный текст.
  2. END [NameModule]. – обязательное ключевое слово с именем модуля. По другому компилятор никак не сможет определить, где заканчивается программный код. Нельзя забывать, что за концом программного текста ещё могут быть различные элементы, как-то: коммандер (а то и не один), данные для ввода, данные для компиляции, заметки типа TODO или краткие примеры правильного использования. Кроме того, можно вставить ссылки на документацию по модулю или смежные темы.
  3. BEGIN – необязательное ключевое слово уровня модуля. Обычно, код размещённый после него – исполняется для служебных целей во время загрузки самого модуля. По возможности, не стоит использовать это логическое пространство для кода. С высокой вероятностью, это будет плохим решением.
  4. CLOSE – необязательное ключевое слово уровня модуля. Обычно, код размещённый после него – исполняется для служебных целей во время выгрузки самого модуля. Эта возможность используется ещё реже, чем BEGIN, так что с ещё большей вероятностью использование этой секции будет ещё более плохим решением.

Читатели знакомые, например, с python, обратят своё внимание, что это очень похоже на специальные методы классов init и del. И такое сходство будет не случайно. Вспоминаем, что основная единица компиляции в КП – модуль! И понятие модуля органически совмещается с понятием класса. И всё же, надо помнить, что BEGIN и CLOSE относятся к модулю, а не классу (которых в python в одном модуле может быть несколько, хотя сами же питонёры к такой практике относятся не очень хорошо).

3. Арифметические и логические операции

Здесь будут рассмотрены только обойдённые вниманием операции.

  1. MOD – бывает весьма полезная операция для поиска остатка при целочисленном делении. Можно вычислить остаток и через программное решение, но оно гарантированно будет более медленней. Пример: 5 MOD 3 = 2.
  2. DIV – также весьма полезная операция для целочисленного деления (т. е. когда оба операнда имеют целочисленный тип, и результат имеет его же). Также работает заметно быстрее, чем операции над вещественными числами. Пример: 5 DIV 3 = 1. Разумеется, точность страдает, но бывает это приемлемо.
  3. ~[число]выворачивает число. Инвертирует все биты.
  4. OR – логическое сложение чисел, бывает полезным, например, при наложении изображений. Пример: 3 OR 2 = 3.
  5. & – логическое умножение (читается «амперсанд»). Бывает полезным при, например: шифровании, обработки изображений. Пример: 5 & 3 = 1.
  6. IN – принадлежность к множеству. Не путать с параметрами на вход в процедурах! Пример: 6 in a. Где а: ARRAY 1000 OF BYTE (или ещё чего-нибудь). Если значение 6 содержится в массиве а, то результатом этого выражения будет TRUE, в противном случае FALSE.
  7. IS – принадлежность к типу. Бывает полезным узнать во время выполнения программы к какому типу относится переменная. Используется вместо с оператором выбора типа WITH . Аналогично с предыдущим ключевым словом результатом вычисления является TRUE или FALSE. Оператор IS вводит в Компонентный Паскаль возможности интроспекции (исследование «системы во внутрь»).
  8. ASSERT – оператор охраны. Вызывает системное исключение, если выражение скобках не соответствует истине. Например, ASSERT( (10<i) & (i<20), 20). Системное исключение возникнет тогда, когда i будет меньше или равно 10 и больше или равно 20.

4. Оператор WITH

Этот оператор занимает промежуточное положение между оператором контекста, оператором приндлежности к типу и оператором множественного выбора. В динамических средах бывает сложно предугадать тип «подсовываемой» переменной. И в зависимости от типа, нужно выполнять различные действия.

Например:

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) – компилятор просто откажется компилировать такой модуль.

5. Заключение

Приведённые особенности Компонентного Паскаля надо знать. Можно поспорить с тем, что, например CASE может и излишняя семантическая конструкция в языке, но опытные программисты на практическом примере покажут вам преимущества того или иного способа. Важно иметь практику, и понимание, что для чего предназначено.

В качестве самостоятельного задания, которое потребует почитать документацию, рекомендуется составить две программы с помощью IF THEN ELSE и CASE, и сравнить быстродействие на 10 ветках исполнения 1).

1)
подсказка: Time
bb/redbook/213.txt · Последнее изменение: 2020/10/29 07:08 (внешнее изменение)