关于rust:文盘Rust-struct-中的生命周期

42次阅读

共计 2258 个字符,预计需要花费 6 分钟才能阅读完成。

最近在用 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 问题。俗话讲:” 背着抱着,一样沉 ”. 我自己还是偏向于把问题管制在上线之前,少折腾用户。

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

正文完
 0