“Box<Fn() + Send + 'static>” 在 rust 中是啥意思?

Posted

技术标签:

【中文标题】“Box<Fn() + Send + \'static>” 在 rust 中是啥意思?【英文标题】: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()是什么?

【问题讨论】:

【参考方案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 bounds 的dyn 类型(特征对象类型)。

'static绑定

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

    如果明确给出,则使用该生命周期。 否则,从内在特征推断。例如,Box&lt;Any&gt;Box&lt;Any + 'static&gt;,因为 Any: 'static。 如果特征没有适当的生命周期,则从外部类型推断。例如,&amp;'a Fn()&amp;'a (Fn() + 'a)。 如果失败,它会退回到'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,是的,这更像是一个假设性问题。

以上是关于“Box<Fn() + Send + 'static>” 在 rust 中是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章