HTML Diff
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>