“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<Fn() + Send + 'static>
在 rust 中是什么意思?
我在阅读高级类型章节时偶然发现了这种语法。 Send
是一个特征,但是在类型参数化中,+
一生对特征(在这种情况下为 'static
)意味着什么?还有Fn()
是什么?
【问题讨论】:
【参考方案1】:我发现'static
部分需要来自the top-voted answer 的更多详细说明。
将基础混凝土类型表示为A
。
特征对象Box<dyn Fn() + Send + 'static>
可以从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<T>
是指向堆分配的T
的指针。我们在这里使用它是因为 trait 对象只能存在于指针之后。
特征对象
在Box<Fn() + Send + 'static>
中,Fn() + Send + 'static
是trait object 类型。以后会改成written Box<dyn (Fn() + Send + 'static)>
,以免混淆。
dyn
内部是对原始类型的限制。 Box<T>
只能在T: Fn() + Send + 'static
时强制转换为Box<Fn() + Send + 'static>
。因此,虽然我们不知道原始类型,但我们可以假设它是 Fn()
和 Send
并且拥有 'static
生命周期。
Fn()
这是一个特征,就像Clone
或Default
。但是,它使用了一个特殊的语法糖。
Fn(A1, ..., An)
是 Fn<(A1, ..., An), Output=()>
的语法糖。
Fn(A1, ..., An) -> R
是 Fn<(A1, ..., An), Output=R>
的语法糖。
此语法糖也适用于以下特征:Fn
、FnMut
、FnOnce
和 FnBox
。
那么Fn
是什么意思? T: Fn(A1, ..., An) -> R
表示x: T
是一个可调用对象,带有参数A1, ..., An
和返回类型R
。示例包括函数指针和闭包。
发送
Send
表示这种类型的值可以跨线程发送。由于这是一个auto trait,它是can be specified as the second bounds 的dyn
类型(特征对象类型)。
'static
绑定
事实上,dyn
类型(特征对象类型)必须有一个生命周期限制。省略时推断。推理规则在RFC 0192 和RFC 1156 中描述。基本上是这样的:
-
如果明确给出,则使用该生命周期。
否则,从内在特征推断。例如,
Box<Any>
是 Box<Any + 'static>
,因为 Any: 'static
。
如果特征没有适当的生命周期,则从外部类型推断。例如,&'a Fn()
是 &'a (Fn() + 'a)
。
如果失败,它会退回到'static
(对于函数签名)或匿名生命周期(对于函数体)。
结论
f: Box<Fn() + Send + 'static>
是一个拥有的指针,指向一个可调用值(原始类型未知并且动态变化),例如闭包(没有参数或没有返回值),它可以跨线程发送,只要程序存在自己。
【讨论】:
非常感谢正树的详细解释!一个离题的问题:Box<&i32>
是否意味着它将在heap
中分配指针/引用,并且borrowed content (i32)
(它指向的数据)很可能在堆栈上?并且*b
将给我&i32
和**b
将给100(鉴于let m = 100; let b:Box<&i32> = Box::new(&m);
);此处不考虑println!
autorefs
@soupybionics 我知道你现在可能不在乎,哈哈,但我相信。当然,没有太多理由对堆栈分配值的引用进行装箱,而且您无法对框做太多事情,因为在 i32 被删除或移动后它将无效。
@HutchMoore,是的,这更像是一个假设性问题。以上是关于“Box<Fn() + Send + 'static>” 在 rust 中是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章