rust - 如何在有条件地修改外部选项时返回对选项内部值的引用
问题描述
我在选项中有令牌。在每次操作之前,我需要检查令牌是否有效。它可能已过期。如果它已过期,我想将外部选项设置为 None 并返回错误,所以下次我只会得到“无令牌”错误。
#[derive(Debug)]
struct Token {
exp : u64
//other cool stuff
}
fn is_valid<'a>(v : &'a mut Option<Token> ) -> Result<&'a mut Token, String> {
match v {
None => Err("No Token".into()),
Some(v_) => {
if v_.exp > 10 {
*v = None;
Err("Token Expired".into())
}
else {
Ok(v_)
// Err("erlgnerlg".into()) //commenting this out and comenting upper line also work.
}
}
}
}
fn main() {
let mut v = Some(Token { exp : 69 });
//expecting "Token Expired" error
println!("{:?} ", is_valid(&mut v));
//expecting "No Token" error
println!("{:?} ", is_valid(&mut v));
}
但它无法编译。
error[E0506]: cannot assign to `*v` because it is borrowed
--> src/main.rs:13:17
|
8 | fn is_valid<'a>(v : &'a mut Option<Token> ) -> Result<&'a mut Token, String> {
| -- lifetime `'a` defined here
...
11 | Some(v_) => {
| -- borrow of `*v` occurs here
12 | if v_.exp > 10 {
13 | *v = None;
| ^^^^^^^^^ assignment to borrowed `*v` occurs here
...
17 | Ok(v_)
| ------ returning this value requires that `v.0` is borrowed for `'a
如果我不将 None 分配给外部选项,我的代码将编译。同样在 else 块中,如果我返回 Err 而不是 Ok,它编译得很好。为什么会发生这种情况,我该如何解决这个问题?
解决方案
首先,如果我们替换*v = None
为let _ = v.take()
(它做同样的事情),我们会得到另一个编译器错误。这产生了经典的“第二个可变借用发生在这里”:
10 | Some(v_) => {
| -- first mutable borrow occurs here
11 | if v_.exp > 10 {
12 | let _ = v.take();
| ^ second mutable borrow occurs here
...
16 | Ok(v_)
| ------ returning this value requires that `v.0` is borrowed for `'a`
这是有道理的:首先,我们解构了借来Option
的东西来看看里面,然后我们想要改变它,同时仍然参考Option
周围的内部。
但是,我们可以使用匹配守卫match
通过一条语句捕获所有条件逻辑:
match v {
None => Err("No Token".into()),
Some(v_) if v_.exp > 10 => {
dbg!(v_.exp); // use v_ in _some_ way
let _ = v.take(); // same as *v = None
Err("Token Expired".into())
}
Some(v_) => Ok(v_)
}
我不完全确定,为什么编译器会卡在您的版本上,但这是我认为发生的事情:您的匹配臂以某种方式Token
返回对内部值的引用,因此编译器推断该引用必须保持活动状态手臂的整个范围。
使用匹配守卫,它可以推断出我们再也不会触及包含的值并缩短内部借用的生命周期(我们在匹配时隐式执行的那个Some(v_) if ...
)。请注意,当我们删除先前包含的值时,此借用的生命周期恰好结束,因为我们仍然可以在行中使用它dbg!(v_.exp)
。
一旦这个内部借用结束,外部借用v
是唯一剩下的引用,并且可以触及匹配臂中的外部值。
推荐阅读
- angular - 错误 TS2554 Angular 项目预期有 4 个参数,但得到了 3 个
- sql - BigQuery 请求、生成组合并计算交集
- python-3.x - 如何使用 Pandas 为特定列分配自定义值?
- vba - 如何在其中找到带有破折号的单词?
- php - PHP 可以确定给定语言环境的给定字符串的“属格大小写”吗?
- spring - Spring SAML 扩展和 Spring Security 5
- jmeter - Jmeter Moodle 测试最大并发使用量
- java - 为什么 Double::compareTo 可以用作 Stream.max(Comparator 比较器)的参数
- django - 从 Django 中的变量列出会话中使用的所有值
- kubernetes - 如何使用 Istio Ingress 隔离内部和外部负载?