编辑:张汉东
为生命周期参数命名
假如有这样一段代码:
struct Person {name: String}impl Person {pub fn name<'a>(&'a self) -> &'a str {&self.name}}
上面示例只是简单的单一生命周期参数'a,但我们将其重写命名为'me,可能会更加直观:
struct Person {name: String}impl Person {pub fn name<'me>(&'me self) -> &'me str {&self.name}}
在下面一些场景中,命名生命周期参数可能更好:
场景一
use once_cell::unsync::OnceCell;struct Provider {data_cache: OnceCell<Data>,metadata_cache: OnceCell<Metadata>,}// ...fn process_data(data: &Data) -> Result<&str> {// ...}
修正为:
fn process_data<'prov>(data: &'prov Data) -> Result<&'prov str> {// ...}
将生命周期参数命名为 'prov 有助于标识 data 数据来自于 Provider结构体实例。 在 Rust 编译器源码中也能见到'tcx这样的命名,用来标识这是类型上下文(typing context )。
场景二
struct Article {title: String,author: Author,}#[derive(PartialEq, Eq)]struct Author {name: String,}struct ArticleProvider {articles: Vec<Article>,}struct AuthorProvider {authors: Vec<Author>,}// 这里具有两种生命周期参数命名struct AuthorView<'art, 'auth> {author: &'auth Author,articles: Vec<&'art Article>,}// 这里具有两种生命周期参数命名// 在需要指定两个生命周期参数长短关系的时候可以通过 'auth : 'art 这种方式指定,但是此处不需要fn authors_with_articles<'art, 'auth>(article_provider: &'art ArticleProvider,author_provider: &'auth AuthorProvider,) -> Vec<AuthorView<'art, 'auth>> {author_provider.authors.iter().map(|author| {let articles = article_provider.articles.iter().filter(|article| &article.author == author).collect();AuthorView { author, articles }}).collect()}
小结
将生命周期参数重新命名,面对使用引用比较复杂的场景,可以增加可读性,方便开发者分析生命周期参数。这算得上一个最佳实践。
来源: https://www.possiblerust.com/pattern/naming-your-lifetimes
优化技巧:Rust 中 match 分支语句中避免使用 ?
来自微信群:David Li
最近碰到rust的一个坑,在match 的分支里面使用?可能会导致栈内存特别大。
有一个函数,match 一个 Enum,这个Enum 有十几个定义,因此match 有十几个分支,每个分支里面最后都会调一个函数,返回值是Result,因此使用了?。
上周测试报告说 debug 版本跑查询进程会崩掉,分析发现栈溢出了。我们上层代码把线程栈设置为 512 KB,然后调试发现某些函数栈内存竟然用了几百KB。
代码示意:
match SomeEnum {One(_) => get_result()?,Two(_) => get_result()?,Three(_) => get_result()?,Four(_) => get_result()?,Five(_) => get_result()?,//...}
最后把match分支的Result去掉?,把 match表达式赋值 给临时变量之后再用?,内存占用降下来了。
代码示意:
let get_res = match SomeEnum {One(_) => get_result(),Two(_) => get_result(),Three(_) => get_result(),Four(_) => get_result(),Five(_) => get_result(),//...};let res = get_res?
P.S : 还可以获得一个优化技巧是:先把栈内存调低点,让这种问题尽早暴露。
