Pourquoi est-elle si compliquée?
Nous allons casser vers le bas, ligne par ligne
let s1 = "foobar";
Nous avons créé une chaîne littérale qui est encodé en UTF-8. UTF-8 nous permet d'encoder le 1,114,112 les points de code de l'Unicode dans une manière qui est assez compact si vous venez d'une région du monde que les types de la plupart des caractères en ASCII, qui est une norme créée en 1963. UTF-8 est d'une longueur variable de codage, ce qui signifie qu'un seul point de code peut prendre de 1 à 4 octets. La plus courte des codages sont réservés pour l'ASCII, mais beaucoup de Kanji prendre 3 octets en UTF-8.
let mut v: Vec<char> = s1.chars().collect();
Cela crée un vecteur d' char
acteurs. Un caractère est un nombre de 32 bits qui mappe directement à un point de code. Si nous avons commencé avec de l'ASCII uniquement du texte, nous avons quadruplé nos besoins en mémoire. Si nous avions un tas de caractères à partir de l'astral, alors peut-être que nous n'avons pas utilisé beaucoup plus.
v[0] = v[0].to_uppercase().nth(0).unwrap();
Cet attrape le premier point de code et demande qu'il soit converti en majuscules variante. Malheureusement pour ceux d'entre nous qui ont grandi en parlant anglais, il n'y a pas toujours un simple one-to-one mapping d'une "petite lettre" à une "grande lettre". Note de côté: nous les appelons des haut - et bas-de-casse , car une boîte de lettres a été au-dessus de l'autre boîte de lettres de retour dans la journée.
Ce code de panique lorsqu'un point de code n'a pas de correspondant en majuscules variante. Je ne suis pas sûr si ceux-ci existent, en fait. Il pourrait aussi sémantiquement échouent lorsqu'un point de code a une majuscule variante qui a de multiples personnages, tels que le german ß
. Notez que ß peuvent ne jamais être capitalisés dans Le Monde Réel, c'est le juste exemple, je peux toujours vous rappeler et de la recherche. Comme de 2017-06-29, en fait, les règles officielles de l'orthographe allemande ont été mis à jour afin que les deux "ss" et "SS" sont valables capitalisations!
let s2: String = v.into_iter().collect();
Ici nous avons convertir les caractères de retour en UTF-8 et nécessitent une nouvelle allocation pour les stocker, comme la variable d'origine a été stocké dans la mémoire constante afin de ne pas encombrer la mémoire au moment de l'exécution.
let s3 = &s2;
Et maintenant, nous prenons une référence pour qui String
.
C'est un problème simple
Malheureusement, ce n'est pas vrai. Peut-être que nous devrions essayer de convertir le monde de l'Espéranto?
Je présume char::to_uppercase
déjà correctement gère l'Unicode.
Oui, je l'espère bien. Malheureusement, l'Unicode n'est pas suffisant dans tous les cas.
Grâce à huon pour souligner le turc je, où à la fois la partie supérieure (I) et les minuscules (i) les versions ont un point. Qui est, il n'est pas un bon de capitalisation de la lettre i
; elle dépend de la locale de la le texte source ainsi.
pourquoi la nécessité pour tous les conversions de types de données?
Parce que les types de données qui vous travaillez important lorsque vous êtes inquiet au sujet de la justesse et de la performance. Un char
32-bits et une chaîne de caractères est codé en UTF-8. Ce sont des choses différentes.
l'indexation pourrait revenir un multi-octets, de caractères Unicode
Il peut être incompatibles terminologie ici. Un char
est un multi-octets de caractères Unicode.
Découpage d'une chaîne de caractères est possible si vous allez octet-par-octet, mais la bibliothèque standard de panique si vous n'êtes pas sur un personnage de la frontière.
L'une des raisons qui l'indexation d'une chaîne de caractères pour obtenir un caractère n'a jamais été mis en œuvre est parce que beaucoup de gens l'utilisation abusive des chaînes comme des tableaux de caractères ASCII. L'indexation d'une chaîne de caractères pour définir un personnage ne pourra jamais être efficace, vous deviez être en mesure de remplacer de 1 à 4 octets avec une valeur qui est également de 1 à 4 octets, entraînant le reste de la chaîne de rebondir autour de beaucoup.
to_uppercase
pourrait revenir un caractère majuscule
Comme mentionné ci-dessus, ß
est un caractère unique qui, lorsque capitalisé, devient deux personnages.
Solutions
Voir aussi trentcl la réponse de laquelle seuls les majuscules des caractères ASCII.
D'origine
Si j'avais à écrire le code, ça ressemble:
fn some_kind_of_uppercase_first_letter(s: &str) -> String {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().chain(c).collect(),
}
}
fn main() {
println!("{}", some_kind_of_uppercase_first_letter("joe"));
println!("{}", some_kind_of_uppercase_first_letter("jill"));
println!("{}", some_kind_of_uppercase_first_letter("von Hagen"));
println!("{}", some_kind_of_uppercase_first_letter("ß"));
}
Mais je serais probablement de recherche pour les majuscules ou unicode sur des caisses.io et de laisser quelqu'un de plus intelligent que moi à gérer.
L'amélioration de
En parlant de "quelqu'un de plus intelligent que moi", Veedrac souligne qu'il est probablement plus efficace pour convertir l'itérateur de retour dans une tranche après la première capitale codepoints sont accessibles. Cela permet une memcpy
du reste des octets.
fn some_kind_of_uppercase_first_letter(s: &str) -> String {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
}
}