• 【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
  • 相关阅读:
    java毕业设计宠物销售管理系统Mybatis+系统+数据库+调试部署
    stm32--独立看门狗
    uniapp\ taro 如何使用 UnoCSS 原子化css
    AndroidTV开发12——大屏TV电视及盒子Apk远程安装说明文档
    集采报告丨国家药品带量采购政策及趋势分析
    微信小程序 地图map组件 SDK 并 实现导航
    需求工程咨询和实施服务
    Ubuntu 22.04安装Rust编译环境并且测试
    Day76-Spring Boot实践,开发社区登录模块-生成二维码
    自然语言处理:Transformer与GPT
  • 原文地址:https://blog.csdn.net/weixin_42338512/article/details/126780501