为何Rust中.retain()与.iter()链式调用无法生效?
问题:为何链式调用.retain()无法移除空字符串?
我想知道为什么下面这段代码没法移除所有空字符串:
fn set_name_list(&mut self, mut name_list: Vec<String>) { // 初始状态:name_list = [" "] name_list .iter() .map(|o| trim_all_spaces(o)) .collect::<Vec<String>>() .retain(|o| !o.is_empty()); // 执行后:name_list还是[" "] }
但另一段代码却能正常工作:
fn set_name_list(&mut self, mut name_list: Vec<String>) { // 初始状态:name_list = [" "] name_list = name_list .iter() .map(|o| trim_all_spaces(o)) .collect::<Vec<String>>(); name_list.retain(|o| !o.is_empty()); // 执行后:name_list正确变为[] }
为什么.retain()和.iter()链式调用后没效果?
原因解析
问题核心在于链式调用中的collect创建了临时Vec,且未将其赋值回原变量:
第一段代码里,
name_list.iter()只是生成原Vec的迭代器,不会改动原数据;map处理后,collect::<Vec<String>>()会创建一个全新的临时Vec,这个临时Vec和原来的name_list是完全独立的两个对象。最后调用的.retain()是在这个临时Vec上做过滤,但临时Vec执行完操作后就被销毁了,原name_list全程没被修改,所以结果没变。第二段代码中,
collect生成新Vec后,通过name_list = ...把新Vec赋值给了原变量,替换掉了原来的内容。之后调用.retain()是在这个新的name_list上操作,自然能正确移除空字符串。
另外可以做个优化:把转换和过滤合并成一步,用filter替代retain,直接生成最终需要的Vec,代码更简洁高效:
name_list = name_list .iter() .map(|o| trim_all_spaces(o)) .filter(|o| !o.is_empty()) .collect::<Vec<String>>();
内容的提问来源于stack exchange,提问作者Fred Hors
相关产品推荐
相关产品推荐

