最近在用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. Bika LIMS 开源LIMS集—— SENAITE的使用(检测流程)

    客户管理 登记客户信息,包括地址.合同报告邮寄地址.账单邮寄地址.付款银行账号等. 产品批次管理 例如某乳品公司生产处一批产品,该批产品送往实验室检测,实验室登记该批产品批号,如对该批产品做多次检测, ...

  2. SkiaSharp 之 WPF 自绘 投篮小游戏(案例版)

    此案例主要是针对光线投影法碰撞检测功能的示例,顺便做成了一个小游戏,很简单,但是,效果却很不错. 投篮小游戏 规则,点击投篮目标点,就会有一个球沿着相关抛物线,然后,判断是否进入篮子里,其实就是一个矩 ...

  3. NetCore路由的Endpoint模式

    IdentityServer里有各种Endpoint,如TokenEndpoint,UserInfoEndpoint,Authorize Endpoint,Discovery Endpoint等等.E ...

  4. 不会提交 PR 的小伙伴看过来,超详细的视频教程!

    点击上方 蓝字关注我们 作者 | 严天奇 ✎ 编 者 按 最近有一些新加入社区的朋友反馈不太了解 Apache DolphinScheduler 提交 PR 的步骤和规则.这不,人帅心美的严天奇同学就 ...

  5. 在Go中如何正确重试请求

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/677 我们平时在开发中肯定避不开的一个问题是如何在不可靠的网络服务中 ...

  6. ASP.NET Core 5.0中的Host.CreateDefaultBuilder执行过程

      通过Rider调试的方式看了下ASP.NET Core 5.0的Web API默认项目,重点关注Host.CreateDefaultBuilder(args)中的执行过程,主要包括主机配置.应用程 ...

  7. PerfView专题 (第四篇):如何寻找 C# 中程序集泄漏

    一:背景 前两篇我们都聊到了非托管内存泄漏,一个是 HeapAlloc ,一个是 VirtualAlloc,除了这两种泄漏之外还存在其他渠道的内存泄漏,比如程序集泄漏,这一篇我们就来聊一聊. 二: 程 ...

  8. java学习第二天小细节.day10

    栈内存溢出表示可以使用递归 This的使用 普通方法,字段,其他方法与构造器三种访问方法 Super的使用 在子类如果需要使用到父类的字段者使用到super(字段,字段),需要放到第一行,因需要初始化 ...

  9. 一文理解Hadoop分布式存储和计算框架入门基础

    @ 目录 概述 定义 发展历史 发行版本 优势 生态项目 架构 组成模块 HDFS架构 YARN架构 部署 部署规划 前置条件 部署步骤 下载文件(三台都执行) 创建目录(三台都执行) 配置环境变量( ...

  10. package.json 与 package-lock.json 的关系

    模块化开发在前端越来越流行,使用 node 和 npm 可以很方便的下载管理项目所需的依赖模块.package.json 用来描述项目及项目所依赖的模块信息. 那 package-lock.json  ...