语言技巧
编辑:张汉东
为生命周期参数命名
假如有这样一段代码:
#![allow(unused)] fn main() { struct Person { name: String } impl Person { pub fn name<'a>(&'a self) -> &'a str { &self.name } } }
上面示例只是简单的单一生命周期参数'a
,但我们将其重写命名为'me
,可能会更加直观:
#![allow(unused)] fn main() { struct Person { name: String } impl Person { pub fn name<'me>(&'me self) -> &'me str { &self.name } } }
在下面一些场景中,命名生命周期参数可能更好:
场景一
#![allow(unused)] fn main() { use once_cell::unsync::OnceCell; struct Provider { data_cache: OnceCell<Data>, metadata_cache: OnceCell<Metadata>, } // ... fn process_data(data: &Data) -> Result<&str> { // ... } }
修正为:
#![allow(unused)] fn main() { fn process_data<'prov>(data: &'prov Data) -> Result<&'prov str> { // ... } }
将生命周期参数命名为 'prov
有助于标识 data 数据来自于 Provider
结构体实例。 在 Rust 编译器源码中也能见到'tcx
这样的命名,用来标识这是类型上下文(typing context )。
场景二
#![allow(unused)] fn main() { 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。
代码示意:
#![allow(unused)] fn main() { match SomeEnum { One(_) => get_result()?, Two(_) => get_result()?, Three(_) => get_result()?, Four(_) => get_result()?, Five(_) => get_result()?, //... } }
最后把match分支的Result去掉?
,把 match表达式赋值 给临时变量之后再用?
,内存占用降下来了。
代码示意:
#![allow(unused)] fn main() { 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 : 还可以获得一个优化技巧是:先把栈内存调低点,让这种问题尽早暴露。