这里有两个代码段,但是它们表现出不同的行为,我不明白那里发生了什么。它们的主要功能是相同的。如果借用和所有权概念适用于一个代码(即代码2),为什么不适用于另一个代码(即代码1)?
代码1:
此代码编译无误,并提示结果。
fn main() {
let mut s = String::from("Hello world");
let result = first_word(&s);
s.clear();
println!("result:{:#?}", result);
}
fn first_word(s: &String) -> usize {
let s = s.as_bytes();
//println!("{:?}",s);
for (i, &item) in s.iter().enumerate() {
if item == 32 {
return i;
}
}
s.len()
}
代码1输出:
Finished dev [unoptimized + debuginfo] target(s) in 0.28s
Running `target/debug/rust_Slices`
result:5
代码2: 该代码将无法编译并给出错误。
fn main() {
let mut s = String::from("Hello world");
let result = first_word(&s);
s.clear();
println!("{:#?}", result);
}
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
代码2输出:
cannot borrow `s` as mutable because it is also borrowed as immutable
--> src/main.rs:4:4
|
3 | let result = first_word(&s);
| -- immutable borrow occurs here
4 | s.clear();
| ^^^^^^^^^ mutable borrow occurs here
5 | println!("{:#?}",result);
| ------ immutable borrow later used here
答案 0 :(得分:2)
让我们分解:
// Let's build a string, which basically is a growable array of chars
let mut s = String::from("Hello world");
// now make result a slice over that string, that is a reference
// to a part of the underlying chars
let result = first_word(&s);
// now let's remove the content of the string (which of course removes
// what the slice was referring to)
s.clear();
// and let's... print it ?
println!("{:#?}", result);
希望借用检查器阻止您执行此确切错误:
不能借用
s
可变,因为它也借来不可变
如果您理解了这一点,则解决方案应该很明显:不要使result
成为另一个字符串的窗口,而是使一个字符串本身具有自己的内容:将第二行更改为
let result = first_word(&s).to_string();
现在,您可以清除源字符串并保留第一个单词。当然,to_string()
并非是一项无花费的操作,因此您可能希望尝试在实际应用程序中保留源字符串。
答案 1 :(得分:0)
这里的关键是生命。默认情况下,具有一个输入引用和输出引用的函数的寿命参数相同(liftime elision)。因此,编译器会按照以下方式隐式更改代码:
fn first_word<'a>(s: &'a String) -> &'a str { // note 'a here
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
这意味着结果借用了输入参数。您可以显着改变生存期并消除main
中的错误,但是在这种情况下first_word
无法编译:
fn first_word1<'a, 'b>(s: &'a String) -> &'b str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:7:21
|
7 | return &s[0..i];
| ^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body