После того как ты познакомился с типами данных и переменными, пора научиться выполнять над ними операции. Go поддерживает арифметические, логические, побитовые и строковые операции.
Операции — это основа любой программы. Они позволяют обрабатывать данные, принимать решения и создавать полезную функциональность. В этой главе мы изучим не только синтаксис операций, но и их практическое применение в реальных проектах. Особое внимание уделим безопасности кода и обработке потенциальных ошибок.
🔢 Арифметические операции
Арифметические операции — это математические действия над числовыми типами данных. Go поддерживает все стандартные арифметические операции, которые работают с целыми числами (int, int32, int64) и числами с плавающей точкой (float32, float64).
Важно понимать особенности каждой операции, особенно деления, которое ведёт себя по-разному для целых и дробных чисел:
| Операция | Символ | Пример | Результат | 
|---|---|---|---|
| Сложение | + | 2 + 3 | 5 | 
| Вычитание | - | 5 - 2 | 3 | 
| Умножение | * | 4 * 2 | 8 | 
| Деление | / | 10 / 2 | 5 | 
| Остаток | % | 10 % 3 | 1 | 
💡 Деление целых чисел всегда возвращает целое число. Например,
5 / 2 = 2, а не2.5. Для дробного результата нужно использоватьfloat.
var a = 10
var b = 3
fmt.Println(a / b) // 3 (int)
fmt.Println(float64(a) / float64(b)) // 3.3333 (float)
✅ Операторы присваивания
Операторы присваивания — это удобный синтаксический сахар для модификации переменных. Они объединяют арифметическую операцию с присваиванием в одну инструкцию, что делает код более читаемым и менее подверженным ошибкам.
Эти операторы особенно полезны в циклах, при работе с аккумуляторами, счётчиками и при обновлении состояния объектов. Они также снижают вероятность ошибок, когда нужно модифицировать переменную на основе её текущего значения:
x := 5
x = x + 1  // Обычное присваивание | x = 6
x += 2     // Увеличить на 2 | x = 8
x -= 1     // Уменьшить на 1 | x = 7
x *= 3     // Умножить на 3 | x = 21
x /= 2     // Разделить на 2 | x = 10
x %= 3     // Остаток от деления на 3 | x = 1
🧠 Инкремент и декремент
x++ // увеличивает на 1 | эквевалетна записи x = x + 1
x-- // уменьшает на 1 | эквевалетна записи x = x - 1
⚠️ В Go эти операторы — отдельные инструкции. Нельзя писать
y = x++, как в C++ или Java.
🔁 Сравнения (bool-выражения)
Операции сравнения — основа условной логики в программах. Они сравнивают два значения и возвращают булево значение (true или false). Эти операции используются в условных конструкциях (if, switch), циклах (for, while) и любых других местах, где нужно принять решение на основе данных.
Go поддерживает строгую типизацию, поэтому сравнивать можно только значения совместимых типов. Результат сравнения всегда имеет тип bool:
| Операция | Пример | 
|---|---|
== Равно | x == 10 | 
!= Не равно | x != y | 
< Меньше | a < b | 
> Больше | a > b | 
<= Меньше или равно | a <= b | 
>= Больше или равно | a >= b | 
🔗 Логические операции
Логические операторы — это инструменты для создания сложных условий в программах. Они работают с булевыми значениями (true или false) и позволяют комбинировать простые условия в более сложные логические выражения.
Это особенно важно при создании условных конструкций, проверке прав доступа, валидации данных и принятии решений в программе. Логические операторы следуют законам булевой алгебры и используют принцип короткого замыкания — если результат уже можно определить по первому операнду, второй не вычисляется.
&&— логическое И (AND)
Выражение возвращаетtrue, только если оба условия истинны.
Пример:x > 5 && x < 10вернётtrue, еслиxбольше 5 и меньше 10 одновременно.||— логическое ИЛИ (OR)
Выражение возвращаетtrue, если хотя бы одно из условий истинно.
Пример:x < 0 || x > 100вернётtrue, еслиxменьше 0 или больше 100.!— логическое НЕ (NOT)
Инвертирует логическое значение.
Пример:!isReadyвернётtrue, еслиisReadyравноfalse.
📋 Таблица истинности
| A | B | A && B | A || B | !A | 
|---|---|---|---|---|
| true | true | true | true | false | 
| true | false | false | true | false | 
| false | true | false | true | true | 
| false | false | false | false | true | 
📚 Операции со строками
Строки в Go поддерживают ограниченный набор операций по сравнению с числами. Основная операция — конкатенация (объединение строк), которая позволяет создавать новые строки из существующих. Это фундаментальная операция для формирования сообщений, путей к файлам, SQL-запросов и других текстовых структур.
Важно помнить, что строки в Go неизменяемы (immutable), поэтому каждая операция конкатенации создаёт новую строку в памяти:
first := "Hello, "
second := "world!"
greeting := first + second
fmt.Println(greeting) // Hello, world!
💡 В Go строки можно только складывать. Умножать или вычитать нельзя.
🚀 Практические примеры работы с операциями
Операции в Go — это не просто арифметические действия, но и мощные инструменты для решения реальных задач. Рассмотрим несколько примеров, которые показывают, как правильно использовать операции для создания надёжных программ.
Безопасный калькулятор с обработкой ошибок
В реальных проектах важно предусматривать обработку ошибок. Рассмотрим пример функции-калькулятора, которая корректно обрабатывает различные случаи, включая деление на ноль и неподдерживаемые операции:
func calculate(a, b float64, op string) (float64, error) {
    switch op {
    case "+": return a + b, nil
    case "-": return a - b, nil
    case "*": return a * b, nil
    case "/":
        if b == 0 { return 0, errors.New("деление на ноль") }
        return a / b, nil
    default: return 0, errors.New("неподдерживаемая операция")
    }
}
Такой подход делает код более надёжным и предсказуемым. Функция возвращает не только результат вычисления, но и потенциальную ошибку, что позволяет вызывающему коду правильно реагировать на проблемные ситуации. Это типичная практика в Go — всегда возвращать ошибку как второе значение.
Проверка силы пароля
func checkPasswordStrength(password string) string {
    var (
        hasUpper    = false
        hasLower    = false
        hasDigit    = false
        hasSpecial  = false
        length      = len(password)
    )
    for _, char := range password {
        switch {
        case char >= 'A' && char <= 'Z':
            hasUpper = true
        case char >= 'a' && char <= 'z':
            hasLower = true
        case char >= '0' && char <= '9':
            hasDigit = true
        case char == '!' || char == '@' || char == '#' || char == '$':
            hasSpecial = true
        }
    }
    score := 0
    if hasUpper { score++ }
    if hasLower { score++ }
    if hasDigit { score++ }
    if hasSpecial { score++ }
    if length >= 8 { score++ }
    switch {
    case score >= 5:
        return "🔒 Очень сильный"
    case score >= 3:
        return "🔑 Сильный"
    case score >= 2:
        return "⚠️ Средний"
    default:
        return "❌ Слабый"
    }
}
Операторы присваивания для счётчиков
Операторы присваивания (+=, -=, *=) особенно полезны при работе со счётчиками и аккумуляторами. Например, при подсчёте частоты слов в тексте:
// Подсчёт частоты слов
counter := make(map[string]int)
for _, word := range words {
    counter[word]++ // Короткая запись для counter[word] = counter[word] + 1
}
Такой подход делает код чище и понятнее. Оператор ++ автоматически обрабатывает случай, когда ключа ещё нет в карте (создаёт значение 0 и увеличивает его).
🧮 Побитовые операции (продвинутое)
📚 Примечание: Этот раздел предназначен для любознательных читателей. Побитовые операции редко используются в обычной разработке на Go, но полезны для понимания низкоуровневых оптимизаций.
🧮 Побитовые операции
Побитовые операции работают с целыми числами на уровне отдельных битов. Это может быть полезно, когда нужно экономить память, управлять флагами или взаимодействовать с низкоуровневыми структурами (например, сетевые протоколы, работа с оборудованием, сжатие данных и т.д.).
📋 Основные побитовые операторы
&— И (AND): устанавливает бит в 1, если он установлен в обоих операндах|— ИЛИ (OR): устанавливает бит в 1, если он установлен хотя бы в одном операнде^— исключающее ИЛИ (XOR): устанавливает бит в 1, если он установлен только в одном из операндов&^— очистка бита (AND NOT): обнуляет биты, установленные в правом операнде<<— сдвиг влево: сдвигает биты влево на указанное число позиций (умножение на 2ⁿ)>>— сдвиг вправо: сдвигает биты вправо (деление на 2ⁿ)
🔍 Примеры
a := 12        // 1100 в двоичной системе
b := 10        // 1010
result1 := a & b   // 1000 = 8
result2 := a | b   // 1110 = 14
result3 := a ^ b   // 0110 = 6
result4 := a &^ b  // 0100 = 4
result5 := a << 1  // 11000 = 24
result6 := b >> 1  // 0101 = 5
🛠 Примеры использования
Флаги и маски
const ( FlagRead = 1 << 0 // 0001 FlagWrite = 1 << 1 // 0010 FlagExec = 1 << 2 // 0100 ) var perms uint8 = FlagRead | FlagWrite // 0011 if perms&FlagWrite != 0 { fmt.Println("Запись разрешена") }Оптимизация по памяти Побитовые флаги позволяют хранить до 8 независимых булевых значений в одном
uint8.Низкоуровневые вычисления Часто используются в криптографии, коде для микроконтроллеров и сетевых протоколов.
🧠 Побитовые операции — мощный инструмент, но применяются в основном в системном и высокопроизводительном коде. В повседневной разработке на Go они встречаются нечасто, но полезно понимать, как они работают.
🧪 Пример
package main
import "fmt"
func main() {
    x := 10
    y := 3
    fmt.Println("x + y =", x + y)
    fmt.Println("x % y =", x % y)
    fmt.Println("x > y:", x > y)
    fmt.Println("x < 20 && y > 1:", x < 20 && y > 1)
    greeting := "Привет, " + "Go!"
    fmt.Println(greeting)
    // Побитовые операции (используются редко)
    fmt.Println("Побитовые:", x&y, x|y, x<<1)
}
🔍 Вопросы для самопроверки
- Чем отличается 
x++отx += 1? - Что произойдёт при делении 
5 / 2? - Можно ли использовать 
x = y++в Go? - Какие логические операторы ты знаешь?
 - Как соединить две строки в Go?
 - Как безопасно преобразовать 
int64вint8? - Когда могут понадобиться побитовые операции?
 
📌 Главное из главы
- Операции в Go строго типизированы — нельзя складывать числа разных типов без явного преобразования
 - Арифметические операции работают с числами; деление целых чисел всегда даёт целое число
 - Логические операторы (
&&,||,!) используют короткое замыкание для оптимизации - Операторы присваивания (
+=,-=,*=) делают код более читаемым и менее подверженным ошибкам - Инкремент/декремент (
++,--) — отдельные инструкции, не возвращающие значения - Строковые операции ограничены конкатенацией; строки неизменяемы
 - Побитовые операции применяются в системном программировании и работе с флагами
 - Обработка ошибок критически важна для создания надёжных программ
 
🛠 Практические упражнения
Упражнение 1: Расширенный калькулятор
Создайте калькулятор с поддержкой всех базовых операций (+, -, *, /, %), включая обработку ошибок и сравнение целочисленного с дробным делением.
Упражнение 2: Анализатор текста и паролей
Реализуйте функцию анализа строк: подсчёт слов, поиск частых слов, проверка силы паролей с различными критериями безопасности.
Упражнение 3: Работа с операторами присваивания
Напишите программу для обработки массивов чисел с использованием +=, -=, *= для вычисления суммы, произведения и статистических показателей.