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

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


bb:redbook:213

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
bb:redbook:213 [2016/09/08 09:54]
prospero78 [1. Оператор выбора CASE]
bb:redbook:213 [2020/10/29 07:08] (текущий)
Строка 2: Строка 2:
  
 ==== 1. Оператор выбора CASE ==== ==== 1. Оператор выбора CASE ====
-Компонентный Паскаль предлагает инструкции выбора ''IF ELSIF ELSE'. Их можно комбинировать в произвольной последовательности и глубине. Но довольно часто случается, что выбор происходит больше, чем из одной-двух альтернатив. Бородатые компьютерщики помнят, что в начальных меню ДОСа довольно часто, для выбора пункта меню приходилось выбирать номер пункта и вводить его через клавиатуру. Так происходило интерактивное взаимодействие в эпоху чёрных экранов. Если посмотреть на исходники многих современных программ, выбор //что надо сделать// до сих пор построен именно так (хотя эта логика скрыта //плюшками//, //приблудами// и //контролами// интерфейса графического пользователя).+Компонентный Паскаль предлагает инструкции выбора ''IF ELSIF ELSE''. Их можно комбинировать в произвольной последовательности и глубине. Но довольно часто случается, что выбор происходит больше, чем из одной-двух альтернатив. Бородатые компьютерщики помнят, что в начальных меню ДОСа довольно часто, для выбора пункта меню приходилось выбирать номер пункта и вводить его через клавиатуру. Так происходило интерактивное взаимодействие в эпоху чёрных экранов. Если посмотреть на исходники многих современных программ, выбор //что надо сделать// до сих пор построен именно так (хотя эта логика скрыта //плюшками//, //приблудами// и //контролами// интерфейса графического пользователя).
  
 Так когда же нужно применять оператор выбора ''CASE''? Должно быть выполнено два условия: Так когда же нужно применять оператор выбора ''CASE''? Должно быть выполнено два условия:
Строка 10: Строка 10:
  
 Как использовать оператор ''CASE'' представлено ниже: Как использовать оператор ''CASE'' представлено ниже:
 +<code oberon2>
 +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.
 +</code>
 +Вывод:
 +<code>
 +компилируется "Test_case" 252 0
 +старый модуль Test_case выгружен
 +v := 6
 +Малое число
 +v := 12
 +Среднее число
 +v := 102
 +Ого! Большое число!
 +v := - 1
 +Нет. Это что - то не то...
 +</code>
   
 Как видно из текста модуля, количество веток с ''ELSE'' было бы драматически большим, пришлось бы написать больше кода, а значит риск совершения ошибки увеличивается. Кроме того, более компактная форма записи, позволяет сократить занимаемое место на экране, что положительно сказывается на понимании текста программы. Как видно из текста модуля, количество веток с ''ELSE'' было бы драматически большим, пришлось бы написать больше кода, а значит риск совершения ошибки увеличивается. Кроме того, более компактная форма записи, позволяет сократить занимаемое место на экране, что положительно сказывается на понимании текста программы.
Строка 16: Строка 64:
 ==== 2. Ключевые слова модуля ====  ==== 2. Ключевые слова модуля ==== 
 Таких слов на данный момент рассмотрено три: Таких слов на данный момент рассмотрено три:
-  - MODULE [NameModule];  -- обязательное ключевое слово с именем модуля. По другому компилятор никак не сможет определить к чему относится программный текст. +  - ''MODULE'' [NameModule];  -- обязательное ключевое слово с именем модуля. По другому компилятор никак не сможет определить к чему относится программный текст. 
-  - END [NameModule]. -- обязательное ключевое слово с именем модуля. По другому компилятор никак не сможет определить, где заканчивается программный код. Нельзя забывать, что за концом программного текста ещё могут быть различные элементы, как-то: коммандер (а то и не один), данные для ввода, данные для компиляции, заметки типа TODO или краткие примеры правильного использования. Кроме того, можно вставить ссылки на документацию по модулю или смежные темы. +  - ''END'' [NameModule]. -- обязательное ключевое слово с именем модуля. По другому компилятор никак не сможет определить, где заканчивается программный код. Нельзя забывать, что за концом программного текста ещё могут быть различные элементы, как-то: коммандер (а то и не один), данные для ввода, данные для компиляции, заметки типа **TODO** или краткие примеры правильного использования. Кроме того, можно вставить ссылки на документацию по модулю или смежные темы. 
-  - BEGIN -- необязательное ключевое слово уровня модуля. Обычно, код размещённый после него -- исполняется для служебных целей во время загрузки самого модуля. По возможности, не стоит использовать это логическое пространство для кода. С высокой вероятностью, это будет плохим решением. +  - ''BEGIN'' -- необязательное ключевое слово уровня модуля. Обычно, код размещённый после него -- исполняется для служебных целей во время загрузки самого модуля. По возможности, не стоит использовать это логическое пространство для кода. С высокой вероятностью, это будет плохим решением. 
-  - CLOSE -- необязательное ключевое слово уровня модуля. Обычно, код размещённый после него -- исполняется для служебных целей во время выгрузки самого модуля. Эта возможность используется ещё реже, чем BEGIN, так что с ещё большей вероятностью использование этой секции будет ещё более плохим решением.+  - ''CLOSE'' -- необязательное ключевое слово уровня модуля. Обычно, код размещённый после него -- исполняется для служебных целей во время выгрузки самого модуля. Эта возможность используется ещё реже, чем ''BEGIN'', так что с ещё большей вероятностью использование этой секции будет ещё более плохим решением.
  
