Содержание


Язык программирования Nimrod

Часть 5. Составные и производные типы данных

Comments

Серия контента:

Этот контент является частью # из серии # статей: Язык программирования Nimrod

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Язык программирования Nimrod

Следите за выходом новых статей этой серии.

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

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

1. Несколько слов о расширениях базовых типов данных

Для символьного типа (char) в Nimrod определён размер в один байт. Таким образом, лишь часть символов в кодировке UTF-8 может быть представлена с помощью этого типа. Автор языка объясняет такое решение соображениями эффективности обработки символов. Впрочем, с помощью оператора $ можно преобразовать любой символ в строку (string). Символьные значения нельзя использовать совместно с целочисленными, необходимо сначала преобразовать символы в целые числа посредством процедуры ord. Если требуется обратное преобразование (из целого числа в символ), то для этого используется процедура chr.

Строки в Nimrod (в кодировке UTF-8) являются изменяемыми, то есть любую строку можно дополнять (процедура add). Строки содержат поле длины, но в то же время завершаются специальным символом '\0'. Оператор присваивания создаёт копию строки. Для объединения строк применяется оператор &. Строковые переменные инициализируются специальным значением nil, но не все операции со строками корректно обрабатывают это значение, поэтому для создания пустой строки рекомендуется использовать значение "".

