Rust代码编译报错:类型不匹配与str编译期大小未知问题解析
into_iter()相关代码编译失败的原因分析 我的理解
iter():集合内数据的只读视图。into_iter():集合内数据的可读写视图(注意:拥有完整访问权限,但会从父作用域转移所有权)。iter_mut():集合内数据的可写视图(注意:拥有完整访问权限,但不会从父作用域转移所有权,类似其他GC回收语言)。
为区分iter()和iter_mut()返回的数据类型,我们使用&"Ferris"和&mut"Ferris"。
可正常运行的代码
fn main() { let mut names = vec!["Bob", "Frank", "Ferris"]; for name in names.iter_mut() { *name = match name { &mut "Ferris" => "There is a rustacean among us!", _ => "Hello!", } } println!("names: {:?}", names); }
无法运行的代码
fn main() { let names = vec!["Bob", "Frank", "Ferris"]; for name in names.into_iter() { *name = match name { "Ferris" => "There is a rustacean among us!", _ => "Hello", }; println!("names: {:?}", names); } }
编译报错信息
Compiling playground v0.0.1 (/playground) error[E0308]: mismatched types src/main.rs:6:25 | 6 | "Ferris" => "There is a rustacean among us!", expected `str`, found `&str` error[E0277]: the size for values of type `str` cannot be known at compilation time src/main.rs:5:9 | 5 | *name = match name { doesn't have a size known at compile-time | help: the trait `Sized` is not implemented for `str` note: the left-hand-side of an assignment must have a statically known size Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. error: could not compile `playground` (bin "playground") due to 2 previous errors
问题
我尝试使用to_string()将&str转换为String,但仍未解决问题,请问这段代码无法运行的原因是什么?
原因分析
1. 所有权转移导致原集合无法访问
调用names.into_iter()后,names的所有权会被完全转移到迭代器中,循环内的println!("names: {:?}", names);已经无法访问原names变量,这本身会触发所有权错误,不过代码还没走到这一步就因其他错误编译失败了。
2. 动态大小类型的赋值限制
对于Vec<&str>来说,into_iter()迭代出的每个元素类型是&str,执行*name = ...时,*name对应的是str类型——而str是动态大小类型,它的内存大小在编译期无法确定。Rust明确禁止给动态大小类型直接赋值,这是报错中E0277的核心原因。
3. 类型不匹配问题
match分支返回的是&str类型(字符串字面量默认是&str),而你试图赋值给*name(类型为str),两者类型不兼容,因此触发E0308的类型匹配错误。
4. to_string()无法解决根本问题
to_string()得到的是String类型,原集合的元素类型是&str,String和&str是不同类型,无法直接赋值给*name(str类型),自然无法解决问题。
修正方案
如果想用into_iter()实现修改元素的效果,需要将集合类型改为Vec<String>,迭代出的元素是拥有所有权的String,可以直接修改:
fn main() { let names = vec!["Bob".to_string(), "Frank".to_string(), "Ferris".to_string()]; for mut name in names.into_iter() { name = match name.as_str() { "Ferris" => "There is a rustacean among us!".to_string(), _ => "Hello!".to_string(), }; println!("current modified name: {:?}", name); } // 注意:原names变量已被转移所有权,此处无法再访问 }
如果需要保留原集合的所有权,直接使用你提供的第一个可运行代码(iter_mut()方式)即可,这也是这类场景下的常规做法。
内容的提问来源于stack exchange,提问作者Code learner

