Типы данных

Все типы данных, используемые в Fore, являются производными от объектного типа - Object. Объектный тип предназначен для ссылки и обращению к объекту. Объектный тип является структурой, состоящей из фиксированного числа компонентов. Каждый компонент является либо полем, содержащим данные строго определенного типа, либо методом, выполняющим операции над объектом. По аналогии с описанием переменных, описание поля указывает тип данного этого поля и идентификатор, именующий поле: по аналогии с описанием процедуры или функции, описание метода указывает заголовок процедуры, функции, конструктора или деструктора.

Объектный тип может наследовать компоненты другого объектного типа. Если T2 наследует от T1, то T2 является потомком T1, а T1 является родителем T2.

Наследование является транзитивным, то есть если T3 наследует от T2, а T2 наследует от T1, то T3 наследует от T1. Область объектного типа состоит из него самого и из всех его наследников.

Операции

Для двух переменных, хранящих в себе объекты (или ссылки на объекты), доступны следующие операции отношения: равно(=) и не равно(<>). Результатом операций будет логическое значение, отражающее равенство или неравенство двух объектов.

Пример

Class TestClass: Object
    Public i: Integer;
    
    Public Constructor Create(Value: Integer);
    Begin
        i := Value;
    End Constructor Create;
End Class TestClass;

Sub SampleObject;
Var
    o: Object;
Begin
    o := Integer.MaxValue;
    Debug.WriteLine(o);
    o := "Program";
    Debug.WriteLine(o);
    o := New TestClass.Create(100);
    If o Is TestClass Then
        Debug.WriteLine((o As TestClass).i);
    End If;
End Sub SampleObject;

Типы данных языка Fore можно классифицировать в соответствии с тем, хранят ли переменные отдельных типов свои данные или указывают на них. Тип данных является типом значений, если он содержит данные в пределах своей собственной области памяти. Ссылочный тип содержит указатель на область памяти, в которой содержатся данные.

Важно. При описании пользовательский класс должен наследоваться от какого-либо существующего класса или базового класса Object. Наследование от классов базовых типов Fore запрещено.

Типы значений

Логический тип данных состоит из двух логических значений: True (истина) и False (ложь).

Для двух логических переменных доступны логические операции и операции отношения. Также для логической переменной доступна унарная операция Not.

Пример:

Sub SampleBoolean;
Var
    b: Boolean;
Begin
    b := True;
    Debug.WriteLine(b);
    b := 1 < 0;
    Debug.WriteLine(b);
    b := Boolean.Parse("TRUE");
    Debug.WriteLine(b);
    b := Not b;
    Debug.WriteLine(b);
End Sub SampleBoolean;

Переменные типа Char представляют собой один символ в кодировке Юникод. Каждому символу соответствует двухбайтное число в диапазоне 0 до 65535. Для обращения к константам типа Char используется свойство Char.Chr либо сочетание #Код.

