HashMap<UniCase<Cow<str>>>生命周期问题的修复方案咨询
修复UniCase搭配Cow在HashMap中索引的生命周期问题
问题背景
UniCase未实现Borrow trait,导致无法在不分配String的情况下用UniCase键索引HashMap。官方给出的临时方案是使用HashMap<UniCase<Cow<str>>>,但以下代码编译失败:
use std::borrow::Cow; use std::collections::HashMap; use std::io::{BufRead, Result}; use unicase::UniCase; fn rm_reader_keys<R: BufRead>( reader: R, dict: &mut HashMap<UniCase<Cow<str>>, String> ) -> Result<()> { for ln in reader.lines() { let line: String = ln?; if let Some((key, _)) = line.rsplit_once(' ') { dict.remove(&UniCase::unicode(Cow::Borrowed(key))); } } Ok(()) }
编译报错信息
error[E0597]: `line` does not live long enough --> src/main.rs:44:33 | 40 | reader: R, dict: &mut HashMap<UniCase<Cow<str>>, std::string::String> | ---- has type `&mut HashMap<UniCase<Cow<'1, str>>, std::string::String>` ... 43 | let line: String = ln?; | ---- binding `line` declared here 44 | if let Some((key, _)) = line.rsplit_once(' ') { | ^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough 45 | dict.remove(&UniCase::unicode(Cow::Borrowed(key))); | -------------------------------------------------- argument requires that `line` is borrowed for `'1` 46 | } 47 | } | - `line` dropped here while still borrowed
报错原因
dict的生命周期'1要求传入的键引用必须存活到'1的整个周期,但line是循环内的局部变量,每次循环结束就会被销毁,无法满足这个生命周期约束,导致编译报错。
可行修复方法
方法一:将Cow转为Owned(分配String)
把key转换为Cow::Owned类型,让UniCase内部持有独立的String,不再依赖line的生命周期:
use std::borrow::Cow; use std::collections::HashMap; use std::io::{BufRead, Result}; use unicase::UniCase; fn rm_reader_keys<R: BufRead>( reader: R, dict: &mut HashMap<UniCase<Cow<str>>, String> ) -> Result<()> { for ln in reader.lines() { let line: String = ln?; if let Some((key, _)) = line.rsplit_once(' ') { dict.remove(&UniCase::unicode(Cow::Owned(key.to_string()))); } } Ok(()) }
方法二:遍历HashMap匹配键(避免分配)
利用UniCase::as_str方法遍历HashMap,找到大小写匹配的键后再移除,这种方式不需要分配新的String:
use std::borrow::Cow; use std::collections::HashMap; use std::io::{BufRead, Result}; use unicase::UniCase; fn rm_reader_keys<R: BufRead>( reader: R, dict: &mut HashMap<UniCase<Cow<str>>, String> ) -> Result<()> { for ln in reader.lines() { let line: String = ln?; if let Some((key, _)) = line.rsplit_once(' ') { let target_key = dict.keys() .find(|uc| uc.as_str().eq_ignore_ascii_case(key)) .cloned(); if let Some(k) = target_key { dict.remove(&k); } } } Ok(()) }
方法三:改用UniCase作为键类型
如果可以接受初始就使用UniCase<String>作为HashMap的键类型,代码会更简洁,也不会有生命周期问题:
use std::collections::HashMap; use std::io::{BufRead, Result}; use unicase::UniCase; fn rm_reader_keys<R: BufRead>( reader: R, dict: &mut HashMap<UniCase<String>, String> ) -> Result<()> { for ln in reader.lines() { let line: String = ln?; if let Some((key, _)) = line.rsplit_once(' ') { dict.remove(&UniCase::unicode(key.to_string())); } } Ok(()) }
内容的提问来源于stack exchange,提问作者Nil Admirari
相关产品推荐
相关产品推荐

