【rust/egui】(三)看看template的app.rs:序列化、持久化存储

说在前面

  • rust新手,egui没啥找到啥教程,这里自己记录下学习过程
  • 环境:windows11 22H2
  • rust版本:rustc 1.71.1
  • egui版本:0.22.0
  • eframe版本:0.22.0
  • 上一篇:这里

serde

  • app.rs中首先定义了我们的TemplateApp结构体
    /// 继承序列化以及反序列化 用于存储一些状态数据
    #[derive(serde::Deserialize, serde::Serialize)]
    #[serde(default)] // 在反序列化时,缺少的字段会使用Default特征对应的值进行初始化
    pub struct TemplateApp {// Example stuff:label: String,// 声明该字段跳过序列化#[serde(skip)]value: f32,
    }
    // 为TemplateApp实现Default特征
    impl Default for TemplateApp {fn default() -> Self {Self {// Example stuff:label: "Hello World!".to_owned(),value: 2.7,}}
    }
    
  • 在定义TemplateApp时,我们让其继承了serde::Deserialize, serde::Serializeserde是rust中用于序列化和反序列化(serialize and deserialize)一个框架。详细见这里
  • eframe中,我们使用的是ron提供的序列化实现,与json类似,但并不一致,例如以下是一个ron序列化的结果:
    Scene( // class name is optionalmaterials: { // this is a map"metal": (reflectivity: 1.0,),"plastic": (reflectivity: 0.5,),},entities: [ // this is an array(name: "hero",material: "metal",),(name: "monster",material: "plastic",),],
    )
    
    详细请参考https://github.com/ron-rs/ron
  • 看一个简单的ron序列化例子
    use serde::{Deserialize, Serialize};#[derive(Debug, Deserialize, Serialize)]
    struct MyStruct {boolean: bool,float: f32,
    }impl MyStruct {fn new() -> Self {return ron::from_str("(boolean: true, float: 1.23)").unwrap();}
    }fn main() {let x = MyStruct::new();println!("RON: {}", ron::to_string(&x).unwrap());
    }
    // output:
    // RON: (boolean:true,float:1.23)
    
  • 关于更深层次的内容这里就不再展开了 (咱也展开不下去)

持久化存储

  • 有了serde之后我们可以干什么呢?让我们继续看代码:
    impl TemplateApp {/// 在第一帧之前调用pub fn new(cc: &eframe::CreationContext<'_>) -> Self {// 我们也可以在这里定义我们的界面样式 使用`cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.// 加载一些应用状态(比如上一次打开了那些文件之类的) 但是我们必须启用`persistence`特性if let Some(storage) = cc.storage {// 这里我们使用ron取出存入的状态数据 并将其反序列化成TemplateAppreturn eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default();}Default::default()}
    }impl eframe::App for TemplateApp {/// 在应用关闭前调用 用于存储状态fn save(&mut self, storage: &mut dyn eframe::Storage) {// 这里我们使用ron将TemplateApp序列化 并且存入对应的文件中eframe::set_value(storage, eframe::APP_KEY, self);}
    
  • 首先我们为TemplateApp实现了new方法
  • 而在之前的main.rs中,我们可以看到该方法的调用,实际上,该函数是在eframe的各种准备工作完成后,才进行的回调
    eframe::run_native("demo app",native_options,Box::new(|cc| Box::new(demo_app::TemplateApp::new(cc))),)
    
  • 在该函数中,我们完成了一些状态数据的还原,即读取应用上一次的工作状态,那么这些数据又是在什么时候存储下来的呢?以及存在了哪里呢?
  • 在接下来的代码中,我们实现了eframe::App特征,在save方法中,我们对状态数据进行了存储,我们可以看看eframe::set_value的具体实现:
    #[cfg(feature = "ron")]
    pub fn set_value<T: serde::Serialize>(storage: &mut dyn Storage, key: &str, value: &T) {// 首先对TemplateApp进行序列化match ron::ser::to_string(value) {// 如果序列化成功 那么进一步进行存储 这里并不会立即写文件Ok(string) => storage.set_string(key, string),// 失败则打印日志Err(err) => log::error!("eframe failed to encode data using ron: {}", err),}
    }
    
  • 我们可以运行一下应用看看效果,先修改输入:
    在这里插入图片描述
    关闭应用后再打开:
    在这里插入图片描述
    可以看到字符串确实保持一致,而数值已经变回原样了。
  • 那我们的数据到底存储在哪里呢?参照上一节的做法,将eframe的日志输出打开,可以看到存储路径打印出来了
    [2023-08-19T09:26:27Z DEBUG eframe] Using the glow renderer
    [2023-08-19T09:26:27Z DEBUG eframe::native::run] Entering the winit event loop (run_return)[2023-08-19T09:26:27Z DEBUG eframe::native::file_storage] Loading app state from "C:\\Users\\xxxx\\AppData\\Roaming\\demo app\\data\\app.ron"
  • 打开文件,可以看到存储的内容确实在,其中还存储了一些其他数据
    在这里插入图片描述
  • 当我们直接修改对应的数据后再打开应用,对应的数据也发生了变化:
    在这里插入图片描述
  • 既然是单个文件存储,那么是否会有竞争问题呢?我们打开两个应用A,B
    在这里插入图片描述
    A想要改字符串,B同时改了字符串和数值,B先关闭,A后关闭
    在这里插入图片描述
    再次打开应用,B修改的数据丢失了
    在这里插入图片描述
    因此在开发/使用的时候需要注意多窗口下的数据存储问题

参考

  • serde
  • serde api
  • ron

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/44264.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git判断本地是否最新

场景需求 需要判断是否有新内容更新,确定有更新之后执行pull操作&#xff0c;然后pull成功之后再将新内容进行复制到其他地方 pgit log -1 --prettyformat:"%H" HEAD -- . "origin/HEAD" rgit rev-parse origin/HEAD if [[ $p $r ]];thenecho "Is La…

域名解析和代理

购买域名 这里使用腾讯云进行购买。 对域名进行解析 通过添加记录接口对域名进行解析。 此时我们的服务器地址就被解析到域名上了。 我们可以通过以下格式进行访问&#xff1a; [域名]:[对应的项目端口] 效果为下: 通过nginx进行代理 如果我们使用上述的方式进行访问还是…

c语言strtol函数、strtod函数、strtoul函数浅悉

---------------- | strtol | ---------------- i.e. string to long long int strtol(const char *nptr, char **endptr, int base) strtol()会将nptr指向的字符串&#xff0c;根据参数base&#xff0c;按权转化为long int, 然后返回这个值。 参数base的范…

【hive】hive分桶表的学习

hive分桶表的学习 前言&#xff1a; 每一个表或者分区&#xff0c;hive都可以进一步组织成桶&#xff0c;桶是更细粒度的数据划分&#xff0c;他本质不会改变表或分区的目录组织方式&#xff0c;他会改变数据在文件中的分布方式。 分桶规则&#xff1a; 对分桶字段值进行哈…

使用图像处理算法检测金属表面的生锈区域: Python实现及步骤解析

摘要&#xff1a; 本文主要介绍如何使用Python和OpenCV库来实现对金属表面的生锈区域的检测。图像处理在工业领域有着广泛的应用&#xff0c;尤其是对材料的表面缺陷的检测。本文将详细阐述该算法的具体实现步骤&#xff0c;并提供完整的Python代码示例。 1. 引言 金属的锈蚀是…

flutter-设置开屏页 解决开屏白屏问题

flutter_native_splash 当您的应用程序打开时&#xff0c;本机应用程序会短暂加载 Flutter。默认情况下&#xff0c;在此期间&#xff0c;本机应用程序会显示白色启动屏幕。该包自动生成 iOS、Android 和 Web 本机代码&#xff0c;用于自定义本机启动画面背景颜色和启动图像。支…

Webshell的过滤绕过

目录 Webshell的过滤绕过 1.异或操作绕过 2.取反操作绕过 3.PHP语法绕过 的过滤绕过 1.异或操作绕过 先来看一段代码 <?phpecho "A"^"";//结果为"!" ?> 为什么会输出"!" 之所以会得到这样的结果&#xff0c;是因为代…

react之react-redux的介绍、基本使用、获取状态、分发动作、数据流、reducer的分离与合并等

react之react-redux的介绍、基本使用、获取状态、分发动作、数据流、reducer的分离与合并等 一、react-redux介绍二、React-Redux-基本使用三、获取状态useSelector四、分发动作useDispatch五、 Redux 数据流六、代码结构七、ActionType的使用八、Reducer的分离与合并九、购物挣…

计算机视觉的应用11-基于pytorch框架的卷积神经网络与注意力机制对街道房屋号码的识别应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用11-基于pytorch框架的卷积神经网络与注意力机制对街道房屋号码的识别应用&#xff0c;本文我们借助PyTorch&#xff0c;快速构建和训练卷积神经网络&#xff08;CNN&#xff09;等模型&#xff0c;…

【Redis从头学-5】Redis中的List数据类型实战场景之天猫热销榜单

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 &#x1f4d6;所属专栏&#xff1a;Re…

Debain和MariaDB简单设置

1. Debian静态ip设置 没有网络寸步难行&#xff0c;所以要首先设置静态IP访问&#xff0c;确保网络正常。 设置静态IP vi /etc/network/interfacesauto ens33 # 开机自启ens33网卡 iface lo inet loopback # 设置回环网卡 allow-hotplug ens33 ifac…

git错误记录

露id没有影响&#xff0c;搞得微软不知道我ip一样 git fatal: 拒绝合并无关的历史的错误解决(亲测有效)

校园网安全风险分析

⒈物理层的安全风险分析 网络的物理安全风险主要指网络周边环境和物理特性引起的网络设备和线路的不可用 , 而 造成网络系统的不可用。我们在考虑校园网络安全时&#xff0c;首先要考虑物理安全风险&#xff0c;它是整个 网络系统安全的前提。物理安全风险有&#xff1a;设备…

mybatis缓存

目的&#xff1a;提高查询效率。 映射语句文件中的所有 select 语句的结果将会被缓存。映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。缓存会使用最近最少使用算法&#xff08;LRU, Least Recently Used&#xff09;算法来清除不需要的缓存。缓存不会定时进行…

Matplotlib绘图知识小结--Python数据分析学习

一、Pyplot子库绘制2D图表 1、Matplotlib Pyplot Pyplot 是 Matplotlib 的子库&#xff0c;提供了和 MATLAB 类似的绘图 API。 Pyplot 是常用的绘图模块&#xff0c;能很方便让用户绘制 2D 图表。 Pyplot 包含一系列绘图函数的相关函数&#xff0c;每个函数会对当前的图像进行…

Spring 整合RabbitMQ,笔记整理

1.创建生产者工程 spring-rabbitmq-producer 2.pom.xml添加依赖 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.7.RELEASE</version></dep…

爬虫框架- feapder + 爬虫管理系统 - feaplat 的学习简记

文章目录 feapder 的使用feaplat 爬虫管理系统部署 feapder 的使用 feapder是一款上手简单&#xff0c;功能强大的Python爬虫框架 feapder 官方文档 文档写的很详细&#xff0c;可以直接上手。 基本命令&#xff1a; 创建爬虫项目 feapder create -p first-project创建爬虫 …

根据源码,模拟实现 RabbitMQ - 实现消息持久化,统一硬盘操作(3)

目录 一、实现消息持久化 1.1、消息的存储设定 1.1.1、存储方式 1.1.2、存储格式约定 1.1.3、queue_data.txt 文件内容 1.1.4、queue_stat.txt 文件内容 1.2、实现 MessageFileManager 类 1.2.1、设计目录结构和文件格式 1.2.2、实现消息的写入 1.2.3、实现消息的删除…

如何将常用的jdbc方法封装起来???

你是否还在为每次新建项目连接数据库而烦恼&#xff1f;&#xff1f;&#xff1f;&#xff08;教你一次代码&#xff0c;简单完成每次连接&#xff09; 1.建立maven项目 还没下载安装或者不会建立maven项目的可以看这里哦&#xff1a;maven的下载安装与配置环境变量&#xff0…

设计模式——创建型

1.单例模式 单例模式主要用于某个类有且只能用一个对象的场景&#xff0c;单例模式下不能外部实例化对象&#xff0c;由类内部自行私有化实例对象并提供一个可以获得该对象的方法。单例模式主要有饿汉模式&#xff08;安全&#xff0c;但在编译时就会自动创建对象&#xff0c;…