最近在用rust 写一个redis的数据校验工具。redis-rs中具备 redis::ConnectionLike trait,借助它可以较好的来抽象校验过程。在开发中,不免要定义struct 中的某些元素为 trait object,从而带来一些rust语言中的生命周期问题。

本文不具体讨论 redis的数据校验过程,通过一个简单的例子来聊聊 struct 中 trait object 元素的生命周期问题。

首先来定义一个 base trait,该 trait 中只包含一个函数,返回String类型。

pub trait Base {
fn say(&self) -> String;
}

接下来,定义两个实现了 Base trait 的 struct AFromBase 和 BFromBase

pub struct AFromBase {
content: String,
} impl Base for AFromBase {
fn say(&self) -> String {
self.content.clone()
}
} pub struct BFromBase {
text: String,
} impl Base for BFromBase {
fn say(&self) -> String {
self.text.clone()
}
}

接下来,定义一个struct 包含两个 Base trait 的 trait object ,然后实现一个函数是 say 函数输出的字符串的拼接结果.

按照其他没有生命周期语言的编写习惯,直觉上这么写

pub struct AddTowBase {
a: &mut dyn Base,
b: &mut dyn Base,
} impl AddTowBase {
fn add(&self) -> String {
let result = self.a.say() + &self.b.say();
result
}
}

最后,搞个main函数验证一下。

完整代码如下

pub trait Base {
fn say(&self) -> String;
} pub struct AFromBase {
content: String,
} impl Base for AFromBase {
fn say(&self) -> String {
self.content.clone()
}
} pub struct BFromBase {
text: String,
} impl Base for BFromBase {
fn say(&self) -> String {
self.text.clone()
}
} pub struct AddTowBase {
a: &mut dyn Base,
b: &mut dyn Base,
} impl<'a> AddTowBase<'a> {
fn add(&self) -> String {
let result = self.a.say() + &self.b.say();
result
}
} fn main() {
let mut a = AFromBase {
content: "baseA".to_string(),
}; let mut b = BFromBase {
text: "baseB".to_string(),
}; let addtow = AddTowBase {
a: &mut a,
b: &mut b,
};
let r = addtow.add();
println!("{}", r);
}

很遗憾,以上代码是不能编译通过的,编译时报如下错误

error[E0106]: missing lifetime specifier
--> examples/lifetimeinstruct.rs:26:8
|
26 | a: &mut dyn Base,
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
25 ~ pub struct AddTowBase<'a> {
26 ~ a: &'a mut dyn Base,
| error[E0106]: missing lifetime specifier
--> examples/lifetimeinstruct.rs:27:8
|
27 | b: &mut dyn Base,
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
25 ~ pub struct AddTowBase<'a> {
26 | a: &mut dyn Base,
27 ~ b: &'a mut dyn Base,
| For more information about this error, try `rustc --explain E0106`.
error: could not compile `wenpan-rust` due to 2 previous errors

编译器给出的提示很明确,要在 trait object 上添加生命周期参数,确保 struct 和他的 trait object 元素在同一生命周期,避免悬垂指针。

我们按照编译器的提示修改代码

pub struct AddTowBase<'a> {
a: &'a mut dyn Base,
b: &'a mut dyn Base,
} impl<'a> AddTowBase<'a> {
fn add(self) -> String {
let result = self.a.say() + &self.b.say();
result
}
}

代码顺利通过编译。

rust 的生命周期保证了内存的安全性,同时也增加了开发者的心智负担。是在上线之前多费心思写代码,还是在上线以后忙忙活活查问题,这是个 trade off 问题。俗话讲:"背着抱着,一样沉".我本人还是倾向于把问题控制在上线之前,少折腾用户。

本期咱们先聊到这儿,下期见

