После того как ты познакомился с типами данных и переменными, пора научиться выполнять над ними операции. 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: Работа с операторами присваивания
Напишите программу для обработки массивов чисел с использованием +=
, -=
, *=
для вычисления суммы, произведения и статистических показателей.