< 返回版块

leolee0101 发表于 2022-07-03 17:54

Tags:lifetime,

Cell 因为内部可变性,会让Cell 相对于T 不变。 为什么似乎在下面的函数中,并不会严格两个函数参数的lifetime完全匹配。 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=701b7efc3ed036db2147cfd74bb480cc

 fn retsct3<'a>(to_drop: &'a String, rg: Cell<&'a i32>)
{
    ;
}

函数签名中使用同一lifetime标注,并且其中一个是Cell中,传参过程中Cell<&'a i32> 相对于&'a i32 不变。传递的是Cell<&'static i32>,那就要求 函数中'a 是 'static 。而第一个参数的lifetime 只能在那个局部scope 内,这样不就冲突了吗?

评论区

写评论
苦瓜小仔 2022-07-05 13:33

我最后总结一下吧。

生命周期描述了什么

'c 标记成编译通过的生命周期参数: let cell: Cell<&'c str> = Cell::new(refincell);

那么 f 的签名 fn f<'c>(s: &'c str, cell: &Cell<&'c str>) { } 表示: 只要保持传入给 f 的 s 有效,那么 Cell<&'c str> 就能有效地存在;一旦 s 所引用的数据被销毁,则不得再使用 cell;否则导致编译错误。

variance 发挥的作用

因为 Cell 对 'c 是 invariant,这意味着传递给 cell 这个参数的生命周期时,'c 应保持不变。

但这不会阻止对其他参数发生隐式的型变转换: & 对 'c 是 covariant,所以对于给定的 'c,任何传递给 s 参数的引用可以至少比 'c 长。我的例子中, 'static: 'c、'string: 'c、's: 'c 都满足这些时,代码才能通过。

苦瓜小仔 2022-07-05 12:11

是。。。。。。。。。。

use std::cell::Cell;
fn f<'a>(s: &'a str, cell: &Cell<&'a str>) {
    cell.set(s);
    dbg!(cell);
}

fn main() {
    let string = String::from("outer: string");
    let refincell = &string;

    //let cell: Cell<&'static str> = Cell::new(refincell);// can't be this
    let cell: Cell<&'_ str> = Cell::new(refincell);
    f("alive", &cell);
    {
        let s = String::from("local: s");
        f(&s, &cell);
        f(&string, &cell);
        drop(string);
        f("error due to the lifetime of string", &cell);
    }
    //f("error due to the lifetime of s", &cell);
}

--
👇
leolee0101: 是不是 应该是 &'_ i32 短于等于 ss ?

作者 leolee0101 2022-07-05 11:55

是不是 应该是 &'_ i32 短于等于 ss ?

--
👇
苦瓜小仔: 我的表述还存在一点问题。

sc 的类型是一个被推断的更短的生命周期的 Cell<&'_ i32> ,但 &'_ i32 一定比 ss 要长(而不是我之前说的,与变量 ss 生命周期相同)。

更准确地说,Cell<&'_ i32> 中的 &'_ i32 的确是(因为 invariance)固定的,但当前 Rust 借用规则 NLL 实质上是围绕生命周期的约束集合求解。

具体的逻辑推断,我帮你在官方论坛提问了,@Steffahn 大佬回答得很详尽。 https://users.rust-lang.org/t/help-me-to-understand-invariance-and-lifetime-here

Mike Tang 2022-07-04 23:22

感谢苦瓜小仔仔~~

苦瓜小仔 2022-07-04 09:03

我也有很多东西不知道,不是大佬 :)

回答问题也是一种学习。相互学习~

作者 leolee0101 2022-07-04 06:40

哇,中外大佬们的热情和精力,让人钦佩。苦瓜大佬是专职rust相关的(维护中文社区?之类)吗,感觉精力特别棒,回答提问都特别详细认真。跟以前知乎里编译原理虚拟机领域里的 FX 一样。五体佩服。

--
👇
苦瓜小仔: 我的表述还存在一点问题。

