← Volver al listado de tecnologías
Funciones en Zig
Funciones
Funciones Básicas
const std = @import("std");
// Función simple
fn saludar() void {
std.debug.print("¡Hola!\n", .{});
}
// Con parámetros y retorno
fn sumar(a: i32, b: i32) i32 {
return a + b;
}
// Múltiples parámetros del mismo tipo
fn maximo(a: i32, b: i32) i32 {
return if (a > b) a else b;
}
pub fn main() void {
saludar();
const resultado = sumar(10, 20);
std.debug.print("Suma: {d}\n", .{resultado});
std.debug.print("Máximo: {d}\n", .{maximo(5, 8)});
}
Funciones Públicas y Privadas
// Pública - accesible desde otros módulos
pub fn funcionPublica() void {}
// Privada - solo accesible en este archivo
fn funcionPrivada() void {}
// Export para C ABI
export fn funcionC() callconv(.C) void {}
Parámetros por Valor y Referencia
const std = @import("std");
// Por valor (copia)
fn duplicar(n: i32) i32 {
return n * 2;
}
// Por referencia constante (solo lectura)
fn sumarArray(arr: []const i32) i32 {
var suma: i32 = 0;
for (arr) |n| suma += n;
return suma;
}
// Por referencia mutable
fn incrementarTodos(arr: []i32) void {
for (arr) |*n| {
n.* += 1;
}
}
// Puntero mutable
fn intercambiar(a: *i32, b: *i32) void {
const temp = a.*;
a.* = b.*;
b.* = temp;
}
pub fn main() void {
var numeros = [_]i32{ 1, 2, 3 };
incrementarTodos(&numeros);
std.debug.print("Suma: {d}\n", .{sumarArray(&numeros)}); // 9
var x: i32 = 5;
var y: i32 = 10;
intercambiar(&x, &y);
std.debug.print("x={d}, y={d}\n", .{ x, y }); // x=10, y=5
}
Retornos Múltiples con Structs
const std = @import("std");
const DivisionResultado = struct {
cociente: i32,
resto: i32,
};
fn dividirConResto(dividendo: i32, divisor: i32) DivisionResultado {
return .{
.cociente = @divTrunc(dividendo, divisor),
.resto = @rem(dividendo, divisor),
};
}
pub fn main() void {
const resultado = dividirConResto(17, 5);
std.debug.print("17 / 5 = {d} resto {d}\n", .{
resultado.cociente,
resultado.resto
});
}
Funciones con Errores
const std = @import("std");
const MathError = error{
DivisionPorCero,
Overflow,
};
fn dividirSeguro(a: i32, b: i32) MathError!i32 {
if (b == 0) return MathError.DivisionPorCero;
return @divTrunc(a, b);
}
pub fn main() void {
// Usando try (propaga el error)
const r1 = dividirSeguro(10, 2) catch |err| {
std.debug.print("Error: {}\n", .{err});
return;
};
std.debug.print("10/2 = {d}\n", .{r1});
// Usando catch con valor por defecto
const r2 = dividirSeguro(10, 0) catch 0;
std.debug.print("10/0 = {d}\n", .{r2});
}
Funciones Genéricas con Comptime
const std = @import("std");
fn maximoGenerico(comptime T: type, a: T, b: T) T {
return if (a > b) a else b;
}
fn llenarArray(comptime T: type, arr: []T, valor: T) void {
for (arr) |*elem| {
elem.* = valor;
}
}
pub fn main() void {
std.debug.print("Max i32: {d}\n", .{maximoGenerico(i32, 5, 10)});
std.debug.print("Max f64: {d}\n", .{maximoGenerico(f64, 3.14, 2.71)});
var arr: [5]u8 = undefined;
llenarArray(u8, &arr, 42);
}
Funciones como Valores
const std = @import("std");
fn sumar(a: i32, b: i32) i32 {
return a + b;
}
fn restar(a: i32, b: i32) i32 {
return a - b;
}
fn aplicar(f: *const fn (i32, i32) i32, a: i32, b: i32) i32 {
return f(a, b);
}
pub fn main() void {
const resultado1 = aplicar(sumar, 10, 5);
const resultado2 = aplicar(restar, 10, 5);
std.debug.print("Sumar: {d}, Restar: {d}\n", .{ resultado1, resultado2 });
}
Recursión
const std = @import("std");
fn fibonacci(n: u32) u32 {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// Versión con tail call optimization
fn fibonacciTail(n: u32, a: u32, b: u32) u32 {
if (n == 0) return a;
if (n == 1) return b;
return @call(.always_tail, fibonacciTail, .{ n - 1, b, a + b });
}
pub fn main() void {
std.debug.print("Fib(10): {d}\n", .{fibonacci(10)});
std.debug.print("FibTail(10): {d}\n", .{fibonacciTail(10, 0, 1)});
}
Testing de Funciones
const std = @import("std");
const testing = std.testing;
fn sumar(a: i32, b: i32) i32 {
return a + b;
}
fn multiplicar(a: i32, b: i32) i32 {
return a * b;
}
const MathError = error{DivisionPorCero};
fn dividir(a: i32, b: i32) MathError!i32 {
if (b == 0) return MathError.DivisionPorCero;
return @divTrunc(a, b);
}
fn factorial(n: u32) u32 {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
fn maximoGenerico(comptime T: type, a: T, b: T) T {
return if (a > b) a else b;
}
fn intercambiar(a: *i32, b: *i32) void {
const temp = a.*;
a.* = b.*;
b.* = temp;
}
test "funciones básicas" {
try testing.expectEqual(@as(i32, 15), sumar(10, 5));
try testing.expectEqual(@as(i32, 0), sumar(-5, 5));
try testing.expectEqual(@as(i32, 50), multiplicar(10, 5));
}
test "función con errores - caso exitoso" {
const resultado = try dividir(10, 2);
try testing.expectEqual(@as(i32, 5), resultado);
}
test "función con errores - división por cero" {
const resultado = dividir(10, 0);
try testing.expectError(MathError.DivisionPorCero, resultado);
}
test "función recursiva" {
try testing.expectEqual(@as(u32, 1), factorial(0));
try testing.expectEqual(@as(u32, 1), factorial(1));
try testing.expectEqual(@as(u32, 120), factorial(5));
}
test "función genérica" {
try testing.expectEqual(@as(i32, 10), maximoGenerico(i32, 5, 10));
try testing.expectEqual(@as(f64, 3.14), maximoGenerico(f64, 2.71, 3.14));
try testing.expectEqual(@as(u8, 255), maximoGenerico(u8, 100, 255));
}
test "función con punteros" {
var a: i32 = 5;
var b: i32 = 10;
intercambiar(&a, &b);
try testing.expectEqual(@as(i32, 10), a);
try testing.expectEqual(@as(i32, 5), b);
}
test "función con slice mutable" {
var arr = [_]i32{ 1, 2, 3 };
for (&arr) |*n| {
n.* *= 2;
}
try testing.expectEqual(@as(i32, 2), arr[0]);
try testing.expectEqual(@as(i32, 4), arr[1]);
try testing.expectEqual(@as(i32, 6), arr[2]);
}
Ejercicios
- Crea una función que calcule la potencia de un número (recursiva e iterativa)
- Implementa una función genérica que encuentre el mínimo en un slice
- Crea una función que valide un email y retorne un error si es inválido
Resumen
- Las funciones se definen con
fny pueden serpubo privadas - Los parámetros pueden ser por valor, referencia constante o mutable
- Los errores se manejan con
error!Tytry/catch comptimepermite crear funciones genéricas- Las funciones pueden ser valores y pasarse como parámetros