我正在尝试为String实现一个新特性,该字符串具有一个函数,该函数将每个String的第一个字母大写并且不使其余字符大写。我基于Rust标准库中to_uppercase()
和to_lowercase()
的函数接口。
use std::io;
trait ToCapitalized {
fn to_capitalized(&self) -> String;
}
impl ToCapitalized for String {
fn to_capitalized(&self) -> String {
self.chars().enumerate().map(|(i, c)| {
match i {
0 => c.to_uppercase(),
_ => c.to_lowercase(),
}
}).collect()
}
}
fn main() {
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).ok().expect("Unable to read from stdin.");
println!("{}", buffer.to_capitalized());
}
此代码基于here给出的建议,但代码已过时并导致多个编译错误。我现在执行的唯一问题是以下错误:
src/main.rs:10:13: 13:14 error: match arms have incompatible types [E0308]
src/main.rs:10 match i {
^
src/main.rs:10:13: 13:14 help: run `rustc --explain E0308` to see a detailed explanation
src/main.rs:10:13: 13:14 note: expected type `std::char::ToUppercase`
src/main.rs:10:13: 13:14 note: found type `std::char::ToLowercase`
src/main.rs:12:22: 12:38 note: match arm with an incompatible type
src/main.rs:12 _ => c.to_lowercase(),
简而言之,fn to_uppercase(&self) -> ToUppercase
和fn to_lowercase(&self) -> ToLowercase
的返回值无法收集在一起,因为地图现在有多种返回类型。
我试图将它们转换为另一种常见的Iterator类型,例如Bytes
和Chars
,但是这些迭代器类型无法收集以形成String。有什么建议吗?
答案 0 :(得分:2)
很少转换是解决Rust中类型问题的好方法。这里正确的解决方案是编写(或找到一个定义的包)一种统一不同迭代器类型的类型。但这需要努力,所以将collect
抛出窗口会更简单:
trait ToCapitalized {
fn to_capitalized(&self) -> String;
}
impl ToCapitalized for String {
fn to_capitalized(&self) -> String {
let mut r = String::with_capacity(self.len());
for (i, c) in self.chars().enumerate() {
match i {
0 => r.extend(c.to_uppercase()),
_ => r.extend(c.to_lowercase()),
}
}
r
}
}
fn main() {
let buffer = String::from("canberra");
println!("{}", buffer.to_capitalized());
}
如果您有某种类型来表示“collect
或ToUppercase
”,这或多或少都会ToLowercase
在浩大的大多数情况下,这也只会执行一次分配。
答案 1 :(得分:2)
在查看了pub fn to_uppercase(&self) -> String
here的实现之后,我设计了一个解决方案,该解决方案在Dogbert和DK。的解决方案以及标准库中给出的实现之间有点混合。它甚至适用于Unicode!
fn to_capitalized(&self) -> String {
match self.len() {
0 => String::new(),
_ => {
let mut s = String::with_capacity(self.len());
s.extend(self.chars().next().unwrap().to_uppercase());
s.extend(self.chars().skip(1).flat_map(|c| c.to_lowercase()));
return s;
}
}
}
Working Rust Playground Example
编辑:为了提高可见度,Shepmaster的简化和优化解决方案:
fn to_capitalized(&self) -> String {
let mut s = String::with_capacity(self.len());
let mut chars = self.chars();
s.extend(chars.by_ref().take(1).flat_map(|c| c.to_uppercase()));
s.extend(chars.flat_map(|c| c.to_lowercase()));
s
}
答案 2 :(得分:1)
这是我将如何做到的:
trait ToCapitalized {
fn to_capitalized(&self) -> String;
}
impl ToCapitalized for String {
fn to_capitalized(&self) -> String {
match self.chars().next() {
Some(c) => {
c.to_uppercase()
.chain(self.chars().skip(1).flat_map(|c| c.to_lowercase()))
.collect()
}
None => String::new(),
}
}
}
fn main() {
println!("{}", "fOoBaR".to_string().to_capitalized());
}
这会比理想的解决方案慢一些,因为它会对第一个char进行两次解码,但它的可读性非常高。
输出:
Foobar