Файл: пОНЯТИЕ ПЕРЕМЕННОЙ В ПРОГРАММИРОВАНИИ.виды и типы переменных.pdf
Добавлен: 18.05.2023
Просмотров: 196
Скачиваний: 3
С увеличением количества переменных, увеличивается вероятность взаимных блокировок.
Например, на языке С/С++ можно привести следующие примеры кода:
int a; /* Объявление глобальной целочисленной переменной «а» */
float b = 6; /* Объявление глобальной переменной с плавающей запятой «b» и присваивание ей значения «6» */
int main(void)
{
a = 12; /* Присваивание переменной «а» значения «12» */
return a+b;
}
2.3 ТИПЫ ПЕРЕМЕННЫХ
Тип переменных, также известный как тип данных, это вид классификации, отмечающий одних из различных видов данных. Скажем так: тип описывает возможные значения структуры (например, переменной), её семантическое значение и способ хранения в памяти. Типы можно разбить на категории:
1.Простые типы — варьируются в зависимости от языка, но самые основные — это целые, числа с плавающей запятой, булевы величины и символы.
2.Сложные типы —состоят из несколько примитивных типов, например, массив или запись (но не хэш). Все сложные типы считаются структурами данных.
3.Абстрактные типы — типы, у которых нет конкретной реализации, такие как хэш, множество, очередь и стек.
4.Прочие типы — например, указатели (тип, в значении которого хранится ссылка на другое место в памяти).
Подробнее рассмотрим простые и сложные типы переменных так они более распространены.
Простые типы в свою очередь делятся на:
1.Дискретные (можно перечислить возможные значения):
- целые (integer, longint)
- символьный (char)
- логический (boolean)
- диапазон (часть значений стандартного дискретного типа, например, 1..100)
- перечисляемый (явно перечислены все допустмые значения)
2. Вещественные (real, double, extended) — служат для представления действительных чисел с ограниченной точностью.
В основном простые типы — это типы о объектах, которых, постоянных или переменных, можно сказать следующее:
1. Работа осуществляется с помощью конструкций языка;
2. Внутреннее представление значений объектов зависит от реализации транслятора (интерпретатора или компилятора) и соответственно от платформы;
3. Основой для построения других объектов служат объекты, которые не включают в себя другие объекты.
Создание переносимого кода (кода, результат компилирования/интерпретации которого разными трансляторами одинаков на разных платформах) возможно, если не пытаться интерпретировать значения простых типов. Например, основанием системы счисления числа могут отличаться на разных платформах, порядком байт, разрядностью, форматом представления. При работе с форматами представления чисел переносимость теряется, но код выполняется быстрее.
В каждом языке программирования доступны разные простые типы данных. В некоторых языках для контролеров с программируемой логикой имеются простые типы для хранения времени. Способы записи констант разных типов определяются стандартом языка. Например, запись 1 может описывать константу целого типа, а запись 1.0 - вещественного.
Введение простых типов преследовало несколько целей:
- Упрощение жизни программистов путём предоставления стандартных контейнеров для размещения данных;
- Предотвращение ошибок и неоднозначностей, связанных со случайным или преднамеренным доступом к внутреннему представлению значений простых типов.
- Предотвращение логических ошибок (ошибок программиста), связанных с применением к данным несвойственных им команд;
Большое количество языков программирования содержат предопределённые функции для работы с простыми типами:
- функция для получения знака числа;
- функция для проверки чётности/нечётности числа
- функция для получения модуля числа;
- функции для приведения типов с округлением или без.
- функции для получения целой и дробной частей вещественного числа;
Некоторые языки (например, C и C++) не ограничивают программиста в выборе способа обработки значений простых типов, даже позволяют определить поля для простого типа.
Сложные или структурированные типы
- Массив (фиксированное количество данных одного типа)
- Строка
- Запись (связанные данные, в общем случае, разных типов)
- Множество
- Файл (данные одного типа, хранящиеся на внешнем носителе)
В разных языках программирования набор базовых сложных типов может несколько отличаться чаще по названию и деталям реализации. Но также есть и объективные критерии — однотипность элементов и способ доступа, позволяющие выделить главные представители сложных типов.
Очень важной идеей, родившейся на границе 60-70-х годов XX века, является возможность произвольного конструирования нужных структур из небольшого набора предопределённых типов. Чем адекватнее программист смоделировал обрабатываемые данные в рамках такого «конструктора», тем безошибочнее и долговечнее будет разработанная программа.
Приведем примеры типов как простейших, так и сложных которые чаще всего используются в языках программирования.
Integer (простой) – целый тип. Переменные этого типа могут хранить целые числа в диапазоне от −2147483648 до 2147483647 (это −231 и 231−1).
Real (сложный) – вещественный тип. Так называемые числа с плавающей точкой. Может быть обычной десятичной дробью (например, 1234.543), но может также содержать порядок – символ «е» и какое-либо число за ним, например, 1.2345е3. Такая запись означает, что число 1.2345 нужно умножить на 103. Максимальное количество цифр в числе 15, порядок может быть в диапазоне от −308 до 308.
Char (простой) – символьный тип. Значением этой переменной может быть одиночный символ – буква латинского алфавита (большие и малые буквы здесь различаются), цифра или какой-либо из специальных символов.
String(сложный) – строка. Значения — наборы символов.
Boolean(простой) – логический тип. Переменная может принимать два значения: true (истина) и false (ложь). Такие значения могут быть, например, у логических выражений наподобие «x>2». Если истинно, что x>2, то выражение принимает значение true иначе значение false.
2.4 ПРОВЕРКА СООТВЕТСТВИЯ ТИПОВ ПЕРЕМЕННЫХ
В различных языках могут различаться примитивные типы и структуры данных, но принцип везде один. Тип просто определяет набор правил и протоколов, которым должен соответствовать элемент данных.
Существование типов не имеет смысла без процесса подтверждения того, что эти типы имеют логический смысл и программа может быть корректно исполнена. Тут и приходит на помощь проверка соответствия типов. Это процесс подтверждения и применения ограничений типов, и он может проходить как во время компиляции (т.е. статически), так и во время выполнения (т.е. динамически). Проверка соответствия типов нужна, чтобы убедиться в типобезопасности программы, что сведёт количество ошибок, связанных с типами, к минимуму. Это такие ошибки, которые возникают, когда операция производится с тем типом, с каким она производиться не должна: например, когда целое число принимается за число с плавающей запятой, или когда происходит сложения строки и целого: x = 1 + "2"
Хотя во многих языках и строки, и числа могут использовать оператор +, это зачастую приводит к ошибкам типа, поскольку это выражение обычно не работает с разными типами данных.
Для случая не типобезопасной программы единого алгоритма действий нет. Какие-то языки выдают ошибку типа, которая останавливает компиляцию или выполнение, а в каких-то есть встроенные обработчики таких ошибок (что позволяет разработчикам порой ошибаться при работе с типами). Вне зависимости от этого, процесс проверки типов — это необходимость.
Теперь, когда мы знаем, что такое типы и как работает проверка соответствия типов, можем рассмотреть, как работают статическая, динамическая и постепенная типизация переменных.
- Языки со статической типизацией (static typing languages).
- Языки с динамической типизацией (dynamic typing languages).
- Языки с постепенной типизацией (gradual typing languages).
В последнее время наблюдается четкое движение в сторону более строгих и мощных систем типизации в программировании, поэтому важно понимать, о чем идет речь, когда говорят о типах и типизации.
Статическая типизация — широко используемый приём в языках программирования при котором параметр подпрограммы, переменная возвращаемое значение функции связывается с типом в момент объявления и тип не может быть изменён в последующим (параметр или переменная будут принимать, а функция — возвращать значения только этого типа). Существуют такие примеры статически типизированных языков — С++, Ада, D, Паскаль, Nim , Java, ML.
Статические языки проверяют типы в программе во время компиляции, еще до запуска программы. Любая программа, в которой типы нарушают правила языка, считается некорректной. Например, большинство статических языков отклонит выражение "a" + 1 (язык Си — это исключение из этого правила). Компилятор знает, что "a" — это строка, а 1 — это целое число, и что + работает только когда левая и правая часть относятся к одному типу. Так что ему не нужно запускать программу чтобы понять, что существует проблема. Каждое выражение в статически типизированном языке относится к определенному типу, который можно определить без запуска кода.
Многие статически типизированные языки требуют обозначать тип. Функция в Java выглядит следующим образом public int add(int x, int y) принимает два целых числа и возвращает третье целое число. Другие статически типизированные языки могут определить тип автоматически. Та же самая функция сложения в Haskell выглядит так: add x y = x + y. Мы не сообщаем языку типы, но он может определить их сам, потому что знает, что + работает только на числах, так что x и y должны быть числами, значит функция add принимает два числа как аргументы.
Это не уменьшает "статичность" системы типов. Система типов в Haskell знаменита своей статичностью, строгостью и мощностью, и по всем этим фронтам Haskell опережает Java.
Преимущества статической типизации заключаются в следующем:
- Статическая типизация даёт самый простой машинный код. Поэтому для языков, дающих исполняемые файлы ОС или JIT-компилируемые промежуточные коды она очень удобна.
- Большинство ошибок исключаются уже на стадии компиляции. 3.
- Статическая типизация хорошо подходит для написания сложного, но быстрого кода.
- В интегрированной среде разработки релевантное автодополнение более осуществимо, особенно если типизация — сильная статическая: можно отбросить множество вариантов как не подходящие по типу.
- Чем проект больше и сложнее в реализации, тем большее преимущество дает использование статической типизации.
К недостаткам статической типизации относятся:
- Языки с недостаточно проработанной математической базой оказываются довольно многословными: каждый раз нужно указывать, какого типа будет переменная. В некоторых языках присутствует автоматическое выведение типа, но оно может привести к труднонаходимым ошибкам. IDE функции нивелируется, например, quick fix.
Но для языков семейства ML это не является недостатком так как они основаны на «главной типизации» которая одновременно автоматически выводит наиболее общий тип всякого выражения и строго проверяет согласование типов зависимостей. Это придаёт языку выразительность динамически типизируемых, но обеспечивает лучшую типобезопасность и быстродействие.
- Очень тяжело и неудобно работать с данными из внешних источников (например, в десериализации данных и реляционных СУБД).
Динамическая типизация — это такой приём, который используется в языках спецификации и языках программирования при котором переменная связывается с типом не в момент объявления переменной, а в момент присваивания значения. Таким образом, одна и та же переменная в различных участках программы может принимать значения разных типов.
Динамически типизированные языки не требуют указывать тип, но и не определяют его сами. Типы переменных неизвестны до того момента, когда у них есть конкретные значения при запуске.
Например, функция в Python
def f(x, y):
return x + y
Даная функция может складывать два целых числа, склеивать строки, списки и так далее, и мы не можем понять, что именно происходит, пока не запустим программу. Возможно, в какой-то момент функцию f вызовут с двумя строками, и с двумя числами в другой момент. В таком случае x и y будут содержать значения разных типов в разное время. Поэтому говорят, что значения в динамических языках обладают типом, но переменные и функции — нет. Значение 1 это определенно integer, но x и y могут быть чем угодно.
Также можно привести пример динамической типизации в таких языках как:
В языке программирования Lua;
var="string" -- Переменная строкового типа
var={} -- Переменная стала таблицей
oldprint=print
print=1 -- Такое тоже возможно!
print("somestring") -- attempt to call a nil value
oldprint("somestring") – somestring
В языке программирования JavaScript;
var res = "string1"; alert(res); // выводит 'string1'
res = 1; alert(res); // выводит 1