Rust中使用字符串切片向量填充HashMap后无法跨作用域使用的问题
问题分析与解决方案
问题根源
你猜的没错,问题确实出在字符串切片(&str)的生命周期上。循环里的fc是String类型,每次循环结束后,这个String会被自动销毁(drop)。但你用split得到的&str切片都是借用自fc的内存,当fc被销毁后,这些切片就变成了悬垂引用,Rust的所有权机制会直接阻止这种不安全的情况发生,所以编译报错。
另外还有个小问题:你用{file_name}的写法在字符串里不会自动插值,Rust里需要用format!宏来做字符串拼接。
解决方案
解决思路是让HashMap拥有字符串的所有权,而不是借用。有两种常用方式:
方式一:将HashMap的类型改为HashMap<&str, Vec<String>>
把切片转换成String,让Vec持有所有权,这样就不会依赖循环内的fc了:
use std::collections::HashMap; fn main() { let mut words: HashMap<&str, Vec<String>> = HashMap::new(); for file_name in ["conjunctions", "nouns", "verbs"].iter() { // 用format!宏正确拼接文件路径 let file_path = format!("../wordlists/{}.txt", file_name); let file_content = std::fs::read_to_string(&file_path) .unwrap_or_else(|_| panic!("Failed to read the file: {}", file_path)); // 把split得到的&str转换成String,获取所有权 let wordlist_vec: Vec<String> = file_content.split("\n") .filter(|s| !s.is_empty()) // 过滤掉空行(比如文件末尾的换行) .map(|s| s.to_string()) .collect(); words.insert(file_name, wordlist_vec); } // 现在可以正常外部访问了 println!("{:?}", words["conjunctions"]); }
方式二:用Arc<String>共享所有权(适合多线程场景)
如果之后需要在多个地方共享这些字符串,可以用Arc(原子引用计数)来共享所有权,避免多次复制字符串:
use std::collections::HashMap; use std::sync::Arc; fn main() { let mut words: HashMap<&str, Vec<Arc<String>>> = HashMap::new(); for file_name in ["conjunctions", "nouns", "verbs"].iter() { let file_path = format!("../wordlists/{}.txt", file_name); let file_content = std::fs::read_to_string(&file_path) .unwrap_or_else(|_| panic!("Failed to read the file: {}", file_path)); let wordlist_vec: Vec<Arc<String>> = file_content.split("\n") .filter(|s| !s.is_empty()) .map(|s| Arc::new(s.to_string())) .collect(); words.insert(file_name, wordlist_vec); } println!("{:?}", words["conjunctions"]); }
额外说明
- 为什么
file_name可以用&str?因为["conjunctions", ...]是字符串字面量,它们的生命周期是'static,会一直存在于程序运行期间,所以没问题。 - 加上
filter(|s| !s.is_empty())可以过滤掉文件末尾换行生成的空字符串,让结果更合理。
内容的提问来源于stack exchange,提问作者Ubdus Samad
相关产品推荐
相关产品推荐

