Rust遍历字符串切片数组:to_owned().into_iter()与iter()的差异及选型
Rust字符串切片数组遍历:
iter() vs to_owned().into_iter()的区别与优劣 问题背景
我基于Java知识用iter()实现了capitalize_words_vector函数,在Rustlings解决方案仓库中看到有人用to_owned().into_iter()实现capitalize_words_string函数。想请教遍历字符串切片数组时,这两种方式有何区别,此场景下哪种实现更优?
相关代码
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>() }
两种遍历方式的区别
1. iter()的工作方式
对于&[&str]类型的切片,iter()会生成一个引用迭代器:
- 迭代器产出的每个元素是
&&str(即原切片中每个&str的引用) - 不需要复制原切片的任何元素,只是借用原切片的内容,内存开销极小
- 因为Rust会自动处理解引用,所以在
map中即使拿到的是&&str,也能直接传给接受&str的capitalize_first函数
2. to_owned().into_iter()的工作方式
这是两步操作的组合:
to_owned():对&[&str]调用该方法,会创建一个新的Vec<&str>(仅复制原切片中的&str指针,不会复制字符串实际内容)into_iter():对新创建的Vec<&str>调用该方法,会转移Vec的所有权,生成一个所有权迭代器,产出的每个元素是&str(直接取Vec中的元素,而非引用)- 相比
iter(),多了一步Vec的内存分配和指针复制操作,虽然开销不大,但属于额外的不必要操作
此场景下的最优实现
在这个场景中,iter()的实现更优,原因如下:
- 性能更高:无需额外创建Vec,减少了内存分配和复制的开销
- 代码更简洁:不需要多余的
to_owned()调用,逻辑更直接 - 功能等价:两种方式最终都能完成字符串 capitalize 并收集结果的需求,
iter()的实现完全可以替代to_owned().into_iter()的写法
实际上,capitalize_words_string完全可以改成和capitalize_words_vector一样的写法:
pub fn capitalize_words_string(words: &[&str]) -> String { words.iter().map(|w| capitalize_first(w)).collect() }
内容的提问来源于stack exchange,提问作者Wentao Zhang
相关产品推荐
相关产品推荐