-Читатели знакомые, например, с python, обратят своё внимание, что это очень похоже на специальные методы классов __init__ и __del__. И такое сходство будет не случайно. Вспоминаем, что основная единица компиляции в КП -- модуль! И понятие модуля органически совмещается с понятием класса. [↑]+Читатели знакомые, например, с **python**, обратят своё внимание, что это очень похоже на специальные методы классов ''__init__'' и ''__del__''. И такое сходство будет не случайно. Вспоминаем, что основная единица компиляции в КП -- //модуль//! И понятие //модуля// органически совмещается с понятием //класса//. И всё же, надо помнить, что ''BEGIN'' и ''CLOSE'' относятся к модулю, а не классу (которых в **python** в одном модуле может быть несколько, хотя сами же питонёры к такой практике относятся не очень хорошо).
   
   
 ==== 3. Арифметические и логические операции ==== ==== 3. Арифметические и логические операции ====
-Здесь будут рассмотрены только обойдённые внимание операции. +Здесь будут рассмотрены только обойдённые вниманием операции. 
-  - MOD -- бывает весьма полезная операция для поиска остатка при целочисленном делении. Можно вычислить остаток и через программное решение, но оно гарантированно будет более медленней. Пример: 5 MOD 3 = 2. +  - ''MOD'' -- бывает весьма полезная операция для поиска остатка при целочисленном делении. Можно вычислить остаток и через программное решение, но оно гарантированно будет более медленней. Пример: ''5 MOD 3 = 2''
-  - DIV -- также весьма полезная операция для целочисленного деления (т.е. когда оба операнда имеют целочисленный тип, и результат имеет его же). Также работает заметно быстрее, чем операции над вещественными числами. Пример: 5 DIV 3 =  1. Разумеется, точность страдает, но бывает это приемлемо. +  - ''DIV'' -- также весьма полезная операция для целочисленного деления (т. е. когда оба операнда имеют целочисленный тип, и результат имеет его же). Также работает заметно быстрее, чем операции над вещественными числами. Пример: ''5 DIV 3 =  1''. Разумеется, точность страдает, но бывает это приемлемо. 
-  - ~[число] -- "выворачиваетчисло. Инвертирует все биты.  +  - ''~[число]'' -- //выворачивает// число. Инвертирует все биты.  
-  - OR -- логическое сложение чисел, бывает полезным, например, при наложении изображений. Пример: 3 OR 2 = 3. +  - ''OR'' -- логическое сложение чисел, бывает полезным, например, при наложении изображений. Пример: ''3 OR 2 = 3''
-  - & -- логическое умножение (читается "амперсанд"). Бывает полезным при, например: шифровании, обработки изображений. Пример: 5 & 3 = 1. +  - ''&'' -- логическое умножение (читается "амперсанд"). Бывает полезным при, например: шифровании, обработки изображений. Пример: ''5 & 3 = 1''
-  - IN -- принадлежность к множеству. Не путать с параметрами на вход в процедурах! Пример: 6 in a. Где а: ARRAY 1000 OF BYTE (или ещё чего-нибудь). Если значение 6 содержаится в массиве а, то результатом этого выражения будет TRUE, в противном случае FALSE. +  - ''IN'' -- принадлежность к множеству. Не путать с параметрами на вход в процедурах! Пример: ''6 in a''. Где ''а: ARRAY 1000 OF BYTE'' (или ещё чего-нибудь). Если значение 6 содержится в массиве ''а'', то результатом этого выражения будет ''TRUE'', в противном случае ''FALSE''
-  - IS -- принадлежность к типу. Бывает полезным узнать во время выполнения программы к какому типу относится переменная. Используется вместо с оператором выбора типа WITH . Аналогично с предыдущим ключевым словом результатом вычисления является TRUE или FALSE. Оператор IS вводит в Компонентный Паскаль возможности интроспекции (исследование "системы во внутрь"). +  - ''IS'' -- принадлежность к типу. Бывает полезным узнать во время выполнения программы к какому типу относится переменная. Используется вместо с оператором выбора типа ''WITH'' . Аналогично с предыдущим ключевым словом результатом вычисления является ''TRUE'' или ''FALSE''. Оператор ''IS'' вводит в **Компонентный Паскаль** возможности интроспекции (исследование "системы во внутрь"). 
-  - ASSERT -- оператор охраны. Вызывает системное исключение, если выражение  скобках не соответствует истине. Например, ASSERT((10<i) & (i<20), 20). Системное исключение возникнет тогда, когда i будет меньше или равно 10 и больше или равно 20.+  - ''ASSERT'' -- оператор охраны. Вызывает системное исключение, если выражение  скобках не соответствует истине. Например, ''ASSERT( (10<i) & (i<20), 20)''. Системное исключение возникнет тогда, когда ''i'' будет меньше или равно 10 и больше или равно 20.
   
   
Строка 96: Строка 144:
   
   
-В приведённом примере создаётся тип tRecord и наследующий его tRecord1. Процедура SelectV принимает только тип tRecord, и, теоретически, компилятор должен был грязно выругаться при попытке скомпилировать этот пример. Ведь в процедуре Start видна попытка скормить для SelectV переменную типа tRecord1 (а это уже другой тип). Но компилятор соглашается!!!+В приведённом примере создаётся тип ''tRecord'' и наследующий его ''tRecord1''. Процедура ''SelectV'' принимает только тип ''tRecord'', и, теоретически, компилятор должен был грязно выругаться при попытке скомпилировать этот пример. Ведь в процедуре ''Start'' видна попытка скормить для ''SelectV'' переменную типа ''tRecord1'' (а это уже другой тип). Но компилятор соглашается!!!
  