文盘Rust -- struct 中的生命周期的更多相关文章

  1. 【译】深入理解Rust中的生命周期

    原文标题:Understanding Rust Lifetimes 原文链接:https://medium.com/nearprotocol/understanding-rust-lifetimes- ...

  2. Vue 实例中的生命周期钩子

    Vue 框架的入口就是 Vue 实例,其实就是框架中的 view model ,它包含页面中的业务处理逻辑.数据模型等,它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻 ...

  3. 详解Vue 实例中的生命周期钩子

    Vue 框架的入口就是 Vue 实例,其实就是框架中的 view model ,它包含页面中的业务处理逻辑.数据模型等,它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻 ...

  4. vue中的生命周期

    vue中的生命周期 1,vue生命周期简介: 1.beforeCreate 在实例初始化之后,数据观测和event/watcher时间配置之前被调用.   2.created 实例已经创建完成之后被调 ...

  5. Java对象在JVM中的生命周期

          当你通过new语句创建一个java对象时,JVM就会为这个对象分配一块内存空间,只要这个对象被引用变量引用了,那么这个对象就会一直驻留在内存中,否则,它就会结束生命周期,JVM会在合适的时 ...

  6. [转] IOS中AppDelegate中的生命周期事件的调用条件

    IOS中AppDelegate中的生命周期事件的调用条件 //当应用程序将要进入非活动状态执行,在此期间,应用程序不接受消息或事件,比如来电 - (void)applicationWillResign ...

  7. 《React Native 精解与实战》书籍连载「React Native 中的生命周期」

    此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...

  8. DataSnap高级技术(7)—TDSServerClass中Lifecycle生命周期三种属性说明

    From http://blog.csdn.net/sunstone/article/details/5282666 DataSnap高级技术(7)—TDSServerClass中Lifecycle生 ...

  9. 12、Cocos2dx 3.0游戏开发找小三之3.0中的生命周期分析

    重开发人员的劳动成果.转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27706303 生命周期分析 在前面文章中我们执行了第 ...

随机推荐

  1. [BJDCTF2020]Cookie is so stable-1|SSTI注入

    1.打开之后在各个界面查看源代码,未发现很明显的有用信息,仅发现了提示,结果如下: 2.尝试输入数据,结果就是输入什么就回显什么,也未进行过滤,尝试进行sql注入失败,结果如下: 3.那就根据提示抓包 ...

  2. spring boot实现不同生产环境下的文件配置

    配置不同生产环境 本文适用于开发环境下需要打包项目至生产环境,避免开发环境的配置文件泄露. 设置maven 作用:1. 手动调节运行时的不同环境 2. 打包时可以不会有其它环境的文件 注:每次换环境前 ...

  3. k8s QoS与pod驱逐

    概述 QoS是Quality of Service的缩写,即服务质量.每个pod属于某一个QoS分类,而Kubernetes会根据pod的QoS级别来决定pod的调度.抢占调度和驱逐优先级,而且pod ...

  4. linux常用命令和快捷键收集

    find / -name php #查找根目录下所有包含 php 字符的文件和目录 find / -ctime 1 #查找最近一天下载的文件和目录 yum install lrzsz #安装上传下载组 ...

  5. Linux ssh协议

    基础知识 ssh:secure shell protocol,安全的远程登录 作用:是建立在应用层基础上的安全协议,实现数据传输过程中数据的加密,代替telent协议 使用tcp协议,端口号为22 s ...

  6. Java集合容器的深度理解

    Java容器里有很多写好的容器API,这使我们很方便的可以存储.操作我们的数据. 下面是我写的容器的特点,一些容器的不同之处,从底层源码解析一下容器实现原理 一.常用的容器目录 上图可以看出,java ...

  7. 【manim】3b1b的"Almost" Fourier Transform复刻

    最近在做Fourier Transform的内容,记录一下今天下午的成果. 本文代码全部自行编写,需要math and music项目完整工程可以在gayhub上获取.(现在还没弄完,就先不发了.) ...

  8. 没写完。【java】IDEA-调教界面、设置语言、插件的使用

    步骤: 1.官方网站:https://www.jetbrains.com/idea/ (zip)版本:https://download.jetbrains.com.cn/idea/ideaIC-202 ...

  9. 第八十五篇:Vue购物车(六) 总价的动态计算

    好家伙, 1.实现总价的动态计算 商品数量被动态的改变后, 相应的总价同样会改变 所以我们需要重新计算总价格了 这个的实现并不难 我只要拿到商品的数量就好了 我们用一个计算属性计算出已勾选商品的总数量 ...

  10. centos7设置时间和上海时区并进行同步

    1.设置时区(同步时间前先设置) timedatectl set-timezone Asia/Shanghai 2.安装组件 yum -y install ntp systemctl enable n ...