Cuando trabajamos con colecciones en Zig, a menudo necesitamos localizar la posición de un elemento específico dentro de un slice. La función std.mem.indexOfScalar está diseñada justamente para ese propósito, permitiendo buscar un valor escalar en un slice de cualquier tipo. En este artículo veremos cómo usarla, entender su firma, y explorar algunos ejemplos útiles con comentarios explicativos.
Fundamentos de std.mem.indexOfScalar
La declaración de la función se encuentra en el módulo std.mem y tiene la siguiente firma:
pub fn indexOfScalar(comptime T: type, haystack: []const T, needle: T) ?usize
- T: El tipo de los elementos del slice. Se pasa como parámetro de tipo en tiempo de compilación (
comptime). - haystack: Slice de tipo
[]const Tdonde se buscará. - needle: Valor escalar del tipo
Tque se desea encontrar. - Retorno:
?usize– si el elemento se encuentra, devuelve su índice; si no, devuelvenull.
Esta función es muy similar a std.mem.indexOf, pero en lugar de comparar slices, compara un solo valor escalar contra cada elemento del slice.
Casos de uso típicos
- Buscar un carácter dentro de un string.
- Localizar un número dentro de un array de enteros.
- Encontrar la posición de una estructura con un campo específico.
- Filtrar índices donde un valor aparece en un vector de booleanos.
Ejemplo 1: Buscar un carácter en un string
Supongamos que tenemos un string literal y queremos saber dónde aparece la letra ‘a’.
const std = @import("std");
pub fn main() void {
// String literal (slice de u8)
const haystack: []const u8 = "zig is fun, a language!";
// Valor que queremos encontrar: 'a'
const needle: u8 = 'a';
// Llamamos a indexOfScalar
const idx = std.mem.indexOfScalar(u8, haystack, needle);
// Comprobamos si se encontró
if (idx) |i| {
// Si se encontró, imprimimos el índice
std.debug.print("La letra 'a' se encuentra en la posición {d}\\n", .{i});
} else {
// Si no se encontró, informamos al usuario
std.debug.print("La letra 'a' no se encontró en el texto.\\n", .{});
}
}
Comentarios línea por línea:
const std = @import("std");– Importamos el módulo estándar.const haystack: []const u8 = "zig is fun, a language!";– Creamos un slice deu8(bytes) a partir de un literal.const needle: u8 = 'a';– Declaramos el carácter que buscamos.const idx = std.mem.indexOfScalar(u8, haystack, needle);– Ejecutamos la función. El primer argumento es el tipou8; Zig infiere el resto.if (idx) |i| { ... }– Usamos unifcon desempaquetado opcional para manejar el casonull.std.debug.print(...);– Imprimimos el resultado.
Ejemplo 2: Buscar un número entero en un array
Ahora busquemos la posición del número 42 dentro de un array de enteros.
const std = @import("std");
pub fn main() void {
// Array de enteros (slice de i32)
const numbers: []const i32 = &.{10, 20, 42, 50, 60};
// Valor que queremos buscar
const target: i32 = 42;
// Uso de indexOfScalar
const pos = std.mem.indexOfScalar(i32, numbers, target);
if (pos) |p| {
std.debug.print("El número {d} aparece en el índice {d}.\\n", .{target, p});
} else {
std.debug.print("El número {d} no se encontró.\\n", .{target});
}
}
Detalles:
&.{10, 20, 42, 50, 60}crea un slice inmutable con los valores indicados.- El retorno es opcional; se maneja con
if (pos) |p| { ... }.
Ejemplo 3: Buscar una estructura por un campo específico
Imaginemos una lista de estructuras que representan personas y queremos encontrar la primera con un nombre determinado.
const std = @import("std");
const Person = struct {
id: u32,
name: []const u8,
};
pub fn main() void {
// Lista de personas
const people: []const Person = &.{
.{ .id = 1, .name = "Alice" },
.{ .id = 2, .name = "Bob" },
.{ .id = 3, .name = "Carol" },
};
// Valor que buscamos (nombre)
const targetName: []const u8 =
