« How do I convert between String, &str, Vec<u8> and &[u8]? » — votre checklist d'optimisation en Rust
\n\nSi vous avez déjà écrit du code Rust manipulant du texte ou des octets, vous avez sûrement été confronté à la question : « Comment convertir String en &str ? Et Vec<u8> en &[u8] ? Et dans l'autre sens ? ». C'est l'une des questions les plus populaires sur Stack Overflow (des dizaines de milliers de vues), et pour cause. Des conversions apparemment simples cachent des pièges, surtout en matière de performance.
Dans cet article, nous ne nous contenterons pas d'énumérer les méthodes « comment faire ». Nous expliquerons pourquoi certaines méthodes sont plus rapides que d'autres, et quand utiliser chacune d'elles. Vous apprendrez à éviter les copies inutiles, les allocations superflues et à écrire du code Rust véritablement efficace.
\n\nPourquoi est-ce important ? Contexte et performance
\nRust est un langage qui vous donne le contrôle de la mémoire. Mais ce contrôle s'accompagne de responsabilités. La conversion entre chaînes et octets est l'une des opérations les plus fréquentes. Par exemple, lors du travail avec des protocoles réseau, de la sérialisation de données (JSON, Protobuf) ou simplement de la lecture de fichiers. Un mauvais choix de conversion peut vous amener à copier des données que vous auriez pu utiliser sans copie. Dans le monde de la programmation système, c'est critique.
\n\nDécortiquons les quatre types principaux et apprenons à naviguer entre eux sans perte.
\n\nString et &str : les deux faces d'une même pièce
\nString est une chaîne UTF-8 possédée et mutable. &str est une tranche (slice) de chaîne empruntée et immuable. La règle principale : String est le propriétaire des données, &str est une référence aux données.
Comment obtenir &str à partir de String (et inversement)
\nC'est le cas le plus simple et le plus sûr.
\n\nlet my_string = String::from("Bonjour le monde !");\n// 1. Obtenir &str à partir de String (simple emprunt)\nlet my_str: &str = &my_string;\n// Ou avec as_str()\nlet my_str2: &str = my_string.as_str();\n\n// 2. Obtenir String à partir de &str (créer une nouvelle copie)\nlet new_string: String = my_str.to_string();\n// Ou\nlet new_string2: String = String::from(my_str);\n\nImportant : La conversion de &str en String crée toujours une nouvelle mémoire allouée (une allocation). C'est coûteux. La conversion de String en &str est simplement une prise de référence (gratuite).
Comment obtenir Vec<u8> à partir de String (et inversement)
\nC'est là que les choses deviennent intéressantes, car String est en interne simplement un Vec<u8> avec la garantie d'un UTF-8 valide.
let my_string = String::from("Rust");\n\n// 3. String -> Vec<u8>\n// Option A (copie) : sûr, mais coûteux\nlet bytes_vec_copy: Vec<u8> = my_string.as_bytes().to_vec();\n\n// Option B (sans copie, consommation de String) :\nlet bytes_vec_owned: Vec<u8> = my_string.into_bytes(); // my_string n'existe plus !\n\n// 4. Vec<u8> -> String (vérification de la validité UTF-8)\nlet new_string: String = String::from_utf8(bytes_vec_owned).expect("UTF-8 invalide");\n// Si vous êtes sûr de la validité :\nlet new_string_unchecked: String = unsafe { String::from_utf8_unchecked(bytes_vec_copy) };\n\nPoint clé : into_bytes() est une conversion zero-cost. Elle prend le tampon interne Vec<u8> et vous le donne, sans copier un seul octet. as_bytes().to_vec() est une copie explicite.
La méthode from_utf8_unchecked est unsafe. Utilisez-la uniquement si vous êtes sûr à 100% que les octets sont un UTF-8 valide. Sinon, le programme peut planter avec une panique ou, pire, avec un comportement indéfini (UB).