She*_*ter 92
通过理解词汇生命周期,最容易理解非词汇生命周期是什么.在存在非词法生命周期之前的Rust版本中,此代码将失败:
fn main() {
let mut scores = vec![1, 2, 3];
let score = &scores[0];
scores.push(4);
}
Run Code Online (Sandbox Code Playgroud)
Rust编译器看到这scores是由score变量借用的,所以它不允许进一步突变scores:
error[E0502]: cannot borrow `scores` as mutable because it is also borrowed as immutable
--> src/main.rs:4:5
|
3 | let score = &scores[0];
| ------ immutable borrow occurs here
4 | scores.push(4);
| ^^^^^^ mutable borrow occurs here
5 | }
| - immutable borrow ends here
Run Code Online (Sandbox Code Playgroud)
然而,人可以平凡看到,这个例子是过于保守:score是从来没有使用过!的问题是,借scores由score是词汇 -它持续直到其被包含在所述块的端部:
fn main() {
let mut scores = vec![1, 2, 3]; //
let score = &scores[0]; //
scores.push(4); //
// <-- score stops borrowing here
}
Run Code Online (Sandbox Code Playgroud)
非词汇生命周期通过增强编译器来理解这种细节水平来解决这个问题.编译器现在可以更准确地判断何时需要借用并且此代码将被编译.
关于非词汇生命周期的一个奇妙的事情是,一旦启用,没有人会想到它们.它将简单地变成"Rust所做的",并且(希望)事情将会起作用.
Rust旨在仅允许已知安全程序进行编译.但是,不可能只允许安全的程序并拒绝不安全的程序.为此,Rust在保守方面犯了错误:一些安全程序被拒绝.词汇生命周期就是其中的一个例子.
词汇生命周期在编译器中更容易实现,因为块的知识是"微不足道的",而数据流的知识则不那么简单.需要重写编译器以引入和使用"中级中间表示"(MIR).然后必须重写借用检查器(也称为"借用")以使用MIR而不是抽象语法树(AST).然后必须将借用检查器的规则细化为更细粒度.
词汇生命周期并不总是妨碍程序员,并且有许多方法可以解决词汇生命周期,即使它们很烦人.在许多情况下,这涉及添加额外的花括号或布尔值.这使得Rust 1.0能够在非词汇生命周期实施之前运行多年.
有趣的是,由于词汇生命周期,某些良好的模式被开发出来.最典型的例子对我来说的entry模式.此代码在非词汇生命周期之前失败并编译它:
fn example(mut map: HashMap<i32, i32>, key: i32) {
match map.get_mut(&key) {
Some(value) => *value += 1,
None => {
map.insert(key, 1);
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,此代码效率低,因为它会计算密钥的哈希值两次.由于词汇生命周期而创建的解决方案更短且更有效:
fn example(mut map: HashMap<i32, i32>, key: i32) {
*map.entry(key).or_insert(0) += 1;
}
Run Code Online (Sandbox Code Playgroud)
值的生存期是值保持在特定内存地址的时间跨度(请参阅为什么我不能在同一结构中存储值和对该值的引用?以获得更长的解释).被称为非词汇生命周期的特征不会改变任何值的生命周期,因此它不能使生命周期变为非词汇.它只使跟踪和检查这些值的借用更加精确.
该功能的更准确的名称可能是"非词汇借用 ".一些编译器开发人员参考了底层的"基于MIR的借用".
非词汇生命周期本身从未打算成为"面向用户"的功能.由于我们从他们的缺席中获得的小小的剪切,他们在我们的脑海中大多数都变得很大.他们的名字主要用于内部开发目的,为了营销目的而改变它从来都不是优先事项.
在Rust 1.31(2018-12-06发布)中,您需要选择Cargo.toml中的Rust 2018版本:
[package]
name = "foo"
version = "0.0.1"
authors = ["An Devloper <an.devloper@example.com>"]
edition = "2018"
Run Code Online (Sandbox Code Playgroud)
如果你还在使用2015版本,那么在稳定的Rust中还没有非词汇生命周期.在每晚版本的Rust中,你可以通过一个功能选择加入NLL:
#![feature(nll)]
Run Code Online (Sandbox Code Playgroud)
您甚至可以使用编译器标志选择加入NLL的实验版本-Z polonius.
| 归档时间: |
|
| 查看次数: |
6149 次 |
| 最近记录: |