Примечание. Константы, заключенные в двойные кавычки, определяются типом String ("Любой текст"), а константы, заключенные в апострофы, - типом Char ('A'). Управляющий символ с кодом 0 (#0) в языке Fore обрабатывается как конец строки. Все следующие после него символы будут отброшены.

Для двух символьных переменных доступны операции отношения и арифметическая операция сложения (+). Результатом сложения двух символьных переменных является строковое значение.

Пример:

Sub SampleChar;
Var
    c1, c2: Char;
    s: String;
Begin
    c1 := Char.Chr(163); //Знак франка - ₣
    c2 := #8364; //Знак евро - €
    s := "Франк: " + c1 + ". Евро: " + c2;
    Debug.WriteLine(s);
End Sub SampleChar;

Переменные типа Currency (денежные значения) сохраняются как 64-разрядные (8-байтовые) целые числа, которые после деления на 10000 дают число с фиксированной десятичной точкой с 15 разрядами в целой части и 4 разрядами в дробной. Такое представление позволяет отобразить числа в диапазоне от -922 337 203 685 477,5808 до 922 337 203 685 477,5807. Тип данных Currency используется для денежных расчетов, а также для проведения расчетов с фиксированной десятичной точкой, в которых требуется обеспечить высокую точность.

Для двух переменных, имеющих денежный тип данных, доступны операции отношения и следующие арифметические операции: *, +, -. Результатом арифметических операций является значение денежного типа.

Пример:

Sub SampleCurrency;
Var
    c: Currency;
Begin
    c := 1.123;
    Debug.WriteLine(c);
    c := 1.123E-4;
    Debug.WriteLine(c);
    c := Currency.Parse("1.123");
    Debug.WriteLine(c);
    c := Currency.MaxValue;
    Debug.WriteLine(c);
    c := 1 / 3;
    Debug.WriteLine(c);
End Sub SampleCurrency;

Тип данных DateTime предназначен для хранения даты и времени. Значение переменных типа DateTime представляет дату и время в диапазоне от 00:00:00 1 января 100 года (н.э.) до 23:59:59 31 декабря 9999 года (н.э.). При указании даты меньше допустимой автоматически будет формироваться дата, к которой будет добавлено текущее столетие. Например, при указании даты 1 января 30 года будет сформирована дата - 1 января 2030 года.

Для двух переменных, содержащих дату и время, доступны операции отношения и арифметические операции сложения (+) и вычитания (-). Результатом операции сложения является значение типа DateTime; результатом операции вычитания является значение типа TimeSpan.

Пример:

Sub SampleDateTime;
Var
    d, d1, d2, d3: DateTime;
Begin
    d := DateTime.Now;
    d1 := DateTime.AddYears(d, -1);
    d2 := DateTime.ComposeDay(200011);
    d3 := DateTime.Parse("01.01.2005 18:00:00");
End Sub SampleDateTime;

Переменные типа Decimal хранятся как шестнадцатибайтные целые числа со знаком, масштабируемые с переменным коэффициентом в виде степени 10. Масштабирующий множитель задает количество разрядов после запятой, которое изменяется в пределах от 0 до 28. Для нулевого масштаба (разряды десятичной дроби отсутствуют) наибольшее возможное значение равно +/-79 228 162 514 264 337 593 543 950 335. Для 28 разрядов после запятой наибольшее значение равно +/-7,9228162514264337593543950335, а наименьшее ненулевое значение — +/-0,0000000000000000000000000001 (+/-1E-28).

Для обозначения чисел с типом Decimal используется суффикс «m» или «M»: 1.123m, 1.123e10m, 1.123E-10M. Числа без суффикса рассматриваются как вещественные числа, при попытке их присвоения переменной типа Decimal возникнет ошибка компиляции «Тип Decimal и Double не совместимы». В этом случае необходимо использовать явное преобразование с помощью оператора As.

Примечание. Источники данных, использующие тип данных Decimal и созданные в старых версиях Prognoz Platform, могут не поддерживаться в более новых версиях. Возможно, потребуется пересоздание источника данных.

Для двух переменных, имеющих тип Decimal, доступны операции отношения и следующие арифметические операции: *, +, -, /. Результатом арифметических операций является значение типа Decimal.

Пример:

Sub SampleDecimal;
Var
    d: Decimal;
Begin
    d := 1.123m;
    d := 1.123E-10M;
    d := Decimal.Parse("1.123");
    d := Decimal.MaxValue;
End Sub SampleDecimal;

Для переменных, представляющих число с плавающей точкой, используется тип данных Double или вещественный тип данных.

Тип представляет собой число двойной точности с плавающей точкой и знаком в диапазоне - 5.0 x 10^-324 .. 1.7 x 10^308 (8 байт) (15-16 цифр). Для указания больших чисел доступно использование экспоненциальной записи чисел, например, 1 000 000 = 1e6, 0.000015 = 1.5E-5.

Для двух переменных, имеющих вещественный тип, доступны операции отношения и следующие арифметические операции: *, +, -, /. Результатом арифметических операций являются значения вещественного типа.

Пример:

Sub SampleDouble;
Var
    d: Double;
Begin
    d := 1.123;
    d := 1.123E3;
    d := 1.5E-5;
    d := Double.Parse("1.123");
    d := Double.MaxValue;
End Sub SampleDouble;

Для переменных, представляющих целое число, используется тип данных Integer или целый тип данных.

Тип представляет собой 32-разрядное (4 байта) целое число со знаком в диапазоне -2147483648..2147483647. 0-31 разряды занимает само число, 32 разряд используется для хранения знака.

Для двух целочисленных переменных доступны операции отношения, все арифметические операции и логические операции. Результатом арифметических операций являются значения целого типа, кроме операции деления (/). Результатом деления будет вещественное число. Логические операции выполняются побитно путём приведёния десятичного числа к двоичной форме. Результат операции будет приведён обратно к десятичной форме.

Пример:

Sub SampleInteger;
Var
    i: Integer;
Begin
    i := 1;
    i := Integer.Parse("12345");
    i := Integer.MaxValue;
End Sub SampleInteger;

Тип данных TimeSpan представляет собой промежуток времени. Используется для расчета интервала времени. Методы объекта с типом TimeSpan позволяют инициализировать его на основании различных единиц измерения (часов, минут, секунд, тактов и т. д.). С объектами TimeSpan выполняются операции вычитания, сложения и сравнения.

Для двух переменных, содержащих время, доступны операции отношения.

Пример:

Sub SampleTimeSpan;
Var
    d1, d2: DateTime;
    t: TimeSpan;
Begin
    d1 := DateTime.Now;
    Debug.WriteLine(d1);
    t := TimeSpan.Compose(5101511);
    d2 := DateTime.Add(d1, t);
    Debug.WriteLine(d2);
    Debug.WriteLine(t.Hours);
    Debug.WriteLine(t.TotalHours);
End Sub SampleTimeSpan;

Тип данных Variant используется для описания тех переменных, для которых во время компиляции нельзя определить тип данных, который будет храниться в этих переменных. Тип данных, хранящихся в этих переменных, может меняться во время исполнения программы. В переменную типа Variant можно присвоить любую переменную и после взять её оттуда. Также в переменной может быть сохранена ссылка на объект.

При использовании типа Variant необходимо учитывать, что переменные данного типа занимают больший объем памяти, и операции над переменными данного типа выполняются медленнее, чем над переменными определенных типов. Это связано с тем, что переменная типа Variant помимо значения переменной хранит информацию о типе хранящегося значения.

Значением переменной типа Variant по умолчанию является значение Null. Это значение означает отсутствие данных в переменной.

Неявные преобразования

При получении значения из переменной типа Variant и присвоении данного значения переменной, имеющей определенный тип, осуществляется проверка на возможность преобразования к данному типу. Если неявное преобразование возможно, то значение будет установлено, иначе генерируется исключительная ситуация.

Sub Sample;
Var
    s: String;
    d: DateTime;
    d1: Double;
    i: Integer;
    v: Variant;
Begin
    s := "2000.01.01 12:00:00";
    v := s;
    d := v;
    Debug.WriteLine(d.Date.ToString + " " + d.TimeOfDay.Hour.ToString);
    d1 := 3.14;
    v := d1;
    i := v;
    Debug.WriteLine(i);
End Sub Sample;

Неявное преобразование может осуществляться не только между простыми типами значений, но и между системными типами и типами, определенными в прикладном коде. При этом, если преобразование возможно, в результирующей переменной также будет доступна ссылка на объект, которая была сохранена в переменной типа Variant.

Sub Sample1;
Var
    b: IButton;
    c: IControl;
    v: Variant;
Begin
    b := New Button.Create;
    b.Text := "Кнопка";
    v := b;
    c := v;
    Debug.WriteLine(c.Text);
End Sub Sample1;

В Fore реализовано неявное преобразование при использование переменных типа Variant в операторах If и ?:.

Sub Sample2;
Var
    v: Variant;
Begin
    v := True;
    If v Then
        Debug.WriteLine("Истина");
    Else
        Debug.WriteLine("Ложь");
    End If;
    v := Math.RandBetweenI(0100);
    Debug.WriteLine(v > 50 ? "Больше 50" : "Меньше 50");
End Sub Sample2;

Явное преобразование

Для явного преобразования необходим оператор As. Явное преобразование используется, когда при преобразовании возможна потеря данных или когда преобразование по каким-либо причинам может завершиться исключительной ситуацией. Для проверки возможности явного преобразование может использоваться оператор Is.

Sub ConvertFromVariant;
Var
    v: Variant;
    i: Integer;
    d: Double;
    d1: DateTime;
    s: String;
    b: Boolean;
Begin
    v := 21.9;
    b := v Is Integer; //True
    b := v Is Double; //True
    b := v Is DateTime; //True
    b := v Is String; //True
    b := v Is Boolean; //True
    i := v As Integer; //22
    d := v As Double; //21,9 (Примечание: разделитель целой и дробной части зависит от настроек ОС)
    d1 := v As DateTime; //20.01.1900 21:36:00
    s := v As String; //"21.9"
    b := v As Boolean; //True
End Sub ConvertFromVariant;

Операции

Для переменных типа Variant доступны все операции, определенные в языке Fore. Тип результирующего значения зависит от конкретных значений, хранящихся в переменных. При необходимости, перед выполнением операции будет осуществляться неявное преобразование типов. Если в результате преобразований выполнение операции невозможно, то генерируется исключительная ситуация.

Тип данных String представляет текст как последовательность знаков Юникод. Каждая строка представляет собой упорядоченный массив из нуля или более символов Юникод (т.е. 2-байтовых целых чисел без знака), называемых элементами строки. Элементы строки нумеруются, начиная с нуля. Длина строки - это количество элементов в ней; пустая строка состоит из нуля элементов.

Строка может содержать до 2 Гб данных.

Примечание. Константы, заключенные в двойные кавычки, определяются типом String ("Любой текст"), а константы, заключенные в апострофы - типом Char ('A'). Наследование от класса базового типа String запрещено.

Комментарии

Для строковых переменных доступны операции сложения ("+") и сравнения (">", "<", ">=", "<=", "<>"). Результатом сложения двух строк S и S1 будет новая строка, в которой после символов строки S идут символы строки S1.

Результатом сравнения двух строк является логическое значение. Операция сравнения производится над числовыми значениями символов Юникод, входящих в строку. В какой строке сумма числовых значений символов больше, та строка и является большей.

Для сравнения строк с учетом их синтаксических особенностей (регистр букв, порядок символов) можно использовать один из объектов сравнения, доступных в классе Comparer.

Если в строке содержится текст с кавычками, то для отображения кавычек в строке необходимо заключить текст в двойные кавычки, например, "Любой текст ""Текст""".

Допустимый размер значений переменных

2 Гб - это максимальный, теоретически возможный размер, который могут хранить в себе строковые переменные. Данный размер обусловлен максимальным размером длины строки, установленным для типа String - 4 байта. На практике максимальный размер значения, которое может храниться в строковой переменной, зависит от множества факторов.

В архитектуру операционных систем заложено резервирование части оперативной памяти на нужды самой операционной системы и части для нужд пользовательских приложений. 32-битные процессы используют 32-битные указатели на адреса в виртуальной памяти, которые создают абсолютный верхний предел в 4 Гб (2 ^ 32-ой степени). По умолчанию 32-битная версия Windows разделяет адресное пространство поровну между системой и приложениями, создавая границу в 2 Гб для каждого. (При определенных настройках можно достичь соотношения 1/4 на нужды ОС и 3/4 на нужны приложений). 64-битные процессы используют 64-битные указатели, так что их теоретическое максимальное адресное пространство равно 16 экзабайтам (2 ^ 64-ой степени). Однако, Windows не делит адресное пространство равномерно между активными процессами и системой, а вместо этого определяет область в адресном пространстве для процессов и других системных ресурсов памяти. В 64-битной версии Windows для пользовательских приложений доступно использование адресного пространства в 8192 Гб (8 Тб).

Для каждого приложения операционная система выделяет непрерывный блок памяти, требуемый для работы. При каких-либо операциях с данными также резервируются непрерывные блоки памяти для временных переменных, используемых при вычислениях.

В реальных условиях работа запущенных приложений, служб приводит к фрагментации памяти. Это в свою очередь проводит к ограниченному количеству и объему доступных свободных непрерывных блоков памяти. В ситуациях, когда приложение достигает предела доступного адресного пространства памяти, либо когда ОС по каким-либо причинам не может выделить приложению необходимый объем памяти, генерируется исключительная ситуация «Недостаточно памяти».

Все эти ограничения приводят к тому, что на разных ПК с различными ОС всегда будет различным доступный объем памяти, который сможет использовать продукт «Форсайт. Аналитическая платформа». Это в свою очередь накладывает ограничение на максимально доступный размер данных, который можно хранить в переменных. Необходимо избегать операций с большими объемами данных, оптимизируя алгоритмы для работы с отдельными частями данных.

Операции

Для двух строковых переменных доступны операции отношения и арифметическая операция сложения (+). Результатом сложения двух строк является строковое значение.

Пример:

Sub SampleString;
Var
    s1, s2: String;
    c: Char;
Begin
    s1 := "Program";
    s2 := "Pro" + "gram";
    Debug.WriteLine(s1 = s2); //Сравнение строк по содержимому
    Debug.WriteLine((s1 As Object) = (s2 As Object)); //Сравнение строк как двух объектов
    c := s1.Chars(0);
    s1 := "Знак" + Char.Chr(160) + #169; //160-код пробела, 169-код знака ©
    Debug.WriteLine(s1);
End Sub SampleString;

Для переменных, представляющих целое число большого размера, используется тип данных Int64.

Тип представляет собой 64-разрядное (8 байта) целое число со знаком в диапазоне -9223372036854775808...9223372036854775807. 0-63 разряды занимает само число, 64 разряд используется для хранения знака.

Для обозначения чисел с типом Int64 используется суффикс «l» или «L»: 100000l, -10l. Числа с типом Integer могут быть неявно приведены к типу Int64.

Для двух переменных Int64 доступны операции отношения, все арифметические операции и логические операции. Результатом арифметических операций являются значения типа Int64, кроме операции деления (/). Результатом деления будет вещественное число. Логические операции выполняются побитно путём приведения десятичного числа к двоичной форме. Результат операции будет приведён обратно к десятичной форме.

Пример:

Sub SampleInt64;
Var
    i: Integer;
    i64: Int64;
    ar: Array 
Of Int64;
Begin
    i := Integer.MaxValue;
    i64 := Int64.MaxValue - i;
    
// Массив
    ar := New Int64[3];
    ar[
0] := i;
    ar[
1] := i64;
    ar[
2] := Int64.Parse("1234567890");
End Sub SampleInt64;

Тип данных Guid представляет уникальные глобальные 128-битный идентификаторы. Уникальность идентификаторов позволяет их использовать без опасения возникновения конфликтов, вызванных совпадением идентификаторов.

В текстовом виде уникальный глобальный идентификатор состоит из пяти частей, разделённых дефисом, содержит тридцать две шестнадцатеричных цифры и с двух сторон обозначен фигурными скобками: {2F9B6356-CA0D-4C59-B414-93E027DE207B}.

Для автоматической генерации уникальных глобальных идентификаторов используются методы класса GuidGenerator.

Для двух уникальных глобальных идентификаторов доступны следующие операции отношения: '=' и '<>'.

Пример:

Sub SampleGuid;
Var
    guid_: Guid;
    guidStr_: String;
Begin
    guidStr_ := GuidGenerator.Generate;
    guid_ := GuidGenerator.GenerateGUID;
    Debug.WriteLine(guidStr_);
    Debug.WriteLine(guid_);
    
// Сравнение полученных уникальных глобальных идентификаторов
    If guid_ <> Guid.Parse(guidStr_) Then
        Debug.WriteLine(
"Unique");
    
Else
        Debug.WriteLine(
"Not unique");
    
End If;
End Sub SampleGuid;

Ссылочные типы

Тип Array предназначен для хранения нескольких однотипных объектов, рассматриваемых как единое целое - массив. Размер массива может быть определен как на этапе объявления массива (статический массив), так и на этапе инициализации массива в тексте программы (динамический массив). Массив, состоящий из одного измерения, называется вектором, из двух измерений - таблицей, если измерений больше двух - многомерным массивом. Для описания массивов используется синтаксис, описанный в разделе «Массивы». Работа с массивами осуществляется посредством свойств и методов, реализованных в классе Array.

Примечание. Наследование от класса базового типа Array запрещено.

Пример

Sub SampleArray;
Var
    Arr1: Array[3Of Char;
    Arr2: Array Of Integer;
    Arr3: Array;
    v: Variant;
Begin
    Arr2 := New Integer[3];
    Arr3 := New Variant[3];
    Arr1[0] := 'A';
    Arr1[1] := 'B';
    Arr1[2] := 'C';
    Arr2[0] := 0;
    Arr2[1] := 1;
    Arr2[2] := 2;
    Arr3[0] := Arr1[0] + Arr2[0].ToString;
    Arr3[1] := Arr1[1] + Arr2[1].ToString;
    Arr3[2] := Arr1[2] + Arr2[2].ToString;
    For Each v In Arr3 Do
        Debug.WriteLine(v);
    End For;
End Sub SampleArray;

См. также:

Руководство по языку Fore | Переменные