pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => first.to_uppercase().to_string() + c.as_str(),
}
}
// Step 2.
// Apply the `capitalize_first` funciton to a slice of string slices.
// Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"]
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
words.iter().map(|w| capitalize_first(w)).collect()
}
// Step 3.
// Apply the `capitalize_first` function again to a slice of string slices.
// Return a single string.
// ["hello", " ", "world"] -> "Hello World"
pub fn capitalize_words_string(words: &[&str]) -> String {
words
.to_owned()
.into_iter()
.map(capitalize_first)
.collect::<String>()
}
哪种方法更好?
第一个方法是基于我以前的java知识编写的,第二个方法.to_owned().into_iter().map(...)
是在sushing solution git repo上看到的
谁能给我解释一下有什么区别,在这种情况下哪一个更好?
1条答案
按热度按时间mrfwxfqh1#
第一个函数:
这个方法和我的方法差不多。你可以通过
copied()
将&&str
元素转换成&str
来避免w
变量。除此之外,我认为这个解决方案很好:第二个功能:
在我看来,这不是最优的。
to_owned
创建了一个完全不必要的副本,因为你无论如何都要迭代它。所以把一个可迭代对象转换成一个拥有对象,仅仅是为了你可以通过into_iter
把它转换回一个迭代器,实际上没有任何意义。我会使用与第一个完全相同的语义,甚至不需要
::<String>
,它是从返回类型自动派生的:官方的解决办法似乎是这样说的:
虽然这肯定能起作用,但我不同意它是最优的,因为就像
to_owned().into_iter()
一样,它创建了一个冗余副本(这意味着它首先计算所有单词,存储它们,然后再次使用它们。iter().copied().map(capitalize_first)
不需要迭代两次,它是完全流式的)。重要提示:我在这里所做的关于性能的声明纯粹是启发式的。如果这是一个真实的世界中的问题,请不要*执行启发式性能分析。而是做一些实际的基准测试。编译器是神奇的,很多时候像这里所谈论的改进并不重要,因为编译器已经优化了它。不要浪费时间在优化上,而不先进行基准测试,然后基准测试您的优化是否实际上是优化**。
在这个特定的案例中,我认为官方的解决方案是“最干净的”,因为它有最少的代码重复。代码重复,以及可维护性,在大多数真实的世界的项目中是一个比性能的最后2%更重要的指标。我见过太多的项目因为可维护性问题而死亡,每一次都让我痛苦。