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

2023-11-13

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

    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • mongdb 建立地图索引,删除,查询

    方式一 创建 db shop ensureIndex loc 2dsphere 2Dsphere索引 用于存储和查找球面上的点 db shop ensureIndex loc 2d 2D索引 用于存储和查找平面上的点 本人项目用的这种 查询
  • 阿里最新秋招面经,腾讯/美团/字节1万道Java中高级面试题

    又是一年过去了 职场的积雪还没有消融 又迎来了一次大考 疫情还没完全过去 大家强打起精神 相互问好致意 眼角却满是疲惫 企业调薪 裁员 组织架构调整等等 坏消息只多不少 最近也有很多来咨询跳槽的朋友 都是因为之前的公司出现了比较大的薪资和组
  • tomcat中间件的默认端口号_tomcat默认端口号(三个tomcat端口号)

    tomcat默认端口号 三个tomcat端口号 2020 05 08 10 43 21 共10个回答 Tomcat的默认端口号是多少 您好 提问者 Tomcat的默认端口号是 8080 weblogic的默认端口号是 7001 tomcat
  • 【机器学习笔记1】一元线性回归模型及预测

    目录 什么是线性回归模型 一元线性回归模型 问题引入 问题解析 代价函数 损失函数 代价函数的图像 为什么不是最小而是极小值 梯度下降算法 梯度下降算法公式 对于一元线性回归模型 学习率a的选择 关于梯度下降每一步的变化 补充 代码部分 案
  • SpringBoot整合邮箱验证(典中典)

    大体思路 先生成一个六位随机验证码并存起来 调用邮箱接口发送验证码 将用户输入的验证码和之前保存的验证码进行比对 目录 大体思路 第一步 开启SMTP服务 简单邮件传输协议 第二步 在项目中导入相关依赖 第三步 在配置文件里进行相关配置 第
  • CVE-2022-30190 MSDT远程代码执行漏洞复现

    目录 0x01 声明 0x02 简介 0x03 漏洞概述 0x04 影响版本 0x05 环境搭建 0x06 漏洞复现 是否存在利用点 CMD执行 生成docx文件利用 0x07 CS上线 启动CS服务端 CS客户端连接 设置监听 生成攻击e
  • JAVA 关于static中静态代码块的使用

    与一般静态方法的比较 一般情况下 如果有些代码必须在项目启动的时候就执行的时候 需要使用静态代码块 这种代码是主动执行的 需要在项目启动的时候就初始化 两者的区别就是 静态代码块是自动执行的 静态方法是被调用的时候才执行的 静态方法可以用类
  • 【多线程】ThreadLocal

    目录 简介 底层 set get 回收 简介 线程变量 以ThreadLocal为键 任意对象为值的结构 这个结构被附带在线程上 一个线程根据一个ThreadLocal对象查询到绑定在这个线程上的一个值 本地线程 线程的局部变量 只有当前线
  • 学习少儿编程成为一种必然趋势

    AI人工智能和少儿编程一直是大家热议的话题 在政策引领下 一些城市把人工智能带入中小学教材当中 格物斯坦小坦克认为从编程思维入手 让孩子养成清晰明朗的逻辑思维 在学习 做事各个方面 孩子将来都会得心应手 Scratch编程与其他代码编程 最
  • DS静态查找之折半查找

    题目描述 给出一个队列和要查找的数值 找出数值在队列中的位置 队列位置从1开始 要求使用折半查找算法 输入 第一行输入n 表示队列有n个数据 第二行输入n个数据 都是正整数 用空格隔开 第三行输入t 表示有t个要查找的数值 第四行起 输入t
  • 抓包基本命令

    一 概述 在一个A应用程序内数据有不同的格式如 Integer String等 但是通过网络将数据传输给B应用程序 那么在到达B应用程序之前 数据都将统一解析成数据包 也就是二进制串在网络中传输 在B应用程序前布置一个 网 在这个数据包到达
  • Linux: USB Gadget 驱动简介

    文章目录 1 前言 2 背景 3 USB Gadget 驱动 3 1 什么是 USB Gadget 驱动 3 2 USB Gadget 驱动框架 3 3 USB 设备控制器 UDC 驱动 3 3 1 USB 设备控制器 UDC 驱动 概述
  • Eggjs 从放弃到开始使用

    原文 codesky me archives eg 用掘金刊登虽然分流了但是主要是 现在分享的曝光率实在太低了 所以 支持的请点下原博收藏下关注下以及我的微博 咦 这篇文章标题为什么反了 实际上这是个人走过的心路历程 最初看到 eggjs
  • FastDFS的Tracker及Storage节点添加及删除

    1 增加Storage节点 通过配置 自动加入 1 安装Storage并配置mod fastdfs conf及storage conf 设置fdfs storaged及nginx自启动 2 启动新加的storage节点 会自动同步相同gro
  • openGL之API学习(四)纹理操作

    纹理操作代码流程 向着色器传递纹理单元 glUniform1i gSampler 0 向GPU上传纹理数据 GLuint m textureObj glGenTextures 1 m textureObj 生成一个纹理对象 一个纹理对象有多
  • 谁会嫌钱多啊,最适合打工人小白的Python兼职攻略以及接私活经验!

    这次小编想谈谈一个非常热门的话题 就是如何在学习python的同时去赚钱 在这篇文章中 你会学习到如何通过学习python来赚取副业收入 相信大家都对钱感兴趣吧 如果你和马云爸爸对钱不敢兴趣的话 那这篇文章就不适合你了 如果你想知道如何使用
  • 计算机英语-基础知识

    计算机专业英语基础知识 1 专业英语的专业性和客观性 科技文章属于严肃的书面语体 崇尚严谨周密 逻辑性强 要求层次分明 重点突出 各个领域的专业英语都以表达科技概念 理论和事实为主要目的 因此 它们很注重客观事实和真相 要求逻辑性强 条理规
  • APISIX源码解析-插件-客户端IP【real-ip】

    real ip 客户端IP插件 关键属性 源码解析 real ip 插件用于动态改变传递到 APISIX 的客户端的 IP 和端口 local function get addr conf ctx if conf source http x
  • 卷运维不如卷网络安全

    最近发现很多从事运维的选择了辞职 重新规划自己的职业发展方向 运维工程师这个岗位在IT行业里面确实是处于最底层的 不管什么环节出现问题 基本都是运维背锅 背锅也就罢了 薪资水平也比不上别的岗位 一般运维的薪资水平大多数都是6 9K 还要高频
  • 【Rust】用RefCell避开`&mut XX`导致的借用检查

    derive Debug struct WhatAboutThis lt a gt name String nickname Option lt a str gt impl lt a gt WhatAboutThis lt a gt fn