ProgrammationAutomatisation, Développeur Embedded et Système

Expliquez comment fonctionnent les expressions constantes (const expressions) en Rust, quand elles sont évaluées, et donnez un exemple d'utilisation pratique où le compilateur évalue les valeurs au moment de la compilation.

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

En Rust, les expressions constantes (const) sont évaluées au moment de la compilation, permettant de créer des valeurs qui deviennent une partie du programme avant même son exécution. Elles sont utilisées pour définir les tailles des tableaux, des valeurs dans des structures statiques, des paramètres génériques et d'autres situations où des constantes immuables avec une valeur connue de manière stricte sont nécessaires.

En Rust, il est possible de créer des fonctions "constants" (const fn), qui peuvent être utilisées à l'intérieur d'autres expressions constantes ou pour initialiser des variables constantes. Le compilateur garantit que ces expressions ne contiennent pas d'opérations invalides (comme l'accès à la mémoire).

Exemple:

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]; // Tableau de taille 34

Dans cet exemple, la valeur de F8 et la taille du tableau ARR sont évaluées au moment de la compilation.

Question piège

Quelle est la différence entre une fonction const et une fonction ordinaire, et peut-on déclarer n'importe quelle fonction comme const fn ?

Réponse: Non, on ne peut pas déclarer n'importe quelle fonction comme const fn. Une const fn ne peut contenir que des opérations autorisées, ne permettant pas d'effets secondaires ou d'opérations avec de la mémoire non sécurisée. Par exemple, il n'est pas possible d'ouvrir un fichier ou d'allouer de la mémoire dynamiquement dans une const fn.

const fn add(x: i32, y: i32) -> i32 { x + y // permis } // mais cela ne compilera pas : const fn fail() -> String { // erreur ! String::from("err") }

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet


Histoire

Dans un projet, on a essayé de calculer la valeur du hachage d'une chaîne au moment de la compilation via une fonction constante, mais on a utilisé à l'intérieur de cette fonction des méthodes standard de HashMap et une allocation de mémoire. Le programme ne compilait pas et générait des erreurs incompréhensibles sur l'interdiction d'opérations dans const fn.


Histoire

Dans un grand développement embarqué, un développeur a défini une constante-structure avec des champs nécessitant une évaluation au moment de la compilation, mais a utilisé à l'intérieur l'initialisation de fonctions d'un crate externe, non marquées comme const fn. Cela a conduit à l'impossibilité d'utiliser cette logique pour définir les tailles des buffers statiques.


Histoire

Dans le code, la différence entre static et const a été confondue, essayant de modifier une "constante" en cours d'exécution, ce qui a conduit à un UB (Undefined Behavior) implicite, car les constantes en Rust ne sont pas placées en mémoire comme des valeurs, mais sont substituées par le compilateur au point d'utilisation, ce qui n'implique absolument pas leur modification.