Uso de @src().line en Zig
El macro @src() proporciona información de depuración en tiempo de compilación sobre el lugar exacto del código fuente donde se invoca. Entre sus campos se encuentra .line, que devuelve el número de línea (comenzando en 1) donde se encuentra el @src(). Este valor es muy útil cuando se desea incluir la ubicación de una llamada de función, de una aserción, de un error personalizado o de cualquier otra operación que requiera trazabilidad.
Conceptos básicos de @src()
file– ruta del fichero fuente.line– número de línea donde se ejecuta el macro.column– número de columna (columna de código).- También se puede usar
@src().offsetpara obtener la posición absoluta del byte en el fichero.
La sintaxis se escribe siempre dentro de una expresión Zig: @src().line. Zig sustituye esto durante la compilación por un literal entero con el número de línea correspondiente.
Cómo acceder a la línea actual
A continuación se muestra un ejemplo mínimo que ilustra cómo obtener el número de línea y mostrarlo en la consola:
// main.zig
const std = @import("std");
pub fn main() void {
// Declaramos una variable para almacenar la línea donde se invoca @src()
const lineNum = @src().line;
// Imprimimos el número de línea utilizando la función writeln
std.debug.print("Estoy en la línea {d}\n", .{lineNum});
}
Comentarios línea por línea:
// main.zig
// Importamos el módulo estándar de Zig para acceder a funciones de I/O
const std = @import("std");
// Declaramos la función principal del programa (punto de entrada)
pub fn main() void {
// @src().line devuelve el número de línea actual (en este caso 5)
const lineNum = @src().line;
// std.debug.print imprime un formato con un placeholder {d}
// y sustituye por el valor de lineNum
std.debug.print("Estoy en la línea {d}\n", .{lineNum});
}
Ejemplo práctico: registro de errores con ubicación
En proyectos reales es común generar mensajes de error que incluyan la ubicación exacta del problema. El siguiente código define una macro logError que imprime un mensaje con el fichero y la línea donde se llamó.
// logger.zig
const std = @import("std");
// Macro que recibe un mensaje y lo imprime con la ubicación de origen
fn logError(msg: []const u8, src: @SourceLocation) void {
// Imprime el nombre del fichero y la línea donde se llamó a logError
std.debug.print("[{s}:{d}] ERROR: {s}\n", .{ src.file, src.line, msg });
}
// Función que genera un error de ejemplo
pub fn divide(a: i32, b: i32) !i32 {
if (b == 0) {
// @src() captura la ubicación de esta llamada
// Pasamos esa ubicación al logger para que incluya la línea del error
logError("División por cero", @src());
return error.DivisionByZero;
}
return a / b;
}
Desglose comentado:
// logger.zig
const std = @import("std");
// Definimos una función que recibirá el mensaje y la ubicación de origen
fn logError(msg: []const u8, src: @SourceLocation) void {
// std.debug.print recibe una cadena con placeholders:
// {s} para string, {d} para entero decimal.
// La ubicación se desglosa en file y line.
std.debug.print("[{s}:{d}] ERROR: {s}\n", .{ src.file, src.line, msg });
}
// Función que intenta dividir y lanza un error si el divisor es cero
pub fn divide(a: i32, b: i32) !i32 {
if (b == 0) {
// @src() devuelve la ubicación de la siguiente línea
logError("División por cero", @src());
return error.DivisionByZero;
}
return a / b;
}
Explicación paso a paso del flujo de ejecución
- El programador llama a
divide(10, 0)en algún punto del código. - La función
dividedetecta queb == 0y ejecuta la ramaif. - Dentro de la rama,
@src()captura la línea donde se llama alogError(por ejemplo, línea 11). - El
logErrorimprime:[main.zig:11] ERROR: División por cero. - Finalmente,
dividedevuelve el errorDivisionByZero.
Situaciones donde @src().line es especialmente útil
- Depuración de código con mensajes de
std.debug.print. - Definición de macros de aserción que muestran la línea exacta de fallo.
- Generación
