【问题标题】:What does "Box<Fn() + Send + 'static>" mean in rust?“Box<Fn() + Send + 'static>” 在 rust 中是什么意思?
【发布时间】:2018-06-09 13:56:27
【问题描述】:

Box&lt;Fn() + Send + 'static&gt; 在 rust 中是什么意思?

我在阅读高级类型章节时偶然发现了这种语法。 Send 是一个特征,但是在类型参数化中,+ 一生对特征(在这种情况下为 'static)意味着什么?还有Fn()是什么?

【问题讨论】:

    标签: types rust traits lifetime lifetime-scoping


    【解决方案1】:

    我发现'static 部分需要来自the top-voted answer 的更多详细说明。

    基础混凝土类型表示为A

    特征对象Box&lt;dyn Fn() + Send + 'static&gt; 可以从A 的实例构造,这意味着A: Fn() + Send + 'static。也就是说,具体类型A 的边界是static 生命周期。

    'static 的特定explanation 作为特征绑定:

    作为一个 trait bound,这意味着该类型不包含任何非静态引用。例如。接收者可以随心所欲地保留该类型,并且在他们丢弃它之前它永远不会变得无效。

    重要的是要理解这意味着任何拥有的数据总是通过 'static 生命周期界限,但对该拥有数据的引用通常不会

    generative explanation 用于将任何生命周期用作特征绑定的情况:

    T: 'a 表示T 的所有生命周期参数都比'a 寿命更长。例如,如果 'a 是一个不受约束的生命周期参数,则 i32: 'static 和 &'static str: 'a 满足但 Vec: 'static 不满足。

    对于我们的例子,A 的所有生命周期参数必须比 'static 寿命长,例如

    pub struct A<'a> {
       buf: &'a[u8]
    }
    

    无法满足A: 'static 的要求。

    【讨论】:

    • 那么'静态生命周期是一件坏事吗?如果我过度使用它是否意味着他们永远不会被释放?或者 rust 是否足够聪明,甚至可以在“静态生命周期”中释放不再使用的对象/引用?
    • @RafaelMerlin 一点也不差。如果它在引用上下文中,则意味着要过整个程序生命周期。您也可以使用 Box 有意地leak 堆内存。完全控制底层内存生命周期是一件好事。如果你决定过度使用它,你需要承担后果。我认为这是公平的。
    【解决方案2】:

    让我们一一分解。

    Box&lt;T&gt; 是指向堆分配的T 的指针。我们在这里使用它是因为 trait 对象只能存在于指针之后。

    特征对象

    Box&lt;Fn() + Send + 'static&gt; 中,Fn() + Send + 'statictrait object 类型。以后会改成written Box&lt;dyn (Fn() + Send + 'static)&gt;,以免混淆。

    dyn 内部是对原始类型的限制。 Box&lt;T&gt; 只能在T: Fn() + Send + 'static 时强制转换为Box&lt;Fn() + Send + 'static&gt;。因此,虽然我们不知道原始类型,但我们可以假设它是 Fn()Send 并且拥有 'static 生命周期

    Fn()

    这是一个特征,就像CloneDefault。但是,它使用了一个特殊的语法糖

    • Fn(A1, ..., An)Fn&lt;(A1, ..., An), Output=()&gt; 的语法糖。
    • Fn(A1, ..., An) -&gt; RFn&lt;(A1, ..., An), Output=R&gt; 的语法糖。
    • 此语法糖也适用于以下特征:FnFnMutFnOnceFnBox

    那么Fn 是什么意思? T: Fn(A1, ..., An) -&gt; R 表示x: T 是一个可调用对象,带有参数A1, ..., An 和返回类型R。示例包括函数指针和闭包。

    发送

    Send 表示这种类型的值可以跨线程发送。由于这是一个auto trait,它是can be specified as the second boundsdyn 类型(特征对象类型)。

    'static绑定

    事实上,dyn 类型(特征对象类型)必须有一个生命周期限制。省略时推断。推理规则在RFC 0192RFC 1156 中描述。基本上是这样的:

    1. 如果明确给出,则使用该生命周期。
    2. 否则,从内在特征推断。例如,Box&lt;Any&gt;Box&lt;Any + 'static&gt;,因为 Any: 'static
    3. 如果特征没有适当的生命周期,则从外部类型推断。例如,&amp;'a Fn()&amp;'a (Fn() + 'a)
    4. 如果失败,它会退回到'static(对于函数签名)或匿名生命周期(对于函数体)。

    结论

    f: Box&lt;Fn() + Send + 'static&gt; 是一个拥有的指针,指向一个可调用值(原始类型未知并且动态变化),例如闭包(没有参数或没有返回值),它可以跨线程发送,只要程序存在自己。

    【讨论】:

    • 非常感谢正树的详细解释!一个离题的问题:Box&lt;&amp;i32&gt; 是否意味着它将在heap 中分配指针/引用,并且borrowed content (i32)(它指向的数据)很可能在堆栈上?并且*b 将给我&amp;i32**b 将给100(鉴于let m = 100; let b:Box&lt;&amp;i32&gt; = Box::new(&amp;m););此处不考虑println!autorefs
    • @soupybionics 我知道你现在可能不在乎,哈哈,但我相信。当然,没有太多理由对堆栈分配值的引用进行装箱,而且您无法对框做太多事情,因为在 i32 被删除或移动后它将无效。
    • @HutchMoore,是的,这更像是一个假设性问题。
    猜你喜欢
    • 1970-01-01
    • 2022-10-02
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    • 2020-06-20
    • 1970-01-01
    • 2022-07-22
    • 2016-06-23
    相关资源
    最近更新 更多