我正在做一个练习,我应该只使用标准包。关键是获取字符串向量的所有单词,并仅输出首字母。[“一二”,“三”] -> [“O。T.",“T."]我让它用一个“天真的显式”代码工作:
pub fn initials_explicit_heavy(texts: Vec<&str>) -> Vec<String> {
let mut texts_initials: Vec<String> = vec![];
for one_text in texts {
let mut one_text_initials: String = "".to_string();
for word in one_text.split_whitespace() {
let first: char = word.chars().next().unwrap();
let first_and_dot: String = first.to_string() + ". ";
one_text_initials += &first_and_dot;
}
texts_initials.push(one_text_initials.trim_end().to_string());
// texts_initials.push(one_text_initials);
}
texts_initials
}
但是这个函数分配了太多的堆内存。51次而不是38次。我不确定问题在哪里。我应该使用迭代器而不是for循环吗?避免所有的to_string()转换?还是用我忽略的魔法任何提示都是受欢迎的。
--编辑--
抱歉,我忘了说函数类型sugnature被冻结了。
(texts: Vec<&str>) -> Vec<String>
2条答案
按热度按时间z9smfwbn1#
下面是代码的改进版本,它尽可能接近您的版本:
改进:
1.接受切片作为参数。不需要消耗矢量。
1.使用
write!()
宏写入分配的字符串。这将保存first.to_string()
的所有中间分配。1.只需弹出最后一个字符来处理尾随空格。如果字符串为空,则此操作将不执行任何操作,并保存
one_text_initials.trim_end().to_string()
所需的分配您可以通过预先计算
one_text_initials
所需的字节数并立即分配具有正确大小的结果向量来进一步提高重新分配的数量:这段代码使用了构建返回值所需的最小数量的分配,因此该方面无法进一步改进。您仍然可以通过定义一个返回首字母的迭代器来减少代码重复。
最后,这里是一个以我个人风格实现的函数版本,输入来自注解(而不是试图接近您的代码):
(我通常根本不会费心去实现
initials_string_vec()
,因为它所做的只是将现有函数Map到切片上。axr492tv2#
你不一定需要使用迭代器。事实上,在你的任务中使用迭代器是很不方便的。之所以有这么多的分配,是因为你经常这样做,基本上每次你试图把一些东西转换成字符串(例如。对于每个文本,你做
"".to_string()
和one_text_initials.trim_end().to_string()
,对于每个单词,你做first.to_string()
和one_text_initials += &first_and_dot;
,这很可能需要重新分配以容纳更多的数据。这里有一个可能的修改,先做一些分配,然后每个文本只分配一个(在
texts_initials.push(one_text_initials.iter().collect())
行上):Playground
注意,
one_text_initials
也会为每个字增长,但由于one_text_initials
是在循环外部预分配的,因此每次使用one_text_initials.clear()
时,只有向量的大小被重置为0,而分配的内存不会被释放,因此对于下一个字,重新分配内存的可能性较小