Operadores de Zig

Los operadores y las expresiones son componentes básicos utilizados en los lenguajes de programación para realizar diversas operaciones.

En Zig, los operadores se pueden clasificar en varias categorías, incluyendo operadores aritméticos, operadores relacionales, operadores lógicos, operadores de bits, operadores de asignación y otros operadores.

A continuación se presentan las explicaciones detalladas y ejemplos de cada tipo de operador.

Operadores aritméticos

OperadorDescripción
+Adición (suma)
-Sustracción (resta)
*Multiplicación
/División
%Resto (operación módulo)

Ejemplo

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});
}

El resultado de la compilación es:

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

Operadores relacionales

OperadorDescripción
==Igual a
!=No igual a (distinto de)
>Mayor que
<Menor que
>=Mayor o igual que
<=Menor o igual que

Ejemplo

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});
}

El resultado de la compilación es:

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

Operadores lógicos

OperadorDescripción
andY lógico (AND)
orO lógico (OR)
!Negación lógica (NOT)

Ejemplo

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
}

El resultado de la compilación es:

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

Operadores de bits

OperadorDescripción
&Y bit a bit (AND)
|O bit a bit (OR)
^XOR bit a bit
~Complemento bit a bit (NOT)
<<Desplazamiento a la izquierda
>>Desplazamiento a la derecha

Ejemplo

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});
}

El resultado de la compilación es:

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

Operadores de asignación

OperadorDescripción
=Asignación
+=Asignación con suma
-=Asignación con resta
*=Asignación con multiplicación
/=Asignación con división
%=Asignación con resto (módulo)
&=Asignación con Y bit a bit
|=Asignación con O bit a bit
^=Asignación con XOR bit a bit
<<=Asignación con desplazamiento a la izquierda
>>=Asignación con desplazamiento a la derecha

Ejemplo

const std = @import("std");

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

    a += b; // Equivale a a = a + b;
    std.debug.print("a += b: {}\n", .{a});

    a -= b; // Equivale a a = a - b;
    std.debug.print("a -= b: {}\n", .{a});

    a *= b; // Equivale a a = a * b;
    std.debug.print("a *= b: {}\n", .{a});

    a = @divTrunc(a, b); // Equivale a a = a / b;
    std.debug.print("a /= b: {}\n", .{a});

    a = @mod(a, b); // Equivale a a = a % b;
    std.debug.print("a %= b: {}\n", .{a});

    a &= b; // Equivale a a = a & b;
    std.debug.print("a &= b: {}\n", .{a});

    a |= b; // Equivale a a = a | b;
    std.debug.print("a |= b: {}\n", .{a});

    a ^= b; // Equivale a a = a ^ b;
    std.debug.print("a ^= b: {}\n", .{a});

    a <<= 1; // Equivale a a = a << 1;
    std.debug.print("a <<= 1: {}\n", .{a});

    a >>= 1; // Equivale a a = a >> 1;
    std.debug.print("a >>= 1: {}\n", .{a});
}

El resultado de la compilación es:

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

Otros operadores

OperadorDescripción
++Incremento
--Decremento

Ejemplo

const std = @import("std");

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

    a += 1; // Zig no tiene el operador ++, se puede usar += 1 en su lugar
    std.debug.print("a += 1: {}\n", .{a});

    a -= 1; // Zig no tiene el operador --, se puede usar -= 1 en su lugar
    std.debug.print("a -= 1: {}\n", .{a});
}

El resultado de la compilación es:

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

Precedencia de operadores

La siguiente es la lista de precedencia de los operadores de Zig, ordenada de mayor a menor:

PrecedenciaOperadorDescripción
1[]Operación de subíndice, acceso a arreglos o punteros
1.Acceso a miembros
2fn_call()Llamada a función
2@builtin()Llamada a función incorporada (built-in)
3!Propagación de errores
3?Desempaquetado de valores opcionales
4* &Desreferencia de punteros y operaciones de dirección
5+ -Signo positivo y negativo unario
6~Complemento bit a bit
7* / %Multiplicación, división, resto
8+ -Adición, sustracción
9<< >>Desplazamiento bit a bit a la izquierda y a la derecha
10&Y bit a bit
11^XOR bit a bit
12``
13== !=Igualdad, desigualdad
13< <= > >=Menor que, menor o igual que, mayor que, mayor o igual que
14andY lógico
15orO lógico
16orelseO devolver otro valor
17catchCapturar errores
18=Asignación
19->Cuerpo de función de cierre o indicador de tipo de retorno

Nota:

  • Asociatividad: Generalmente, los operadores de Zig son asociativos a la izquierda, pero se puede consultar la documentación según la función específica del operador.
  • Notas importantes: El diseño de los operadores en Zig es simple y claro, evitando muchos comportamientos implícitos complejos presentes en otros lenguajes, como la ausencia de conversión de tipos implícita.

El siguiente ejemplo muestra cómo la precedencia de operadores afecta el orden de evaluación de las expresiones:

Ejemplo

const std = @import("std");

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

    // La multiplicación tiene prioridad sobre la suma
    const result1: i32 = a + b * c; // 5 + (3 * 2) = 11
    std.debug.print("a + b * c = {}\n", .{result1});

    // Usar paréntesis para cambiar la precedencia
    const result2: i32 = (a + b) * c; // (5 + 3) * 2 = 16
    std.debug.print("(a + b) * c = {}\n", .{result2});

    // Los operadores de comparación tienen prioridad sobre los operadores lógicos
    const result3: bool = a > b and b > c; // (5 > 3) and (3 > 2) = true
    std.debug.print("a > b and b > c = {}\n", .{result3});

    // La negación lógica tiene prioridad sobre el Y lógico
    const result4: bool = !(a > b) and b > c; // !(5 > 3) and (3 > 2) = false
    std.debug.print("!(a > b) and b > c = {}\n", .{result4});
}

El resultado de la compilación es:

a + b * c = 11
(a + b) * c = 16
a > b and b > c = true
!(a > b) and b > c = false
Otras extensiones