update对抗编译检查-循环生命周期

pull/193/head
sunface 3 years ago
parent 72708becdd
commit 3e5f5c5405

@ -127,13 +127,63 @@ fn random_empty_tile_2<'arr>(arr: &'arr mut [Tile]) -> &'arr mut Tile {
结果,编译器还是不给通过,报的错误几乎一样
## 深层原因
令人沮丧的是,我找遍了网上,也没有具体的原因,大家都说这是编译器太笨导致的问题,但是关于深层的原因,也没人能说出个
所有然。
令人沮丧的是,我找遍了网上,也没有具体的原因,大家都说这是编译器太笨导致的问题,但是关于深层的原因,也没人能说出个所有然。
因此,我无法在本文中给出为什么编译器会这么笨的真实原因,如果以后有结果,会在这里进行更新。
## 解决办法
虽然不能给出原因,但是我们可以看看解决办法,在上面,**移除中间变量**是一种办法,还有一种办法就是将部分引用移到循环外面.
------2022年1月13日更新-------
兄弟们,我带着挖掘出的一些内容回来了,再来看段错误代码先:
```rust
struct A {
a: i32
}
impl A {
fn one(&mut self) -> &i32{
self.a = 10;
&self.a
}
fn two(&mut self) -> &i32 {
loop {
let k = self.one();
if *k > 10i32 {
return k;
}
// 可能存在的剩余代码
// ...
}
}
}
```
我们来逐步深入分析下:
1. 首先为`two`方法增加一下生命周期标识: `fn two<'a>(&'a mut self) -> &'a i32 { .. }`, 这里根据生命周期的[消除规则](../../advance/lifetime/basic.md#三条消除规则)添加的
2. 根据生命周期标识可知:`two`中返回的`k`的生命周期必须是`'a`
3. 根据第2条又可知`let k = self.one();`中对`self`的借用生命周期也是`'a`
4. 因为`k`的借用发生在`loop`循环内,因此它需要小于等于循环的生命周期,但是根据之前的推断,它又要大于等于函数的生命周期`'a`,而函数的生命周期又大于等于循环生命周期,
由上可以推出:`let k = self.one();`中`k`的生命周期要大于等于循环的生命周期,又要小于等于循环的生命周期, 唯一满足条件的就是:`k`的生命周期等于循环生命周期。
但是我们的`two`方法在循环中对`k`进行了提前返回,编译器自然会认为存在其它代码,这会导致`k`的生命周期小于循环的生命周期。
怎么办呢?很简单:
```rust
fn two(&mut self) -> &i32 {
loop {
let k = self.one();
return k;
}
}
```
不要在`if`分支中返回`k`,而是直接返回,这样就让它们的生命周期相等了,最终可以顺利编译通过。
> 如果一个引用值从函数的某个路径提前返回了,那么该借用必须要在函数的所有返回路径都合法
## 解决方法
虽然不能给出原因,但是我们可以看看解决办法,在上面,**移除中间变量**和**消除代码分支**都是可行的方法,还有一种方法就是将部分引用移到循环外面.
#### 引用外移
```rust

Loading…
Cancel
Save