最近在用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. netdata检测工具的安装与使用

    Netdata 是一款 Linux 性能实时监测工具..以web的可视化方式展示系统及应用程序的实时运行状态(包括cpu.内存.硬盘输入/输出.网络等linux性能的数据). Netdata文档地址: ...

  2. Python3.7+Django2.0.4配合Mongodb打造高性能高扩展标签云存储方案

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_141 书接上回,之前有一篇文章提到了标签云系统的构建:Python3.7+jieba(结巴分词)配合Wordcloud2.js来构 ...

  3. React Native环境配置、初始化项目、打包安装到手机,以及开发小知识

    1.前言 环境:Win10 + Android 已经在Windows电脑上安装好 Node(v14+).Git.Yarn. JDK(v11) javac -version javac 11.0.15. ...

  4. 3.联合索引、覆盖索引及最左匹配原则|MySQL索引学习

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 导语 在数据检索的过程中,经常会有多个列的匹配需求,今天介绍下联合索引的使用以及最左匹配原则的案例. 最左匹配原则作用在联 ...

  5. Python基础之list和tuple的使用

    list和tuple的使用 list Python内置的一种数据类型列表:list list是一种有序的集合,可以随身添加和删除其中的元素. 比如列出办理所有同学的名字,就可以用一个list表示: & ...

  6. CF 559C - Gerald and Giant Chess (组合计数)

    \(C_{x+y}^y\)的公式,DP容斥删多余贡献. #include <cstdio> #include <iostream> #include <cstring&g ...

  7. MySQL 连接超时:报错SQLSTATE[HY000] [2002] Connection timed out

    在网上找了一堆,结果全部是错的 后来,我明白了其实是设置问题. 当你的代码部署到服务器里的时候,你的mysql 的host 值 应该为 127.0.0.1 而不是 你的服务器ip 不然就会报错. 其实 ...

  8. Express 使用 Cookie

    在使用 Cookie 之前,需要给 Express 加载中间件,cookie-parser: npm i cookie-parser Express 使用中间件: import express fro ...

  9. Word 脚注和尾注是什么?怎么设置?

    描述 脚注一般位于页面的底部,作为文档某处内容的注释.尾注一般位于文档的末尾,列出引文的出处等. 设置脚注和尾注 将光标移动到要插入脚注或尾注的地方,然后点击"引用"选项卡. 左边 ...

  10. JS的简介

    JS式JavaScript的简称,它是一门弱语言,它可以实现让网页动起来 JS的构成 核心(ECMAScript) 文档对象模型(DOM)-- Document Object  Module 浏览器对 ...