Это материал для тех, кто только начал изучать программирование.
Типичная операция в языках программирования выглядит примерно так:
a = 5
Здесь мы переменной a присваиваем значение 5. Чуть более сложный пример выглядит так:
a = a + 5
Здесь мы к переменной a прибавляем 5.
Во многих языках программирования (C, C++, Python, Java, PHP, PERL, JavaScript...) мы можем встретить укороченную запись такого вида:
a += 5
Она делает то же самое, что a = a + 5. В чём отличие, и зачем она?
Самая очевидная причина – так пишется короче и быстрее. Особенно это будет заметно, если переменная будет называться не одной буквой. Достаточно сравнить:
totalTicketsSold = totalTicketsSold + 5
и
totalTicketsSold += 5
Если же вы прибавляете не 5, а 1, то именно для единицы существует ещё более короткая операция (язык Python здесь придется вычеркнуть):
totalTicketsSold++
И чтобы вычесть 1:
totalTicketsSold--
Ситуация становится интересной – почему есть дополнительная операция специально для единицы? Только ли в краткости дело? Нет.
Эти операции, хоть и делают одно и то же, по натуре своей реально отличаются. Правда, на данный момент нет смысла говорить о различиях. Они заметны только на низком уровне, в машинных кодах. А современные трансляторы языков программирования так оптимизируют код, что на низком уровне между этими операциями разницы скорее всего никакой не будет. Поэтому я расскажу про различия только в историческом контексте, для понимания того, откуда вообще они взялись.
Давайте ещё раз посмотрим на выражение
a = a + 5
Это двуместное (для особо грамотных: бинарное) выражение, то есть у него есть левая часть (a) и правая часть (a + 5). Правая часть присваивается левой части. Правая часть, однако – это тоже выражение. Поэтому сначала надо вычислить её. Если весь этот процесс разбить на шаги и перевести в машинные инструкции, то получим:
- Скопировать переменную a во временный регистр
- Прибавить число 5 к временному регистру
- Записать в переменную a содержимое временного регистра
Здесь получается промежуточный результат во временном регистре. А получается он потому, что синтаксис требует сначала вычислить правую часть выражения, а только потом присвоить её.
Теперь посмотрим на шаги для выражения a += 5:
- Прибавить к переменной a число 5
Всё! Результат получен за 1 шаг и без промежуточных результатов.
Теперь посмотрим на шаги для выражения a++:
- Увеличить переменную a на 1
Да! Есть отдельная, специальная машинная инструкция, чтобы делать именно увеличение (инкремент) или уменьшение (декремент) на 1. Это самая короткая и быстрая инструкция.
Использование укороченных инструкций было важно для оптимизации кода, но как я сказал выше, современные трансляторы языков сами справляются с оптимизацией, поэтому остаётся только одно применение для таких инструкций – более короткий код.
Короткая запись существует для почти всех операций:
a -= 5
a *= 5
a /= 5
a %= 5
a &= 5
и т.д.
Осталось рассмотреть особенности операций инкремента на 1 (++) и декремента на 1 (--). Это одноместные (для особо грамотных: унарные) операции, то есть у выражения нет правой части. Операция совершается непосредственно над переменной и сразу же получается результат в виде значения этой переменной.
Это значит, что данное выражение можно вычислять и сразу присваивать, без промежуточных результатов:
b = a++
То есть можно одновременно присвоить b = a, и увеличить a на 1. Есть, однако, один нюанс: при записи в таком виде у переменной a сначала берется значение, а потом она увеличивается на 1. Если a = 5, то после выполнения
b = a++
получим: b = 5, a = 6. Переменной b присвоилось 5, а не 6, потому что переменная a стала 6 уже после этого.
Но есть и другая запись:
b = ++a
Здесь, как видим, операция ++ написана не после, а перед переменной. Это значит, что переменная сначала увеличится, а потом уже возьмется её значение. И после такой операции получится уже b = 6, a = 6.
Давайте повторим: b = a++ это то же самое, что
b = a
a++
А b = ++a это то же самое, что
a++
b = a
В очень многих случаях одноместный инкремент или декремент вам пригодится, чтобы быстро и просто записать некую операцию. Например, мы вручную заполняем массив, проходя по всем его элементам:
i = 0;
while (i < a.length) a[i++] = 0;
В этом примере элементу массива с адресом i присваивается 0, после чего над i делается операция ++, то есть i переходит на следующий элемент массива.
Для тренировки можно подумать над тем, что получится здесь:
i = 0;
while (i < 5) a[i++] = i;
Ну и пример реального кода – сколько здесь одноместных операций?