文盤Rust -- struct 中的生命週期
最近在用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 問題。俗話講:"揹著抱著,一樣沉".我本人還是傾向於把問題控制在上線之前,少折騰使用者。
本期咱們先聊到這兒,下期見
「其他文章」
- Redis 非同步客戶端選型及落地實踐
- Java CompletableFuture 非同步超時實現探索
- 碼農如何提高自己的品味
- 程式設計師大殺器?帶你玩轉ChatGPT
- 一文搞懂Redis
- R2M分散式鎖原理及實踐
- Backbone前端框架解讀
- drools規則動態化實踐
- 搞懂設計模式——代理模式 原理分析
- 從歷代GC演算法角度刨析ZGC
- 一次JSF上線問題引發的MsgPack深入理解,保證對你有收穫
- 一種基於圖片搜尋影片的方案
- 雲原生場景下實現編譯加速
- 隨機高併發查詢結果一致性設計實踐
- 全球首個面向遙感任務設計的億級視覺Transformer大模型
- 如何實現千萬級優惠文章的優惠資訊同步
- 基於Spring Cache實現Caffeine、jimDB多級快取實戰
- 【演算法與資料結構】Trie樹簡介及應用
- 認知篇:CQRS架構模式的本質
- Redis快取的主要異常及解決方案