【Rust】用RefCell避开`&mut XX`导致的借用检查

#[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); 

    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值