- •2.1. Стандартные типы данных
- •2.2. Описание структур данных
- •2.3.1. Интервальные типы данных
- •2.4. Динамические структуры данных
- •2.5. Вариантные структуры данных
- •V: Variant; ; : rv.
- •I: Integer; ::::
- •V: Variant;
- •V: Variant;
- •V: Variant;
- •2.6. Выражения в Object Pascal
- •X, Rd: Double; I, Ri: Integer;
- •Var а, в, с: Boolean
- •X, y: Double;
2.5. Вариантные структуры данных
2.5.1. Общие понятия
Структура данных программы на языке Pascal (то есть переменные) описывается в одном месте каждого модуля — в разделе описания переменных. Данный раздел начинается ключевым словом Var и специально предназначен для этого. Таким образом, переменные не могут быть введены во время выполнения программы. Еще одна существенная особенность представления информации в Pascal — это назначение типа переменной на этапе компиляции.
Однако при программировании под Windows довольно часто встречаются задачи, в которых переменные должны изменять свой тип во время выполнения программы, соответственно, нельзя на этапе написания программы указать, какого именно типа должна быть та или иная переменная. В основном такие возможности требуются от программы, работающей с базами данных и использующей технологию СОМ.
В Delphi введена поддержка переменных, которые не имеют конкретного типа данных на этапе компиляции, а в процессе выполнения программы могут хранить данные разных типов. Такие переменные называются вариантными (англ. Variant — вариантный, различный) и описываются по обычным правилам с указанием в качестве типа данных ключевого слова Variant:
Var
<Назвак/!е
леременной>: Variant;
Во время выполнения программы в вариантных переменных могут храниться данные любого типа, за исключением структурных (записей и статических массивов) и ссылочных (типизированные и нетипизирован-ные указатели, метаклассы и указатели на экземпляры классов7). Также в вариантных переменных не могут находиться значения множественных типов данных. Неинициализированной переменной автоматически присваивается специальная константа Unassigned, описанная в модуле
Заметим, что для хранения одних и тех же данных вариантным переменным потребуется больше места в памяти, чем типизированным переменным. Кроме того, операции над вариантными переменными выполняются несколько дольше. Поэтому применение вариантов оправдано только в тех случаях, когда невозможно обойтись обычными переменными.
Листинг 2.9. Пример описания и использования вариантной переменной
Program UsingVariantsl ; Var
V: Variant;{Описание вариантной переменной,
тип переменной не определен}
S: String; {Описание переменной типа String} Begin
V := 250; {Присвоение значения вариантной переменной V,
переменной назначается целочисленный тип данных;
V := 'It is a STRING' ;
{Присвоение значения вариантной переменной V, переменной назначается строковый тип данных}
S := V; {Строковой переменной присваивается строковое значение вариантной переменной}
End.
2.5.3. Определение типа вариантных переменных
Переменная типа Variant занимает в памяти шестнадцать байт, в которых находится информация о типе данных (код типа), хранящихся в данный момент в данной переменной и сами данные, либо указатель на них. Возможные коды типов данных для вариантных переменных, описанные в модуле System, представлены в табл. 2.4.
Для определения типа данных, хранимых в вариантной переменной, используется функция VarType, описанная в модуле Variants в следующем виде:
Function VarType(const V: Variant): TVarType;
Возвращаемое функцией VarType значение имеет тип аналогичный типу Word и содержит информацию о типе данных, а также о том, является ли значение, хранимое в переменной, массивом или указателем. Младшие двенадцать бит (три последние шестнадцатеричные цифры) этого значения содержат код типа, соответствующий константам, приведенным в табл. 2.4, а в старших четырех битах могут находиться следующие значения:
♦ нулевое значение $0000 — указывает на то, что данные заявленного типа хранятся непосредственно в вариантной переменной;
♦ значение $2000 (константа varArray модуля System) — указывает на то, что хранимые данные являются массивом элементов, имеющих тип, определяемый кодом типа данных;
♦ значение $4000 (константа varByRef модуля System) — указывает на то, что хранимые данные являются ссылкой на соответствующий тип данных, определяемый кодом типа данных.
Для выделения части значения, содержащей код типа данных, предусмотрена константа varTypeMask (значение $0FFF), с помощью которой можно отделить код типа данных от дополнительных признаков:
<Переменная типа Variant> and varTypeMask
В качестве примера использования описанных выше методов приведем фрагмент программы, формирующий строку S, содержащую подробную информацию о типе вариантной переменной V9.
S := 'Data element type: s;
Case VarType(V) and varTypeMask of
varEmpty: S := S + xThe variant is UnassignecT ;
varNuil: S := S + 'The variant is Null';
Таким образом, если в переменной v находится значение 2 0 0, то после выполнения данного фрагмента программы значением переменной s будет строка 'Data element type: A Byte', если переменной v задать значение 1221.66, то в переменной s будет строка 'Data element type:
Currency floating-point value (type Currency)'. Если же значение переменной V будет строковым, например, '1221.66', то значением переменной S будет такая строка: 'Data element type: Reference to a dynamically allocated string'.
2-5.4. Автоматическое приведение типов
Интересной особенностью вариантных переменных является то, что во время выполнения программы их тип автоматически приводится для соответствия смыслу выражения. Естественно, это правило верно не для всех типов вариантных переменных, а только для тех, в которых хранятся числовые (целочисленные и вещественные), строковые, символьные и логические значения.
Допустим, например, что в программе имеется вариантная переменная Vi, которой присвоено значение 2 0 0. После присвоения переменная vi будет целочисленной (иметь тип с кодом varByte):
Vi := 200;
Допустим также, что имеется переменная S типа string. Тогда в результате выполнения оператора присваивания s := vi, значением переменной s будет строка '200'. Таким образом, во время выполнения оператора значение целочисленной переменной будет автоматически переведено в строковый вид.
Более того, возможна и обратная ситуация, когда вариантная переменная строкового типа автоматически переводится в численную форму. Однако именно в таких ситуациях могут возникать ошибки времени выполнения. Рассмотрим пример безошибочного использования вариантной переменной (листинг 2.10).
Листинг 2.11. Пример t
Program UsingVariant Var