Кроме обычного целочисленного типа int в Nimrod встроены специализированные типы для целых чисел: int8 (пример: 1'i8), int16 (68754'i16), int32 (0'i32), int64 (0'i64), а также беззнаковые целочисленные типы: uint (пример: 1'u), uint8, uint16, uint32, uint64. Числовое значение без суффикса по умолчанию имеет тип int.

Для чисел с плавающей точкой имеются встроенные типы float (пример: 3.14), float32 (3.14'f32), float64 (3.14'f64).

При совместном использовании целых чисел и чисел с плавающей точкой в выражениях автоматические преобразования в неявной форме не выполняются. Необходимо явно пользоваться процедурами toInt и toFloat.

2. Производные или расширенные типы

Nimrod позволяет при необходимости определять произвольные типы данных с помощью ключевого слова type, как показано в листинге 1.

Листинг 1. Определение новых типов
type
  bigUInt = uint64    # самый большой из доступных целочисленный беззнаковый тип
  bigFloat = float64  # самый большой из доступных тип с плавающей точкой

2.1. Перечисления

Перечисления представляют собой один из самых простых производных типов, поскольку содержат литеральные символы, расположенные в определённом порядке. Все символы, составляющие перечисление, пронумерованы, начиная с нуля (если явно не указаны другие значения), всегда в возрастающем порядке. Если для элемента перечисления явно не задан номер, то он вычисляется посредством прибавления 1 к номеру предыдущего элемента. Пример определения перечисления показан в листинге 2.

Листинг 2. Определение нового типа - перечисления
type
  TMonths = enum
    jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec

var eng_month = may  # переменная имеет тип TMonths и допустимое значение этого типа
echo( $eng_month, " - это ", ord(eng_month), "-й месяц года" )

Для того, чтобы избежать неоднозначностей и указать принадлежность символьного литерала к определённому типу, можно пользоваться следующей формой записи: TMonth.oct.

Как можно понять из листинга 2, для преобразования значения перечисления в символьную строку применяется всё тот же универсальный оператор $, а для получения числового значения его номера - процедура ord.

Нумерация элементов перечисления не обязательно должна быть непрерывной. Если порядковые номера задаются в явной форме, то перечисление может содержать так называемые "дыры" (holes), как показано в листинге 3.

Листинг 3. Определение перечисления с "дырами"
type
  TPorts = enum
    echo = 7, ftp = 21, smtp = 25, www = 80, pop3 = 110, ntp = 123

2.2. Поддиапазоны

Тип поддиапазон (subrange) является специально определённым диапазоном значений целочисленного типа или перечисления. Примеры определения поддиапазонов приведены в листинге 4.

Листинг 4. Определение поддиапазонов
type
  TSubrangeOfInt = range[10..20]
  TSummerMonths = range[TMonths.jun..TMonths.aug]

После этих определений тип TSubrangeOfInt является поддиапазоном целых чисел, в котором допустимыми являются только значения от 10 до 20 включительно, а переменным типа TSummerMonths могут быть присвоены только значения jun, jul и aug из перечисления TMonths. Все присваиваемые значения, отличающиеся от допустимых, будут вызывать ошибки компиляции (или в некоторых случаях ошибки времени исполнения). Переменным базовых типов (например, int) можно присваивать значения из их поддиапазонов (в данном случае из поддиапазона TSubrangeOfInt).

В модуле system определён специальный тип natural как поддиапазон range[0..high(int)] (процедура high возвращает максимальное значение заданного типа).

2.3. Множества

Множества или наборы (sets) моделируют математическую концепцию множеств. Это один из наиболее интересных комплексных типов в языке Nimrod. Базовым типом для множества может быть только перечислимый тип.

Конструктор множества, обозначаемый парными фигурными скобками, позволяет создать множество и определить его содержимое: например, {} - это пустое множество, которое является совместимым с любым другим типом множества. Создание непустого множества, то есть множества, содержащего элементы (точнее, диапазоны элементов), показано в листинге 5.

Листинг 5. Определение типа множества и его использование
type
  TCharSet = set[char]
var
  chdg: TCharSet
chdg = {'a'..'z', '0'..'9'}

В данном примере определяется тип множества TCharSet с базовым типом char, являющегося перечислимым типом, затем создаётся переменная этого типа: множество chdg, содержащее буквы английского алфавита в нижнем регистре от 'a' до 'z' и цифровые символы от '0' до '9'.

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

  • A + B - объединение двух множеств
  • A * B - пересечение двух множеств
  • A - B - разность между двумя множествами (элементы из A с исключением элементов из B)
  • A == B - проверка на равенство двух множеств
  • A <= B - отношение подмножества (A является подмножеством B или A равно B)
  • A < B - строгое отношение подмножества (A является действительным подмножеством B)
  • e in A - принадлежность к множеству (элемент e содержится в множестве A)
  • e not in A - множество A не содержит элемент e
  • contains(A,e) - множество A содержит элемент e
  • A -+- B - симметричная разность множеств, определяемая формулой (A-B)+(B-A)
  • card(A) - мощность множества A (количество элементов в множестве A)
  • incl( A, element ) - включение элемента в множество, равносильно A + {element}
  • excl( A, element ) - исключение элемента из множества, равносильно A - {element}

2.4. Массивы

Массив (array) представляет собой контейнер заданной фиксированной длины, содержащий элементы только одного типа. Индекс массива может принадлежать к любому перечислимому типу. Определение, конструирование и доступ к элементам массива выполняются с помощью привычных квадратных скобок [], как показано в листинге 6.

Листинг 6. Определение, создание и использование массива
type
  TIntArray = array[0..5, int] # здесь определяются только индексы массива
var
  xarr: TIntArray
xarr = [95, 96, 97, 98, 99, 100]
for i in low(xarr)..high(xarr):
  echo( xarr[i] )
echo( "Длина массива ", len(xarr), " элементов" )

Из приведённого примера очевидно, что форма xarr[i] используется для обращения к i-му элементу массива xarr, low(xarr) возвращает наименьший допустимый индекс массива, high(xarr) возвращает наибольший допустимый индекс массива, а len(xarr) возвращает длину (количество элементов) массива. Правильность доступа в границах массива всегда контролируется внутренним механизмом языка: и во время компиляции, и во время выполнения. При необходимости контроль границ массива можно отключить либо соответствующей прагмой, либо вызывая компилятор с ключом --bound_checks:off.

В Nimrod существуют ещё и так называемые открытые массивы (open arrays), или массивы переменной длины, которые могут быть использованы только для передачи параметров в процедуры для удобства работы с массивами различной длины. Открытые массивы всегда индексируются числовыми значениями типа int, а нумерация индексов всегда начинается с нуля. Массив любого совместимого типа может быть передан в процедуру через параметр, определённый как открытый массив, при этом тип индекса передаваемого массива значения не имеет. Для открытых массивов также доступны операции low, high, len.

2.5. Последовательности

Последовательности (sequences) похожи на массивы, но их длина может динамически меняться во время выполнения. Последовательности всегда индексируются целыми числами типа int, начиная с 0, для них доступны операции low, high и len, а доступ к элементам точно такой же, как для массивов. Последовательности могут быть переданы в процедуру через параметр типа openarray, описанный в предыдущем разделе.

Самым простым способом создания последовательности является применение конструктора массивов [] в сочетании с оператором преобразования массива в последовательность @. Другой способ предполагает вызов встроенной процедуры newSeq. Пример определения последовательности первым способом приведён в листинге 7.

Листинг 7. Определение последовательности целых чисел
var
  x: seq[int]
x = @[10, 11, 12, 13, 14, 15]

Пустую последовательность можно создать при помощи конструкции @[].

2.6. Кортежи

Тип кортеж (tuple) определяет различные именованные поля (fields), следующие друг за другом в заданном порядке, поэтому порядок полей в конструкторе (круглые скобки) обязательно должен соответствовать порядку полей в определении кортежа. Два типа кортежа считаются равными (эквивалентными), если они определяют одинаковые поля одинаковых типов в одинаковом порядке.

Оператор присваивания для кортежей копирует каждый элемент. Форма записи tuple.field позволяет получить доступ к полю кортежа. Кроме того, возможен доступ к полям по их числовым индексам с помощью формы tuple[i], причём значение i обязательно должно быть целочисленной константой. В листинге 8 приводится пример создания кортежа и работы с ним.

Листинг 8. Определение кортежа и его использование
type
  TAnthrop = tuple[ name: string, age: int, height: int, mass: int ]
var
  person1, person2: TAnthrop
person1 = (name: "Игорь", age: 27, height: 188, mass: 87)
# Возможна запись в сокращённом варианте, но она не столь наглядна:
person2 = ("Сергей", 24, 202, 100)
echo( person1.name, " - возраст ", person1.age, ", рост ", person1.height, ", 
вес ", person1.mass )
# Обращение к полям по индексам
echo( person2[0], " - возраст ", person2[1], ", рост ", person2[2], ", вес ", person2[3] )

Заключение

В данной статье рассматривались разнообразные составные и производные типы данных языка программирования Nimrod.


Ресурсы для скачивания


Похожие темы


Комментарии

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source, Linux
ArticleID=856898
ArticleTitle=Язык программирования Nimrod: Часть 5. Составные и производные типы данных
publish-date=01312013