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.
¿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") }
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
HashMapy 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
staticyconst, 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.