更新:为最新的 Rust 更新。从 Rust 1.0.0-alpha 开始,to_lowercase()/to_uppercase() 现在是 CharExt 特征中的方法,并且不再有单独的 Ascii 类型:ASCII 操作现在聚集在两个特征中,AsciiExt 和 @987654323 @。它们被标记为不稳定,因此它们可能会在整个 Rust 测试版期间发生变化。
您的代码不正确,因为它访问单个字节以执行基于字符的操作,但在 UTF-8 中字符不是字节。对于非 ASCII 的任何内容,它都无法正常工作。
事实上,没有办法正确地就地执行此操作,因为任何字符转换都可能改变字符占用的字节数,这需要完整的字符串重新分配。您应该遍历字符并将它们收集到一个新字符串中:
fn titlecase_word(word: &mut String) {
if word.is_empty() { return; }
let mut result = String::with_capacity(word.len());
{
let mut chars = word.chars();
result.push(chars.next().unwrap().to_uppercase());
for c in chars {
result.push(c.to_lowercase());
}
}
*word = result;
}
(试试看here)
因为无论如何您都需要生成一个新字符串,所以最好直接返回它,而不用替换旧字符串。在这种情况下,最好将切片传递给函数:
fn titlecase_word(word: &str) -> String {
let mut result = String::with_capacity(word.len());
if !word.is_empty() {
let mut chars = word.chars();
result.push(chars.next().unwrap().to_uppercase());
for c in chars {
result.push(c.to_lowercase());
}
}
result
}
(试试看here)
另外,String 具有来自 Extend 特征的 extend() 方法,它提供了一种比 for 循环更惯用的方法:
fn titlecase_word(word: &str) -> String {
let mut result = String::with_capacity(word.len());
if !word.is_empty() {
let mut chars = word.chars();
result.push(chars.next().unwrap().to_uppercase());
result.extend(chars.map(|c| c.to_lowercase()));
}
result
}
(试试看here)
事实上,使用迭代器可以进一步缩短它:
fn titlecase_word(word: &str) -> String {
word.chars().enumerate()
.map(|(i, c)| if i == 0 { c.to_uppercase() } else { c.to_lowercase() })
.collect()
}
(试试看here)
如果您事先知道您正在使用 ASCII,那么您可以使用 std::ascii 模块提供的特征:
fn titlecase_word(word: String) -> String {
use std::ascii::{AsciiExt, OwnedAsciiExt};
assert!(word.is_ascii());
let mut result = word.into_bytes().into_ascii_lowercase();
result[0] = result[0].to_ascii_uppercase();
String::from_utf8(result).unwrap()
}
(试试看here)
如果输入字符串包含任何非 ASCII 字符,此函数将失败。
此函数不会分配任何内容,而是会就地修改字符串内容。但是,如果没有不安全的和,您不能使用单个&mut String 参数编写这样的函数,因为它需要从&mut 移出,这是不允许的。
您可以使用std::mem::swap() 和一个带有空字符串的临时变量 - 它不需要不安全,但它可能需要分配空字符串。我不记得它是否真的需要分配;如果没有,那么您可以编写这样的函数,尽管代码会有些麻烦。无论如何,&mut-arguments 对于 Rust 来说并不是真正地道。