Операторы Zig

Операторы и выражения — это фундаментальные компоненты языков программирования, используемые для выполнения различных операций.

В Zig операторы можно разделить на несколько категорий, включая арифметические операторы, операторы сравнения, логические операторы, побитовые операторы, операторы присваивания и другие операторы.

Ниже приведены подробные описания и примеры для каждого типа оператора.

Арифметические операторы

OperatorОписание
+Сложение
-Вычитание
*Умножение
/Деление
%Остаток (операция по модулю)

Пример

const std = @import("std");

pub fn main() void {
    const a: i32 = 5;
    const b: i32 = 3;
   
    const add: i32 = a + b;
    const subtract: i32 = a - b;
    const multiply: i32 = a * b;
    const divide: i32 = a / b;
    const remainder: i32 = a % b;
   
    std.debug.print("a + b = {}\n", .{add});
    std.debug.print("a - b = {}\n", .{subtract});
    std.debug.print("a * b = {}\n", .{multiply});
    std.debug.print("a / b = {}\n", .{divide});
    std.debug.print("a % b = {}\n", .{remainder});
}

Скомпилированный вывод:

a + b = 8
a - b = 2
a * b = 15
a / b = 1
a % b = 2

Операторы отношения

OperatorОписание
==Равно
!=Не равно
>Больше
<Меньше
>=Больше или равно
<=Меньше или равно

Пример

const std = @import("std");

pub fn main() void {
    const a: i32 = 5;
    const b: i32 = 3;

    const equal: bool = a == b;
    const not_equal: bool = a != b;
    const greater: bool = a > b;
    const less: bool = a < b;
    const greater_equal: bool = a >= b;
    const less_equal: bool = a <= b;

    std.debug.print("a == b: {}\n", .{equal});
    std.debug.print("a != b: {}\n", .{not_equal});
    std.debug.print("a > b: {}\n", .{greater});
    std.debug.print("a < b: {}\n", .{less});
    std.debug.print("a >= b: {}\n", .{greater_equal});
    std.debug.print("a <= b: {}\n", .{less_equal});
}

Скомпилированный вывод:

a == b: false
a != b: true
a > b: true
a < b: false
a >= b: true
a <= b: false

Логические операторы

OperatorОписание
иЛогическое И
илиЛогическое ИЛИ
!Логическое НЕ

Пример

const std = @import("std");

pub fn main() void {
    const a: bool = true;
    const b: bool = false;

    const and_result: bool = a and b;
    const or_result: bool = a or b;
    const not_result: bool = !a;

    std.debug.print("a and b: {}\n", .{and_result}); // false
    std.debug.print("a or b: {}\n", .{or_result}); // true
    std.debug.print("!a: {}\n", .{not_result}); // false
}

Скомпилированный вывод:

a and b: false
a or b: true
!a: false

Побитовые операторы

OperatorОписание
&Побитовое И
|Побитовое ИЛИ
^Побитовое XOR
~Побитовое НЕ
<<Сдвиг влево
>>Сдвиг вправо

Пример

const std = @import("std");

pub fn main() void {
    const a: i32 = 5;  // 0101
    const b: i32 = 3;  // 0011

    const bit_and: i32 = a & b;      // 0001
    const bit_or: i32 = a | b;       // 0111
    const bit_xor: i32 = a ^ b;      // 0110
    const bit_not: i32 = ~a;         // 11111111111111111111111111111010
    const left_shift: i32 = a << 1;  // 1010
    const right_shift: i32 = a >> 1; // 0010

    std.debug.print("a & b: {}\n", .{bit_and});
    std.debug.print("a | b: {}\n", .{bit_or});
    std.debug.print("a ^ b: {}\n", .{bit_xor});
    std.debug.print("~a: {}\n", .{bit_not});
    std.debug.print("a << 1: {}\n", .{left_shift});
    std.debug.print("a >> 1: {}\n", .{right_shift});
}

Скомпилированный вывод:

a & b: 1
a | b: 7
a ^ b: 6
~a: -6
a << 1: 10
a >> 1: 2

Операторы присваивания

OperatorОписание
=Присваивание
+=Присваивание со сложением
-=Присваивание с вычитанием
*=Присваивание с умножением
/=Присваивание с делением
%=Присваивание с остатком
&=Присваивание с побитовым И
|=Присваивание с побитовым ИЛИ
^=Присваивание с побитовым исключающим ИЛИ
<<=Присваивание сдвига влево
>>=Присваивание сдвига вправо

Пример

const std = @import("std");

