#[derive(Debug)]
struct WhatAboutThis<'a> {
name: String,
nickname: Option<&'a str>,
}
impl<'a> WhatAboutThis<'a> {
fn tie_the_knot(&'a mut self) {
self.nickname = Some(&self.name[..4]);
}
}
fn main() {
let mut tricky = WhatAboutThis {
name: "Annabelle".to_string(),
nickname: None,
};
tricky.tie_the_knot();
// cannot borrow `tricky` as immutable because it is also borrowed as mutable
// println!("{:?}", tricky);
}
这段代码中如果把最后一句println!("{:?}", tricky)
注释放开,为什么会报“cannot borrow tricky as immutable because it is also borrowed as mutable”
与上述代码几乎一样道理的这个:println!("{}",s);
就不报错呢?没搞明白!
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{}",s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
发表一下个人愚见. 有错误还请指出.
问题出在 fn tie_the_knot(&'a mut self)
这里创建了一个可变引用, 且它的生命周期和 struct WhatAboutThis<'a>
是一样长的. 因此在main()中的代码, tricky.tie_the_knot();
所隐含创建的可变借用的生命周期和tricky这个struct值的生命周期是一样长的, 都截至到main()函数结尾. 因此编译器可能不太聪明的认为: 在tricky.tie_the_knot();
之后(main结束前) 都存在一个对tricky的可变借用, 因此不能再创建对tricky的其它借用了. 但println! 会创建一个不可变借用, 因此编译器认为这违反了借用规则.
另一个例子中的change()
可以改写成 等价 形式 :
fn change<'a>(some_string: &'a mut String) {
some_string.push_str(", world");
}
区别在于这里的生命周期注解不像上面那个有额外的限制: 'a
首先是struct WhatAboutThis
的生命周期, 并且也是fn tie_the_knot(&'a mut self)
中隐含创建的可变引用的生命周期.
因此问题在于(在编译器看来)可变引用的生命周期过大了, 进而遇到借用检查的阻挠. 一个解决的办法就是将其改为不可变引用, 但同时也要有能力来修改struct中的nickname
字段, 因此要"包裹"一层 RefCell<>
:
use std::cell::* ;
#[derive(Debug)]
struct WhatAboutThis<'a> {
name: String,
nickname: RefCell<Option<&'a str> > , // <<======
}
impl<'a> WhatAboutThis<'a>
{
fn tie_the_knot(&'a self) { // <<====== 不可变借用 !
*self.nickname.borrow_mut() = Some(&self.name[..4]);
}
}
fn main() {
let mut tricky = WhatAboutThis {
name: "Annabelle".to_string(),
nickname: RefCell::new(None) , // <<======
};
tricky.tie_the_knot();
println!("===> {:?}", tricky);
}