< 返回版块

leolee0101 发表于 2023-10-22 07:18

Tags:HRTB; lifetime

在查看这个项目时,其中有一段注释,关于 impl 块和 HRTB 中 life 约束,

impl<'id> GhostToken<'id> {
    /// Create a new `GhostToken` with a particular lifetime identifier, `'id`.
    ///
    /// The argument function `f` must be parametric with respect to its lifetime
    /// parameter `'new_id`; this guarantees that `'id` is chosen by `new`, not
    /// the client. Because `'id` is invariant with respect to `GhostToken`, and
    /// cannot be chosen by the client to replicate an existing `GhostToken`, we
    /// know that `'id` is unique per call of `new`.
    #[inline]
    pub fn new<F, R>(f: F) -> R
    where
        F: for<'new_id> FnOnce(GhostToken<'new_id>) -> R,
    {
        // We choose the lifetime; it is definitely unique for each new instance
        // of `GhostToken`.
        let token = GhostToken {
            _marker: InvariantLifetime::new(),
        };
        // Return the result of running `f`.  Note that the `GhostToken` itself
        // cannot be returned, because `R` cannot mention the lifetime `'id`, so
        // the `GhostToken` only exists within its scope.
        f(token)
    }
}

其中,这一段理解的不是特别清楚:

`f` must be parametric with respect to its lifetime parameter `'new_id`; 
this guarantees that `'id` is chosen by `new`, not the client. 
Because `'id` is invariant with respect to `GhostToken`, 
and cannot be chosen by the client to replicate an existing `GhostToken`
  1. 是说,闭包参数使用 'new_id ,确保了 GhostToken 的 'id 由 new 函数内 决定,而不是 new 的调用者决定吗?
  2. 如果是,那么 new 调用者 也只能决定 传入一个 (关于life的)泛型闭包。还是得在 new 内部, GhostToken 实例化,他的 'id 泛型具体化之后,才能决定 闭包的 life 参数。 这样的话,'id 不还是由 new 决定不是 client 决定的吗?
  3. 为什么 client 决定 'id ,就可以复制 存在的 GhostToken ?

评论区

写评论
作者 leolee0101 2023-10-25 09:50

那么在 推断闭包的 类型 (编译 GhostToken::new(|token|token) ) 时,似乎 : F: FnOnce(GhostToken<'id>) -> R, 的情况, 函数被推断为 单型函数 fn f(GhostToken<'1>) -> GhostToken<'1> ;
而 F: for<'new_id> FnOnce(GhostToken<'new_id>) -> R ,被推断为泛型函数 fn f(GhostToken<'1>) -> GhostToken<'2> 。

前者 GhostToken::new(|token|token) 调用时, ‘id 不再是泛型参数 而变成一个具体的life . 后者 调用时, 闭包 仍然是 泛型函数, 'newid 仍然是泛型参数。在补充 返回值的 life 参数时,不考虑:型变不变性,使得返回值拥有和参数同样的life吗? 是在借用检查阶段才考虑 不变性约束吗? 然后 rustc 为什么报错,类型推断后,借用检查应该已经知道 不变性约束 ,参数和返回值 的 life 一样,为什么 还报错: '1 must outlive '2

省略的 lifetime 的补充是 和 类型推断 一起进行的吗。

rust 怎么表示具体的life,除了 <'static> 。

--
👇
hangj: 「假如」写成「加入」了

--
👇
加入没有 'new_id 会怎样?

作者 leolee0101 2023-10-24 20:20

感谢感谢,哎呀,在理解的时候,忽略了 new 会返回闭包的返回值。
关注点都在 life 的型变和约束,还有 HRTB 上了。

--
👇
hangj: 「假如」写成「加入」了

--
👇
加入没有 'new_id 会怎样?

hangj 2023-10-24 14:32

「假如」写成「加入」了

--
👇
加入没有 'new_id 会怎样?

hangj 2023-10-24 14:30

加入没有 'new_id 会怎样?

直接看代码:

impl<'id> GhostToken<'id> {
    pub fn new<F, R>(f: F) -> R
    where
        F: FnOnce(GhostToken<'id>) -> R,
    {
        let token = GhostToken {
            // InvariantLifetime::new() 等价于 InvariantLifetime::<'id>::new()
            // 这个 'id 的生存范围是 new 函数的调用者的区域内, 所以 f 函数可以把 token 返回出去, 导致 token 泄漏
            _marker: InvariantLifetime::new(),
        };
        f(token)
    }
}

fn main() {
    // 看,露出来了吧!
    let token = GhostToken::new(|token|token);
}

playground

作者 leolee0101 2023-10-24 06:22

不知道问题描述的是否清楚。

请路过的 同学,前辈,不吝指教。不管是否有瑕疵,尽管畅所欲言。@everyone ,@苦瓜小仔 。

1 共 5 条评论, 1 页