pub fn main() void {
    var a: i32 = 5;
    const b: i32 = 3;

    a += b; // эквивалентно a = a + b;
    std.debug.print("a += b: {}\n", .{a});

    a -= b; // эквивалентно a = a - b;
    std.debug.print("a -= b: {}\n", .{a});

    a *= b; // эквивалентно a = a * b;
    std.debug.print("a *= b: {}\n", .{a});

    a = @divTrunc(a, b); // эквивалентно a = a / b;
    std.debug.print("a /= b: {}\n", .{a});

    a = @mod(a, b); // эквивалентно a = a % b;
    std.debug.print("a %= b: {}\n", .{a});

    a &= b; // эквивалентно a = a & b;
    std.debug.print("a &= b: {}\n", .{a});

    a |= b; // эквивалентно a = a | b;
    std.debug.print("a |= b: {}\n", .{a});

    a ^= b; // эквивалентно a = a ^ b;
    std.debug.print("a ^= b: {}\n", .{a});

    a <<= 1; // эквивалентно a = a << 1;
    std.debug.print("a <<= 1: {}\n", .{a});

    a >>= 1; // эквивалентно a = a >> 1;
    std.debug.print("a >>= 1: {}\n", .{a});
}

Скомпилированный вывод:

a += b: 8
a -= b: 5
a *= b: 15
a /= b: 5
a %= b: 2
a &= b: 2
a |= b: 3
a ^= b: 0
a <<= 1: 0
a >>= 1: 0

Другие операторы

OperatorОписание
++Инкремент
--Декремент

Пример

const std = @import("std");

pub fn main() void {
    var a: i32 = 5;

    a += 1; // В Zig отсутствует оператор ++, вместо него используйте += 1
    std.debug.print("a += 1: {}\n", .{a});

    a -= 1; // В Zig отсутствует оператор --, вместо него используйте -= 1
    std.debug.print("a -= 1: {}\n", .{a});
}

Скомпилированный вывод:

a += 1: 6
a -= 1: 5

Приоритет операторов

Ниже приведён список приоритетов операторов Zig, упорядоченный от высшего к низшему:

ПриоритетOperatorОписание
1[]Операция индексации, доступ к массиву или указателю
1.Доступ к члену
2fn_call()Вызов функции
2@builtin()Вызов встроенной функции
3!Распространение ошибок
3?Разворачивание опционального значения
4* &Разыменование указателя и операции взятия адреса
5+ -Унарные плюс и минус
6~Побитовое НЕ
7* / %Умножение, деление, остаток
8+ -Сложение, вычитание
9<< >>Побитовый сдвиг влево, сдвиг вправо
10&Побитовое И
11^Побитовое XOR
12``
13== !=Равно, не равно
13< <= > >=Меньше, меньше или равно, больше, больше или равно
14andЛогическое И
15orЛогическое ИЛИ
16orelseИли иначе вернуть другое значение
17catchЗахват ошибки
18=Присваивание
19->Тело функции-замыкания или обозначение типа возвращаемого значения

Примечания:

  • Ассоциативность: Обычно операторы Zig являются левоассоциативными, но вы можете обратиться к документации в зависимости от конкретной функции оператора.
  • Примечания: Операторы в Zig спроектированы простыми и понятными, они избегают сложных неявных моделей поведения, встречающихся во многих языках, например отсутствия неявного преобразования типов.

Следующий пример показывает, как приоритет операторов влияет на порядок вычисления выражений:

Пример

const std = @import("std");

pub fn main() void {
    const a: i32 = 5;
    const b: i32 = 3;
    const c: i32 = 2;

    // Умножение имеет более высокий приоритет, чем сложение
    const result1: i32 = a + b * c; // 5 + (3 * 2) = 11
    std.debug.print("a + b * c = {}\n", .{result1});

    // Используйте круглые скобки для изменения приоритета
    const result2: i32 = (a + b) * c; // (5 + 3) * 2 = 16
    std.debug.print("(a + b) * c = {}\n", .{result2});

    // Операторы сравнения имеют более высокий приоритет, чем логические операторы
    const result3: bool = a > b and b > c; // (5 > 3) and (3 > 2) = true
    std.debug.print("a > b and b > c = {}\n", .{result3});

    // Логическое НЕ имеет более высокий приоритет, чем логическое И
    const result4: bool = !(a > b) and b > c; // !(5 > 3) and (3 > 2) = false
    std.debug.print("!(a > b) and b > c = {}\n", .{result4});
}

Скомпилированный вывод:

a + b * c = 11
(a + b) * c = 16
a > b and b > c = true
!(a > b) and b > c = false
Другие расширения