-После этого в процедуре SelectV использована небольшая хитрость. Так как одна из переменных имеет тип tRecord1, то при первом вызове эта ветка будет пропущена (и это правильно, так как тип переменной -- tRecord). А во втором случае выполнение пойдёт именно по первой ветке (и это тоже правильно, так как второй тип -- tRecord1 является расширением tRecord). После выполнения одной из веток -- другие ветки выполняться не будут.+После этого в процедуре ''SelectV'' использована небольшая хитрость. Так как одна из переменных имеет тип ''tRecord1'', то при первом вызове эта ветка будет пропущена (и это правильно, так как тип переменной -- ''tRecord''). А во втором случае выполнение пойдёт именно по первой ветке (и это тоже правильно, так как второй тип -- ''tRecord1'' является расширением ''tRecord''). После выполнения одной из веток -- другие ветки выполняться не будут.
  
-В тоже время, необходимо обратить внимание, что если в коде попытаться передать переменную типа INTEGER (или вообще любую, не наследующую и не являющуюся типом tRecord) -- компилятор просто откажется компилировать такой модуль.+В тоже время, необходимо обратить внимание, что если в коде попытаться передать переменную типа ''INTEGER'' (или вообще любую, не наследующую и не являющуюся типом ''tRecord'') -- компилятор просто откажется компилировать такой модуль.
   
   
 ==== 5. Заключение ==== ==== 5. Заключение ====
-Приведённые особенности Компонентного Паскаля надо знать. Можно поспорить с тем, что, например CASE может и излишняя семантическая конструкция в языке, но опытные программисты на практическом примере покажут вам преимущества того или иного способа. Важно иметь практику, и понимание, что для чего предназначено.+Приведённые особенности **Компонентного Паскаля** надо знать. Можно поспорить с тем, что, например ''CASE'' может и излишняя семантическая конструкция в языке, но опытные программисты на практическом примере покажут вам преимущества того или иного способа. Важно иметь практику, и понимание, что для чего предназначено.
  
-В качестве самостоятельного задания, которое потребует почитать документацию, рекомендуется составить две программы с помощью IF THEN ELSE  и CASE, и сравнить быстродействие на 10 ветках исполнения (подсказка: Time).+В качестве самостоятельного задания, которое //потребует почитать// документацию, рекомендуется составить две программы с помощью ''IF THEN ELSE''  и ''CASE'', и сравнить быстродействие на 10 ветках исполнения ((подсказка: Time)).
   
bb/redbook/213.1473317685.txt.gz · Последнее изменение: 2020/10/29 07:08 (внешнее изменение)