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

news/2024/11/21 1:37:38/

说在前面

  • 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.ppmy.cn/news/1044131.html

相关文章

36.SpringMVC视图

SpringMVC视图 SpringMVC中的视图是View接口&#xff0c;视图的作用渲染数据&#xff0c;将模型Model中的数据展示给用户 SpringMVC视图的种类很多&#xff0c;默认有转发视图(InternalResourceView)和重定向视图(RedirectView) 配置视图&#xff1a; 当工程引入jstl的依赖&a…

Java 计算两个字符的相似度

在Java中&#xff0c;要计算两个字符的相似度&#xff0c;可以借助一些字符串相似度算法。以下是几种常见的字符串相似度算法&#xff1a; Levenshtein距离&#xff1a;也称为编辑距离&#xff0c;用于计算两个字符串之间的最小编辑操作次数&#xff08;插入、删除、替换&…

Unity进阶–通过PhotonServer实现人物移动和攻击–PhotonServer(五)

文章目录 Unity进阶–通过PhotonServer实现人物移动和攻击–PhotonServer(五)DLc&#xff1a; 消息类和通信类服务器客户端 Unity进阶–通过PhotonServer实现人物移动和攻击–PhotonServer(五) DLc&#xff1a; 消息类和通信类 Message namespace Net {public class Message{p…

力扣75——单调栈

总结leetcode75中的单调栈算法题解题思路。 上一篇&#xff1a;力扣75——区间集合 力扣75——单调栈 1 每日温度2 股票价格跨度1 - 2 解题总结 1 每日温度 题目&#xff1a; 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &…

「UG/NX」Block UI 面收集器FaceCollector

✨博客主页何曾参静谧的博客📌文章专栏「UG/NX」BlockUI集合📚全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C+&#

Codeforces Round 153 (Rated for Div. 2)

目录 A. Not a Substring 题目&#xff1a; 解析&#xff1a; B. Fancy Coins 题目&#xff1a; 解析&#xff1a; C. Game on Permutation 题目&#xff1a; 解析&#xff1a; A. Not a Substring 题目&#xff1a; A bracket sequence is a string consisting of ch…

2023全网Mysql 合集(25w字)附课程 从安装到高级,实战

mysql学习 1.安装mysql 安装教程 2.mysql的详细学习教程 mysql的详细教程 3.mysql 的高级优化 MySQL高级篇&#xff08;SQL优化、索引优化、锁机制、主从复制&#xff09; 4.MySQL 面试 MySQL数据库面试题总结 二.mysql实战 一、创建数据表并插入数据 1、学生表 Stud…