• 【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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    这段代码中如果把最后一句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");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    发表一下个人愚见. 有错误还请指出.
    问题出在 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");
    }
    
    • 1
    • 2
    • 3

    区别在于这里的生命周期注解不像上面那个有额外的限制: '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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 相关阅读:
    云计算技术大数据概述及其知识点
    web前端期末大作业 基于HTML+CSS+JavaScript程序员个人博客模板(web学生作业源码)
    使用GitLab CI/CD 定时运行Playwright自动化测试用例
    处理LetsEncrypt证书签发错误acme-v02.api.letsencrypt.org timeout
    简易数控直流稳压电压
    Educational Codeforces Round 137 (Rated for Div. 2)练习笔记
    三年的功能测试,让我女朋友跑了,太难受了...
    扩散模型又杀疯了!这一次被攻占的领域是...
    Kubernetes:kube-apiserver 之启动流程(二)
    测试小牛,全新出发!!
  • 原文地址:https://blog.csdn.net/weixin_42338512/article/details/126780501