Переменные с непостоянным типом значений
Тип данных Variant
В среде Delphi определен стандартный тип данных Variant, с помощью которого объявляются переменные с непостоянным типом значений. Разработан специально для тех случаев, когда на этапе компиляции программист не может сказать, какого типа данные будут использоваться в выражении или как параметры вызова подпрограмм.
Переменная с типом Variant занимает в памяти 16 байт. В них хранятся текущее значение переменной (или адрес значения в динамической памяти) и тип этого значения.
Структура вариантного типа представляет собой упакованную запись с вариантной частью. Типы TVarData и TVarType (тождественный типу Word), константы (указывающие тип помещенных в вариант данных) описаны в модуле System. Функциональная часть описана в модуле Variants, который необходимо подключать, если мы хотим работать с вариантным типом.
Значения переменных с типом Variant
1. В переменную-вариант можно поместить:
· целое или вещественное число;
· булевское значение;
· строковое значение;
· время и/или дату;
· OLE-объект;
· массив произвольной размерности и длины, содержащий элементы одного из перечисленных выше типов, так называемый вариантный массив (не статический).
Кроме того, переменные с типом Variant принимают два специальных значения: Unassigned и Null.
Значение Unassigned показывает, что переменной еще не присвоено значение. Оно автоматически устанавливается в качестве начального значения любой переменной с типом Variant.
Значение Null показывает, что переменная имеет неопределенное значение.
В Delphi определены такие константы, указывающие тип помещенных в вариант данных. Таблица…
Получить тип вариантных данных можно с помощью функции varType (см. ниже), а изменить тип - путем присваивания варианту нового значения.
Variant в выражениях
1. Варианты могут участвовать в целочисленных, вещественных, логических и время-дата выражениях при условии корректности соответствующих преобразований.
var V1, V2, V3, V4: Variant; begin V1 := 5; // целое число V2 := 0.8; // вещественное число V3 := '10'; // строка V4 := V1 + V2 + V3; // вещественное число 15.8end; |
Если же V3:=’текст’, то выражение V1 + V2 + V3 вызовет исключение EVariantError.
2. Если в выражении участвует переменная со значением Null, то результат будет Null.
Преобразование вариантов к другим типам данных
Все целочисленные, вещественные, булевские, строковые и символьные типы совместимы по присваиванию с Variant. Для них в выражениях осуществляется автоматическая конвертация по следующим правилам:
integer | real | string | boolean | |
integer | converts integer formats | converts to real | converts to string representation | returns False if 0, True otherwise |
real | rounds to nearest integer | converts real formats | converts to string representation using regional settings | returns False if 0, True otherwise |
string | converts to integer, truncating if necessary; raises exception if string is not numeric | converts to real using regional settings; raises exception if string is not numeric | converts string/character formats | returns False if string is "false" (non-case-sensitive) or a numeric string that evaluates to 0, True if string is "true" or a nonzero numeric string; raises exception otherwise |
character | same as string (above) | same as string (above) | same as string (above) | same as string (above) |
Boolean | False = 0, True = -1 (255 if Byte) | False = 0, True = -1 | False = "0", True = "-1" | False = False, True = True |
Unassigned | returns 0 | returns 0 | returns empty string | returns False |
Null | raises exception | raises exception | raises exception | raises exception |
Подпрограммы для работы с вариантами
1. Тип значения выясняется с помощью функции
VarType(const V: Variant): Integer;
Возвращаемый результат формируется из констант, перечисленных в таблице. Например, следующий условный оператор проверяет, содержит ли переменная строку (массив строк):
if VarType(V) and varTypeMask = varString then ... | ||||
Код типа | Значение | Описание | ||
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 в динамической памяти. | ||
varDispatch | $0009 | Переменная содержит ссылку на интерфейс IDispatch (интерфейсы позже). | ||
varError | $000A | Переменная содержит системный код ошибки. | ||
varBoolean | $000B | Переменная содержит значение типа WordBool. | ||
varVariant | $000C | Элемент варьируемого массива содержит значение типа Variant (код varVariant используется только в сочетании с флагом varArray). | ||
varUnknown | $000D | Переменная содержит ссылку на интерфейс IUnknown (интерфейсы рассмотрены в главе 6). | ||
varShortint | $0010 | Переменная содержит значение типа Shortint | ||
varByte | $0011 | Переменная содержит значение типа Byte. | ||
varWord | $0012 | Переменная содержит значение типа Word | ||
varLongword | $0013 | Переменная содрежит значение типа Longword | ||
varInt64 | $0014 | Переменная содержит значение типа Int64 | ||
varStrArg | $0048 | Переменная содержит строку, совместимую со стандартом COM, принятым в операционной системе Windows. | ||
varString | $0100 | Переменная содержит ссылку на длинную строку. | ||
varAny | $0101 | Переменная содержит значение любого типа данных технологии CORBA | ||
Флаги | ||||
varTypeMask | $0FFF | Маска для выяснения типа значения. | ||
varArray | $2000 | Переменная содержит массив значений. | ||
varByRef | $4000 | Переменная содержит ссылку на значение. | ||
2. Функция
VarAsType(const V: Variant; VarType: Integer): Variant;
позволяет вам преобразовать значение варьируемой переменной к нужному типу, например:
V1 := '100';V2 := VarAsType(V1, varInteger); |
3. Остальные функции:
function VarAsType(const V: Variant; VarType: Integer): Variant; | Преобразует данные варианта V к типу, определяемому параметром VarType |
procedure VarCast(var Dest: Variant; const Source: Variant; Var Type: Integer) ; | Преобразует данные варианта Source к типу,определяемому параметром VarType, и помещает результат в переменную Dest |
procedure VarClear(var V: Variant) ; | Освобождает динамическую память, если она была связана с вариантом, и дает ему тип varEmpty |
procedure VarCopy(var Dest: Variant; const Source: Variants; | Копирует параметр Source в вариант Dest |
function VarFrom-DateTime(DateTime: TDateTime):Variant; | Возвращает вариант, содержащий данные DateTime типа дата-время |
function VarIsEmpty(const V: Variant): Boolean; | Возвращает True, если вариант V не содержит данных |
function VarIsNull(const V: Vari ant) : Boolean; | Возвращает True, если вариант V содержит данные неопределенного типа (varNull) ', |
function VarToDateTime(const V: Variant): TDateTime) ; | Преобразует данные варианта V к типу дата-время |
function VarToStr(const V: Vari ant) : String; | Преобразует данные варианта V к строке ; |
function VarType(const V: Variant) : Integer; |
Вариантные массивы
Значением варианта может быть массив данных, такие варианты называются вариантными массивами. (Не путайте с обычным или динамическим массивом, элементами которого являются варианты!)
Значениями элементов вариантного массива могут быть любые допустимые для варианта значения, кроме строк varstring. Значениями элементов вариантного массива могут быть и варианты, а это значит, что в таком массиве могут одновременно храниться данные разных типов (и в том числе строки). Например:
var V: Variant; begin // Создаем одномерный вариантный массив с 5 элементами: V := VarArrayCreate([0, 4], varVariant); // Наполняем его: V[0] := 1; //Тип целый V[1] := 1234.5678; //Тип вещественный V[2] := 'Hello world'; //Строковый тип V[3] := True; //Логический тип //Пятым элементом исходного массива сделаем еще один массив: V[4] := VarArrayOf([1, 10, 100, 1000]); Caption := V[2]; //Hello world IbOutput.Caption := IntToStr(V[4][2]); //100 end; |
Действия с вариантными массивами можно осуществлять с помощью процедур и функций. Приведем некоторые:
function VarArrayCreate(const Bounds: array of Integer; VarType: Integer): Variant; | Создает вариантный массив из элементов типа VarType с количеством и границами измерений, указываемых параметром Bounds |
function VarArrayDimCount(const A: Variant): Integers; | Возвращает количество измерений вариантного массива А или 0, если А не массив |
function VarArrayHighBound(const A: Variant; Dim: Integer): Integer; | Возвращает верхнюю границу индекса вариантного массива А по измерению Dim |
function VarArrayLowBound(const A: Variant; Dim: Integer): Integers; | Возвращает нижнюю границу индекса вариантного массива А по измерению Dim |
function VarArrayOf(const Values: array of Variant): Variants; | Создает одномерный вариантный массив по перечню значений, содержащихся в открытом массиве Values. Нижняя граница индексов вариантного массива в этом случае равна 0 |
Указатели
Понятие указателя
Все переменные, с которыми мы имели дело, известны уже на этапе компиляции. Однако во многих задачах нужны переменные, которые по мере необходимости можно создавать и удалять во время выполнения программы. С этой целью в языке Delphi организована поддержка так называемых указателей, для которых введен специальный тип данных Pointer.
1. Любая переменная в памяти компьютера имеет адрес. Переменные, значением которых является адрес в памяти (в частности, адреса других переменных), принято называть указателями. Указатели объявляются точно так же, как и обычные переменные:
Var P1: Pointer; // переменная-указатель нетипизированный N: Integer; // целочисленная переменная P: ^Integer; // переменная - указатель типизированный |
Переменная P занимает 4 байта и может содержать адрес любого участка памяти, указывая на байты со значениями любых типов данных: Integer, Real, string, record, array и других. Если указатель указывает на переменную структрированного типа (массив, запись…), то этот указатель содержит адрес первого элемента этой структуры.
Чтобы инициализировать переменную P, присвоим ей адрес переменной N. Это можно сделать двумя эквивалентными способами (для P и P1):
P := Addr(N); // с помощью вызова встроенной функции Addr |
или
P1 := @N; // с помощью оператора @ |
В дальнейшем мы будем использовать более краткий и удобный второй способ.
2. Если некоторая переменная P содержит адрес другой переменной N, то говорят, что P указывает на N. Графически это обозначается стрелкой, проведенной из P в N (рисунок выполнен в предположении, что N имеет значение 10):
Рисунок. Графическое изображение указателя P на переменную N
3. Теперь мы можем изменить значение переменной N, не прибегая к идентификатору N. Для этого слева от оператора присваивания запишем не N, а P вместе с символом ^:
P^ := 10; // Здесь не нужно приведение типаInteger(P1^) := 10; // Выполонено приведение типа |
Символ ^, записанный после имени указателя, называется оператором доступа по адресу. В данном примере переменной, расположенной по адресу, хранящемуся в P, присваивается значение 10. Так как в переменную P мы предварительно занесли адрес N, данное присваивание приводит к такому же результату, что и
N := 10; |
4. Отдельно обратим внимание на символ ^.
^typeName; // Для описания типизированного указателяpointer^; // Оператор доступа по адресу |
5. При записи P: ^Integer переменная P по-прежнему является указателем, но теперь ей можно присваивать адреса только целых переменных. В данном случае указатель P называют типизированным, в отличие от переменных типа Pointer, которые называют нетипизированнымиуказателями. При использовании типизированных указателей лучше предварительно вводить соответствующий указательный тип данных, а переменные-указатели просто объявлять с этим типом.
type pointerTypeName = ^type; |
Чтобы отличать указательные типы данных от других типов, будем назначать им идентификаторы, начинающиеся с буквы P (от слова Pointer). Объявление указательного типа данных является единственным способом введения указателей на составные переменные, такие как массивы, записи, множества и другие. Например, объявление типа данных для создания указателя на некоторую запись TPerson может выглядеть так:
Type PPerson = ^TPerson; TPerson = record FirstName: string[20]; LastName: string[20]; BirthYear: Integer; end; var P: PPerson; |
Переменная P, описанная с типом данных PPerson, является указателем и может содержать адрес любой переменной типа TPerson. Впредь все указатели мы будем вводить через соответствующие указательные типы данных. Типом Pointer будем пользоваться лишь тогда, когда это действительно необходимо или оправдано.
Дата добавления: 2016-02-09; просмотров: 1402;