ProgramaciónAutomatización, desarrollador embedded y de sistemas

Explique cómo funcionan las expresiones constantes (const expressions) en Rust, cuándo se evalúan y proporciona un ejemplo de uso práctico donde el compilador evalúa valores en tiempo de compilación.

Supere entrevistas con el asistente de IA Hintsage

Respuesta

En Rust, las expresiones constantes (const) se evalúan en tiempo de compilación, lo que permite crear valores que se convierten en parte del programa incluso antes de su ejecución. Estas expresiones se utilizan para definir tamaños de arreglos, valores en estructuras estáticas, parámetros genéricos y otras situaciones donde se necesitan constantes inmutables con un valor conocido de antemano.

En Rust, se pueden crear funciones "constantes" (const fn), que pueden ser utilizadas dentro de otras expresiones const o para inicializar variables constantes. El compilador garantiza que tales expresiones no contengan operaciones no permitidas (por ejemplo, acceso a memoria).

Ejemplo:

const fn fib(n: u32) -> u32 { match n { 0 | 1 => 1, _ => fib(n - 1) + fib(n - 2), } } const F8: u32 = fib(8); const ARR: [u32; F8 as usize] = [0; F8 as usize]; // Arreglo de tamaño 34

En este ejemplo, el valor de F8 y el tamaño del arreglo ARR se evalúan en tiempo de compilación.

Pregunta capciosa

¿Cuál es la diferencia entre una función const y una función normal, y se puede declarar cualquier función como const fn?

Respuesta: No, no se puede declarar cualquier función como const fn. const fn solo puede contener operaciones permitidas, que no permitan efectos secundarios o trabajos con memoria no segura. Por ejemplo, no se puede abrir un archivo o asignar memoria dinámicamente en const fn.

const fn add(x: i32, y: i32) -> i32 { x + y // permitido } // y esto no compilará: const fn fail() -> String { // ¡error! String::from("err") }

Ejemplos de errores reales por desconocer las sutilezas del tema


Historia

En un proyecto, intentaron calcular el valor hash de una cadena en tiempo de compilación a través de una función constante, pero utilizaron dentro de esta función métodos estándar de HashMap y asignación de memoria. El programa no compilaba, arrojando errores confusos sobre operaciones no permitidas en const fn.


Historia

En un gran desarrollo embebido, un desarrollador definió una constante-estructura con campos que requerían cálculos en tiempo de compilación, sin embargo, utilizó en la inicialización funciones de un crate externo, no marcadas como const fn. Esto llevó a la imposibilidad de utilizar esta lógica para determinar los tamaños de buffers estáticos.


Historia

En el código se confundió la diferencia entre static y const, intentando modificar una "constante" en tiempo de ejecución y obtuvieron un UB implícito (Comportamiento Indefinido), ya que las constantes en Rust no se colocan en memoria como valores, sino que son sustituidas por el compilador en el lugar de uso, lo que no implica su modificación.