На этом шаге мы приведем общие сведения о вариантных типах.
Вариантные типы - это новое языковое средство представления данных, отсутствующее во всех предыдущих реализациях языка Pasсal. Более того, эти типы противоречат "духу" языка Pascal, который был задуман и реализован профессором Н.Виртом как язык сильной типизации, не допускающий неявных преобразований типов во время выполнения программы (исключение составляют очевидные преобразования в рамках группы целых типов и преобразования целых типов к веществественным). С другой стороны, наличие в Object Pascal вариантных типов не переводит его в категорию языков слабой типизации, поскольку неявные преобразования локализованы и допустимы только в рамках типа Variant а не так, как в языке PL/1, повсеместно и для любых типов. Поэтом программисты, отдающие предпочтение строгому стилю программирования, могут попросту отказаться от использования вариантных типов. Oднако, каким бы ни было отношение программистов к типу Variant, он уже присутствует в языке Object Pascal и представляет собой достаточно гибкое и мощное средство преобразования типов во время выполнения программы.
Рассмотрим вариантные типы более подробно.
Переменная типа Variant занимает в памяти 16 байтов и имее структуру, показанную ниже.
Первые 8 байтов (4 поля типа Word):
Рис.1. Содержимое первых четырех слов
Последние 8 байтов (используются в зависимости от типа значения):
Рис.2. Содержимое последних 8 байтов
Для прямой работы с внутренним представлением вариантных типов в модуле System объявлен тип TVarData, который имеет следующий вид:
TVarData = record VType: Word; Reserved1, Reserved2, Reserved3: Word; саsе Integer of varSmallint: (VSmallint: Smallint); varInteger: (VInteger : Integer); varSingle: (VSingle: Single); varDouble: (VDouble: Double); varCurrency: (VCurrency: Currency); varDate: (VDate: Double); varOleStr: (VOleStr: PWideChar); varDispatch: (VDispatch: Pointer); varError: (VError: Integer); varBoolean: (VBoolean : WordBool); varUnknovm: (VUnknown : Pointer); varString: (VString: Pointer); varArray: (VArray: PVarArray); varByRef: (VPointer : Pointer); end;
Первое поле VType типа Word содержит код, определяющий тип значения переменной в конкретный момент выполнения программы. Точнее, этот код занимает 12 младших разрядов поля VType и может быть определен с помощью специальной маски varTypeMask и стандартной функции VarType, которая возвращает его текущее значение. Старшие четыре разряда поля VType могут содержать признак того, что значением переменной является вариантный массив (varArray) или ссылка (varByRef).
Код типа значения вариантной переменной может быть одной из следующих констант:
const varEmpty = $0000; {Переменная содержит специальное значение Unassigned} varNull = $0001; {Переменная содержит специальное со значение Null} varSmallint = $0002; {Переменная содержит значение типа Smallint} varInteger = $0003; {Переменная содержит значение типа Integer} varSingle = $0004; {Переменная содержит значение типа Single} varDouble = $0005; {Переменная содержит значение типа Double} varCurrency = $0006; {Переменная содержит значение типа Currency} varDate = $0007; {Переменная содержит значение типа TDateTime} varOleStr = $0008; {Переменная содержит ссылку на динамически размещенную Unicode-строку (OLE-строку)} varDispatch = $0009; {Переменная содержит ссылку на OLE-объект} varError = $000A; {Переменная содержит код системной ошибки} varBoolean = $000B; {Переменная содержит значение типа WordBool} varVariant = $000C; {Переменная содержит значение типа Variant (используется только с вариантными массивами)} varUnknown = $000D; {Переменная содержит ссылку на неизвестный OLE-объект} varByte = $0011; {Переменная содержит значение типа Byte} varString = $0100; {Переменная содержит ссылку на динамически размещенную строку типа AnsiString} varTypeMask = $0FFF; {Битовая маска для извлечения значения поля VType} varArray = $2000; {Бит, показывающий, что значением переменной является вариантный массив} varByRef = $4000; {Бит, показывающий, что значением переменной является ссылка}
Следующие три поля Reserved1, Reserved2 и Reserved3, которые располагаются после поля VType, зарезервированы для будущих реализаций. Последние 8 байтов внутреннего представления вариантных переменных используются в зависимости от типа присвоенного им значения, то есть от значения поля VType. К этим байтам можно обращаться с помощью полей вариантной части записи TVarData. Если установлен бит varArray, то вариантная переменная будет держать не одно значение определяемого полем VType типа, а указатель на вариантный массив предопределенного типа TVarArray, который описан также, как и тип TVarData, в модуле System. Тип элементов вариантного массива по-прежнему определяется значением поля VType.
type TVarArrayBound = record ElementCount: Integer; LowBound: Integer; end; PVarArray = ^TVarArray; TVarArray = record DimCount: Word; Flags: Word; ElementSize: Integer; LockCount: Integer; Data: Pointer; Bounds: array[0..255] of TVarArrayBound; end;
Если же установлен бит varByRef, то эта вариантная переменная хранит указатель на значение типа, определяемого полем VType.
На следующем шаге мы перечислим свойства вариантных типов и основные процедуры и функции, предназначенные для работы с этими типами.