J'ai une méthode qui prend un &[u8] et j'ai besoin d'extraire des éléments depuis le début jusqu'à un index spécifique, en les copiant dans un String. Je pourrais utiliser une boucle pour l'itérer, mais y a-t-il une seule ligne pour le faire qui me manque?

0
ruipacheco 26 sept. 2020 à 01:36

2 réponses

Meilleure réponse

Si la séquence initiale est seq et que l'index est idx, alors c'est String::from_utf8(seq[..idx].to_vec()).unwrap(). Par étapes:

  1. seq[..idx] obtient la tranche souhaitée &[u8];
  2. seq[..idx].to_vec() convertit cette tranche en Vec<u8> (bien sûr, le clonage coûteux est en cours, mais il est nécessaire si la tranche est immuable);
  3. String::from_utf8(seq[..idx].to_vec()) essaie de convertir Vec<u8> en une chaîne sur place. Puisque String doit avoir une séquence de bits UTF8 valide, il vérifie cette condition et renvoie un Result. Aucun clonage n'a lieu ici: à la place, le String prend possession du Vec et réutilise son contenu. La documentation: https: //doc.rust-lang .org / std / string / struct.String.html # method.from_utf8
  4. Enfin .unwrap() convertit le Result en String si vous êtes sûr que la représentation UTF8 était correcte. Vous pouvez également utiliser .expect("error message") ou match pour gérer une possible erreur de codage.

MODIFIER: Une meilleure méthode a été suggérée dans les commentaires: std::str::from_utf8(&x[..idx]).unwrap(). Ceci est similaire, mais évite d'allouer une nouvelle mémoire. Vous pouvez lier ceci à la variable de type &str au lieu de String - elles sont interchangeables à de nombreuses fins. Si vous voulez vraiment un String, vous pouvez allouer une nouvelle mémoire et convertir par String::from(std::str::from_utf8(&x[..idx]).unwrap()). Par rapport à la méthode ci-dessus, cela présente l'avantage d'éviter l'allocation de mémoire lorsque la tranche n'est pas UTF8 valide.

4
Wolfram 26 sept. 2020 à 00:02

Vous n'avez pas dit comment vous voulez les mettre en forme dans la chaîne. Voici une tentative, en supposant que vous voulez que chaque u8 soit converti en sa représentation décimale et séparé par des virgules:

fn foo(s: &[u8], index: usize) -> String {
    s[..index].iter().map(u8::to_string).collect::<Vec<_>>().join(",")
}

Notez que join dans la bibliothèque std opère sur des tranches plutôt que sur des itérateurs, c'est pourquoi vous devez d'abord les rassembler dans un Vec.

Ou si votre [u8] contenait une séquence de caractères encodés en utf8, vous voudrez peut-être ceci:

fn bar(s: &[u8], index: usize) -> String {
    String::from_utf8(s[..index].to_vec()).unwrap()
}

Dans ce cas, vous voudrez probablement retourner un Result au lieu de déballer comme je l'ai fait dans cet exemple.

2
harmic 25 sept. 2020 à 23:26