0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Переменная в программировании - это именованная область памяти, предназначенная для хранения значения, с которым работает программа. Через переменные код читает, изменяет и передает данные между функциями, модулями и слоями системы.</p>
1
<p>Переменная в программировании - это именованная область памяти, предназначенная для хранения значения, с которым работает программа. Через переменные код читает, изменяет и передает данные между функциями, модулями и слоями системы.</p>
2
<p>Переменная всегда характеризуется тремя основными атрибутами:</p>
2
<p>Переменная всегда характеризуется тремя основными атрибутами:</p>
3
<ul><li><p>имя (идентификатор), по которому к ней обращается программа;</p>
3
<ul><li><p>имя (идентификатор), по которому к ней обращается программа;</p>
4
</li>
4
</li>
5
<li><p>значение, фактически хранящиеся данные;</p>
5
<li><p>значение, фактически хранящиеся данные;</p>
6
</li>
6
</li>
7
<li><p>тип, определяющий набор допустимых значений и операций.</p>
7
<li><p>тип, определяющий набор допустимых значений и операций.</p>
8
</li>
8
</li>
9
</ul><p>Если значение поля памяти не должно изменяться после присвоения, используется константа - логически это та же ячейка памяти, но с запретом на изменение значения.</p>
9
</ul><p>Если значение поля памяти не должно изменяться после присвоения, используется константа - логически это та же ячейка памяти, но с запретом на изменение значения.</p>
10
<h2>Инициализация и объявление переменных</h2>
10
<h2>Инициализация и объявление переменных</h2>
11
<p>Объявление переменной задает ее имя и, в статически типизируемых языках, тип данных. Инициализация присваивает переменной начальное значение. Эти операции могут выполняться совместно или раздельно.</p>
11
<p>Объявление переменной задает ее имя и, в статически типизируемых языках, тип данных. Инициализация присваивает переменной начальное значение. Эти операции могут выполняться совместно или раздельно.</p>
12
<p>Примеры общих шаблонов объявления и инициализации:</p>
12
<p>Примеры общих шаблонов объявления и инициализации:</p>
13
<ul><li><p>C / C++:</p>
13
<ul><li><p>C / C++:</p>
14
<p>int count; - объявление, значение не определено;</p>
14
<p>int count; - объявление, значение не определено;</p>
15
<p>int count = 0; - объявление и инициализация.</p>
15
<p>int count = 0; - объявление и инициализация.</p>
16
</li>
16
</li>
17
<li><p>Java:</p>
17
<li><p>Java:</p>
18
<p>String name = "User"; - обязательная инициализация для полей в большинстве практик.</p>
18
<p>String name = "User"; - обязательная инициализация для полей в большинстве практик.</p>
19
</li>
19
</li>
20
<li><p>JavaScript:</p>
20
<li><p>JavaScript:</p>
21
<p>let value; - объявление, значение undefined;</p>
21
<p>let value; - объявление, значение undefined;</p>
22
<p>let value = 10; - инициализированная переменная.</p>
22
<p>let value = 10; - инициализированная переменная.</p>
23
</li>
23
</li>
24
<li><p>Python:</p>
24
<li><p>Python:</p>
25
<p>x = 5 - фактически сразу создание имени и присвоение значения без явного объявления типа.</p>
25
<p>x = 5 - фактически сразу создание имени и присвоение значения без явного объявления типа.</p>
26
</li>
26
</li>
27
</ul><p>Значение по умолчанию зависит от языка и контекста:</p>
27
</ul><p>Значение по умолчанию зависит от языка и контекста:</p>
28
<ul><li><p>в C использование неинициализированной локальной переменной ведет к неопределенному поведению;</p>
28
<ul><li><p>в C использование неинициализированной локальной переменной ведет к неопределенному поведению;</p>
29
</li>
29
</li>
30
<li><p>в Java локальные переменные должны быть явно инициализированы до чтения;</p>
30
<li><p>в Java локальные переменные должны быть явно инициализированы до чтения;</p>
31
</li>
31
</li>
32
<li><p>в JavaScript переменные, объявленные через var/let/const без присвоения, имеют значение undefined;</p>
32
<li><p>в JavaScript переменные, объявленные через var/let/const без присвоения, имеют значение undefined;</p>
33
</li>
33
</li>
34
<li><p>в Python обращение к имени до первой операции присваивания вызывает NameError.</p>
34
<li><p>в Python обращение к имени до первой операции присваивания вызывает NameError.</p>
35
</li>
35
</li>
36
</ul><p>Явная инициализация при объявлении - базовая практика, снижающая количество скрытых ошибок.</p>
36
</ul><p>Явная инициализация при объявлении - базовая практика, снижающая количество скрытых ошибок.</p>
37
<h2>Область видимости</h2>
37
<h2>Область видимости</h2>
38
<p>Область видимости переменной определяет участок программы, внутри которого к ней можно обращаться по имени. Управление видимостью уменьшает связность кода и предотвращает конфликт имен.</p>
38
<p>Область видимости переменной определяет участок программы, внутри которого к ней можно обращаться по имени. Управление видимостью уменьшает связность кода и предотвращает конфликт имен.</p>
39
<p>Основные разновидности:</p>
39
<p>Основные разновидности:</p>
40
<ul><li><p>локальная область - переменная доступна только внутри функции, метода или блока;</p>
40
<ul><li><p>локальная область - переменная доступна только внутри функции, метода или блока;</p>
41
</li>
41
</li>
42
<li><p>глобальная область - переменная доступна во всем модуле или даже во всем приложении;</p>
42
<li><p>глобальная область - переменная доступна во всем модуле или даже во всем приложении;</p>
43
</li>
43
</li>
44
<li><p>блоковая область - переменная существует внутри конкретного блока { } (например, let и const в JavaScript).</p>
44
<li><p>блоковая область - переменная существует внутри конкретного блока { } (например, let и const в JavaScript).</p>
45
</li>
45
</li>
46
</ul><p>Область видимости следует отличать от времени жизни (lifetime). Переменная может быть недоступна по имени, но физически объект в памяти еще существует, если на него ссылаются другие сущности.</p>
46
</ul><p>Область видимости следует отличать от времени жизни (lifetime). Переменная может быть недоступна по имени, но физически объект в памяти еще существует, если на него ссылаются другие сущности.</p>
47
<p>Чрезмерное использование глобальных переменных приводит к:</p>
47
<p>Чрезмерное использование глобальных переменных приводит к:</p>
48
<ul><li><p>трудной отладке из-за скрытых зависимостей;</p>
48
<ul><li><p>трудной отладке из-за скрытых зависимостей;</p>
49
</li>
49
</li>
50
<li><p>сложности тестирования;</p>
50
<li><p>сложности тестирования;</p>
51
</li>
51
</li>
52
<li><p>росту рисков гонок данных в многопоточной среде.</p>
52
<li><p>росту рисков гонок данных в многопоточной среде.</p>
53
</li>
53
</li>
54
</ul><p>Поэтому рекомендуются:</p>
54
</ul><p>Поэтому рекомендуются:</p>
55
<ul><li><p>минимально возможная область видимости;</p>
55
<ul><li><p>минимально возможная область видимости;</p>
56
</li>
56
</li>
57
<li><p>передача данных через параметры и возвращаемые значения вместо использования глобального состояния.</p>
57
<li><p>передача данных через параметры и возвращаемые значения вместо использования глобального состояния.</p>
58
</li>
58
</li>
59
</ul><h2>Типизация переменных</h2>
59
</ul><h2>Типизация переменных</h2>
60
<p>Тип определяет множество возможных значений и допустимых операций над ними. Существуют два базовых подхода к типизации переменных.</p>
60
<p>Тип определяет множество возможных значений и допустимых операций над ними. Существуют два базовых подхода к типизации переменных.</p>
61
<p>После краткого описания подходов полезно разделить их по моменту проверки:</p>
61
<p>После краткого описания подходов полезно разделить их по моменту проверки:</p>
62
<h3>Статическая и динамическая типизация</h3>
62
<h3>Статическая и динамическая типизация</h3>
63
<p>Статическая типизация:</p>
63
<p>Статическая типизация:</p>
64
<ul><li><p>тип переменной задается при объявлении и не меняется;</p>
64
<ul><li><p>тип переменной задается при объявлении и не меняется;</p>
65
</li>
65
</li>
66
<li><p>несовместимые операции отлавливаются на этапе компиляции;</p>
66
<li><p>несовместимые операции отлавливаются на этапе компиляции;</p>
67
</li>
67
</li>
68
<li><p>пример: int x = 10; x = "text"; в Java или C# вызовет ошибку компиляции.</p>
68
<li><p>пример: int x = 10; x = "text"; в Java или C# вызовет ошибку компиляции.</p>
69
</li>
69
</li>
70
</ul><p>Преимущества:</p>
70
</ul><p>Преимущества:</p>
71
<ul><li><p>раннее обнаружение ошибок;</p>
71
<ul><li><p>раннее обнаружение ошибок;</p>
72
</li>
72
</li>
73
<li><p>более предсказуемое поведение;</p>
73
<li><p>более предсказуемое поведение;</p>
74
</li>
74
</li>
75
<li><p>оптимизация кода компилятором.</p>
75
<li><p>оптимизация кода компилятором.</p>
76
</li>
76
</li>
77
</ul><p>Недостатки:</p>
77
</ul><p>Недостатки:</p>
78
<ul><li><p>меньшая гибкость при работе с неоднородными данными;</p>
78
<ul><li><p>меньшая гибкость при работе с неоднородными данными;</p>
79
</li>
79
</li>
80
<li><p>необходимость явно описывать типы либо использовать вывод типов компилятором.</p>
80
<li><p>необходимость явно описывать типы либо использовать вывод типов компилятором.</p>
81
</li>
81
</li>
82
</ul><p>Динамическая типизация:</p>
82
</ul><p>Динамическая типизация:</p>
83
<ul><li><p>тип привязан к значению, а не к имени переменной;</p>
83
<ul><li><p>тип привязан к значению, а не к имени переменной;</p>
84
</li>
84
</li>
85
<li><p>одна и та же переменная может последовательно хранить значения разных типов;</p>
85
<li><p>одна и та же переменная может последовательно хранить значения разных типов;</p>
86
</li>
86
</li>
87
<li><p>пример в Python: x = 10 → x = "text" - корректно, тип x меняется во время исполнения.</p>
87
<li><p>пример в Python: x = 10 → x = "text" - корректно, тип x меняется во время исполнения.</p>
88
</li>
88
</li>
89
</ul><p>Плюсы:</p>
89
</ul><p>Плюсы:</p>
90
<ul><li><p>гибкость;</p>
90
<ul><li><p>гибкость;</p>
91
</li>
91
</li>
92
<li><p>быстрый прототипинг;</p>
92
<li><p>быстрый прототипинг;</p>
93
</li>
93
</li>
94
<li><p>выразительные структуры данных без сложной типизации.</p>
94
<li><p>выразительные структуры данных без сложной типизации.</p>
95
</li>
95
</li>
96
</ul><p>Минусы:</p>
96
</ul><p>Минусы:</p>
97
<ul><li><p>типовые ошибки проявляются только во время исполнения;</p>
97
<ul><li><p>типовые ошибки проявляются только во время исполнения;</p>
98
</li>
98
</li>
99
<li><p>сложнее статически анализировать и рефакторить код.</p>
99
<li><p>сложнее статически анализировать и рефакторить код.</p>
100
</li>
100
</li>
101
</ul><p>При проектировании ИТ-систем учитывают особенности типизации выбранного языка: требования к безопасному рефакторингу, интеграции, сериализации данных и интерфейсам.</p>
101
</ul><p>При проектировании ИТ-систем учитывают особенности типизации выбранного языка: требования к безопасному рефакторингу, интеграции, сериализации данных и интерфейсам.</p>
102
<h2>Изменение и работа с переменными</h2>
102
<h2>Изменение и работа с переменными</h2>
103
<p>Основная операция над переменной - присваивание. В большинстве языков используется оператор =:</p>
103
<p>Основная операция над переменной - присваивание. В большинстве языков используется оператор =:</p>
104
<ul><li><p>простое присваивание: x = 5;</p>
104
<ul><li><p>простое присваивание: x = 5;</p>
105
</li>
105
</li>
106
<li><p>составные операторы: x += 1, x -= 2, x *= 10 и т. д.</p>
106
<li><p>составные операторы: x += 1, x -= 2, x *= 10 и т. д.</p>
107
</li>
107
</li>
108
</ul><p>Для счетчиков часто применяются операции инкремента и декремента:</p>
108
</ul><p>Для счетчиков часто применяются операции инкремента и декремента:</p>
109
<ul><li><p>x++ / ++x, x-- / --x (C, C++, Java, JavaScript);</p>
109
<ul><li><p>x++ / ++x, x-- / --x (C, C++, Java, JavaScript);</p>
110
</li>
110
</li>
111
<li><p>в языках без этих операторов используется x = x + 1 или x += 1 (Python).</p>
111
<li><p>в языках без этих операторов используется x = x + 1 или x += 1 (Python).</p>
112
</li>
112
</li>
113
</ul><p>Переменные участвуют в:</p>
113
</ul><p>Переменные участвуют в:</p>
114
<ul><li><p>арифметических операциях;</p>
114
<ul><li><p>арифметических операциях;</p>
115
</li>
115
</li>
116
<li><p>логических выражениях;</p>
116
<li><p>логических выражениях;</p>
117
</li>
117
</li>
118
<li><p>конкатенации строк;</p>
118
<li><p>конкатенации строк;</p>
119
</li>
119
</li>
120
<li><p>работе со структурами данных (индексы массивов, ключи словарей).</p>
120
<li><p>работе со структурами данных (индексы массивов, ключи словарей).</p>
121
</li>
121
</li>
122
</ul><p>Важный аспект - передача переменных в функции.</p>
122
</ul><p>Важный аспект - передача переменных в функции.</p>
123
<h3>Передача по значению и по ссылке</h3>
123
<h3>Передача по значению и по ссылке</h3>
124
<p>Модель зависит от языка и типа:</p>
124
<p>Модель зависит от языка и типа:</p>
125
<ul><li><p>передача по значению: в функцию попадает копия значения (например, примитивы в C, Java). Изменение параметра не влияет на исходную переменную;</p>
125
<ul><li><p>передача по значению: в функцию попадает копия значения (например, примитивы в C, Java). Изменение параметра не влияет на исходную переменную;</p>
126
</li>
126
</li>
127
<li><p>передача по ссылке или по указателю: функция получает доступ к тому же объекту в памяти. Изменение состояния объекта видно вызывающему коду.</p>
127
<li><p>передача по ссылке или по указателю: функция получает доступ к тому же объекту в памяти. Изменение состояния объекта видно вызывающему коду.</p>
128
</li>
128
</li>
129
</ul><p>В ряде языков (Java, Python, JavaScript) используется единая модель: по значению передается ссылка на объект. Итог:</p>
129
</ul><p>В ряде языков (Java, Python, JavaScript) используется единая модель: по значению передается ссылка на объект. Итог:</p>
130
<ul><li><p>переназначение параметра (param = ...) не меняет исходную переменную;</p>
130
<ul><li><p>переназначение параметра (param = ...) не меняет исходную переменную;</p>
131
</li>
131
</li>
132
<li><p>изменение внутреннего состояния объекта (param.field = ..., операции с элементами списка) отражается на общем объекте.</p>
132
<li><p>изменение внутреннего состояния объекта (param.field = ..., операции с элементами списка) отражается на общем объекте.</p>
133
</li>
133
</li>
134
</ul><p>Неверное понимание модели передачи часто приводит к трудноотлавливаемым ошибкам мутации.</p>
134
</ul><p>Неверное понимание модели передачи часто приводит к трудноотлавливаемым ошибкам мутации.</p>
135
<h2>Ошибки, связанные с переменными</h2>
135
<h2>Ошибки, связанные с переменными</h2>
136
<p>Наиболее распространенные классы ошибок:</p>
136
<p>Наиболее распространенные классы ошибок:</p>
137
<ul><li><p>использование переменных до инициализации;</p>
137
<ul><li><p>использование переменных до инициализации;</p>
138
</li>
138
</li>
139
<li><p>опечатки в именах и создание "лишних" переменных;</p>
139
<li><p>опечатки в именах и создание "лишних" переменных;</p>
140
</li>
140
</li>
141
<li><p>конфликт имен и затенение (shadowing) переменных внешней области видимости;</p>
141
<li><p>конфликт имен и затенение (shadowing) переменных внешней области видимости;</p>
142
</li>
142
</li>
143
<li><p>неправильный выбор типа (например, использование целого вместо числа с плавающей точкой);</p>
143
<li><p>неправильный выбор типа (например, использование целого вместо числа с плавающей точкой);</p>
144
</li>
144
</li>
145
<li><p>выход за границы массива или диапазона индекса;</p>
145
<li><p>выход за границы массива или диапазона индекса;</p>
146
</li>
146
</li>
147
<li><p>изменение общей переменной из нескольких потоков без синхронизации;</p>
147
<li><p>изменение общей переменной из нескольких потоков без синхронизации;</p>
148
</li>
148
</li>
149
<li><p>изменение разделяемых структур данных по ссылке, когда ожидалась копия.</p>
149
<li><p>изменение разделяемых структур данных по ссылке, когда ожидалась копия.</p>
150
</li>
150
</li>
151
</ul><p>Рекомендации по отладке:</p>
151
</ul><p>Рекомендации по отладке:</p>
152
<ul><li><p>включение максимального уровня предупреждений компилятора;</p>
152
<ul><li><p>включение максимального уровня предупреждений компилятора;</p>
153
</li>
153
</li>
154
<li><p>использование статического анализа и линтеров;</p>
154
<li><p>использование статического анализа и линтеров;</p>
155
</li>
155
</li>
156
<li><p>добавление логирования значений переменных в ключевых точках;</p>
156
<li><p>добавление логирования значений переменных в ключевых точках;</p>
157
</li>
157
</li>
158
<li><p>использование точек останова и watch-выражений в отладчике;</p>
158
<li><p>использование точек останова и watch-выражений в отладчике;</p>
159
</li>
159
</li>
160
<li><p>отказ от глобального состояния в пользу явной передачи данных.</p>
160
<li><p>отказ от глобального состояния в пользу явной передачи данных.</p>
161
</li>
161
</li>
162
</ul><p>Часть ошибок устраняется на уровне соглашений: запрет неинициализированных переменных, ограничение на использование "магических чисел", запрет неконтролируемого изменения полей объектов.</p>
162
</ul><p>Часть ошибок устраняется на уровне соглашений: запрет неинициализированных переменных, ограничение на использование "магических чисел", запрет неконтролируемого изменения полей объектов.</p>
163
<h2>Лучшие практики работы с переменными</h2>
163
<h2>Лучшие практики работы с переменными</h2>
164
<p>Качественная работа с переменными влияет на читаемость, поддерживаемость и надежность ИТ-систем.</p>
164
<p>Качественная работа с переменными влияет на читаемость, поддерживаемость и надежность ИТ-систем.</p>
165
<p>Рекомендуемые практики:</p>
165
<p>Рекомендуемые практики:</p>
166
<ul><li><p>говорящие имена: userCount, orderTotal, timeoutMs вместо a, x1, tmp;</p>
166
<ul><li><p>говорящие имена: userCount, orderTotal, timeoutMs вместо a, x1, tmp;</p>
167
</li>
167
</li>
168
<li><p>следование соглашениям по стилю: camelCase, snake_case, префиксы/суффиксы единиц измерения;</p>
168
<li><p>следование соглашениям по стилю: camelCase, snake_case, префиксы/суффиксы единиц измерения;</p>
169
</li>
169
</li>
170
<li><p>минимизация области видимости: объявление переменной максимально близко к месту использования;</p>
170
<li><p>минимизация области видимости: объявление переменной максимально близко к месту использования;</p>
171
</li>
171
</li>
172
<li><p>неизменяемость по умолчанию: использование констант, const, final, иммутабельных структур там, где изменение не требуется;</p>
172
<li><p>неизменяемость по умолчанию: использование констант, const, final, иммутабельных структур там, где изменение не требуется;</p>
173
</li>
173
</li>
174
<li><p>отсутствие "магических чисел": вынос литералов в именованные константы;</p>
174
<li><p>отсутствие "магических чисел": вынос литералов в именованные константы;</p>
175
</li>
175
</li>
176
<li><p>отдельные переменные для разных смыслов: не использовать одно и то же имя для значений разной природы в пределах длинного блока кода.</p>
176
<li><p>отдельные переменные для разных смыслов: не использовать одно и то же имя для значений разной природы в пределах длинного блока кода.</p>
177
</li>
177
</li>
178
</ul><p>В архитектурном контексте:</p>
178
</ul><p>В архитектурном контексте:</p>
179
<ul><li><p>ограничение глобальных и статических переменных;</p>
179
<ul><li><p>ограничение глобальных и статических переменных;</p>
180
</li>
180
</li>
181
<li><p>хранение состояния в четко определенных слоях (доменная модель, контекст запросов и т. д.);</p>
181
<li><p>хранение состояния в четко определенных слоях (доменная модель, контекст запросов и т. д.);</p>
182
</li>
182
</li>
183
<li><p>явная передача данных через интерфейсы, DTO и контракты API.</p>
183
<li><p>явная передача данных через интерфейсы, DTO и контракты API.</p>
184
</li>
184
</li>
185
</ul><p>Систематическое применение этих подходов делает код предсказуемым, упрощает ревью и снижает количество дефектов, связанных с неправильным использованием переменных.</p>
185
</ul><p>Систематическое применение этих подходов делает код предсказуемым, упрощает ревью и снижает количество дефектов, связанных с неправильным использованием переменных.</p>