sc 的类型是一个被推断的更短的生命周期的 Cell<&'_ i32> ,但 &'_ i32 一定比 ss 要长(而不是我之前说的,与变量 ss 生命周期相同)。

更准确地说,Cell<&'_ i32> 中的 &'_ i32 的确是(因为 invariance)固定的,但当前 Rust 借用规则 NLL 实质上是围绕生命周期的约束集合求解。

具体的逻辑推断,我帮你在官方论坛提问了,@Steffahn 大佬回答得很详尽。 https://users.rust-lang.org/t/help-me-to-understand-invariance-and-lifetime-here

苦瓜小仔 2022-07-04 00:49

我的表述还存在一点问题。

sc 的类型是一个被推断的更短的生命周期的 Cell<&'_ i32> ,但 &'_ i32 一定比 ss 要长(而不是我之前说的,与变量 ss 生命周期相同)。

更准确地说,Cell<&'_ i32> 中的 &'_ i32 的确是(因为 invariance)固定的,但当前 Rust 借用规则 NLL 实质上是围绕生命周期的约束集合求解。

具体的逻辑推断,我帮你在官方论坛提问了,@Steffahn 大佬回答得很详尽。 https://users.rust-lang.org/t/help-me-to-understand-invariance-and-lifetime-here

作者 leolee0101 2022-07-03 21:21

感谢。有了这么详细的解答,才明白。属实有点愚钝了。确实是没注意到sc 类型推断的地方。

--
👇
苦瓜小仔: > 传递的是Cell<&'static i32>,那就要求 函数中'a 是 'static

这句话是对的。在你的例子中,标注 let sc: Cell<&'static i32> = Cell::new( refincell); 就可以印证:

error[E0597]: `ss` does not live long enough
  --> src/main.rs:24:17
   |
19 |     let sc: Cell<&'static i32> = Cell::new( refincell);
   |             ------------------ type annotation requires that `ss` is borrowed for `'static`
...
24 |         retsct3(&ss, sc);
   |                 ^^^ borrowed value does not live long enough
25 | 
26 |     }
   |     - `ss` dropped here while still borrowed

所以 sc (在声明时)的类型(就已经)不是 Cell<&'static i32>,而是一个(根据 retsct3 的 Cell<&'a i32> 推断出的)更短生命周期的 Cell<&'ss i32> (与变量 ss 生命周期相同)。

你只关注到了 Cell<&'a i32> 是 invariant,但没关注到 &'lifetime T 是 covariant。

作者 leolee0101 2022-07-03 21:19

感谢,新手,一时间没点透。看了 苦瓜兄 的解答,才明白您说的是哪个地方。惭愧。

--
👇
7sDream: 因为 &'a T 对于 'a 是协变的。

苦瓜小仔 2022-07-03 21:03

传递的是Cell<&'static i32>,那就要求 函数中'a 是 'static

这句话是对的。在你的例子中,标注 let sc: Cell<&'static i32> = Cell::new( refincell); 就可以印证:

error[E0597]: `ss` does not live long enough
  --> src/main.rs:24:17
   |
19 |     let sc: Cell<&'static i32> = Cell::new( refincell);
   |             ------------------ type annotation requires that `ss` is borrowed for `'static`
...
24 |         retsct3(&ss, sc);
   |                 ^^^ borrowed value does not live long enough
25 | 
26 |     }
   |     - `ss` dropped here while still borrowed

所以 sc (在声明时)的类型(就已经)不是 Cell<&'static i32>,而是一个(根据 retsct3 的 Cell<&'a i32> 推断出的)更短生命周期的 Cell<&'ss i32> (与变量 ss 生命周期相同)。

你只关注到了 Cell<&'a i32> 是 invariant,但没关注到 &'lifetime T 是 covariant。

7sDream 2022-07-03 19:33

因为 &'a T 对于 'a 是协变的。

1 共 11 条评论, 1 页