Box<Fn() + Send + 'static>
在 Rust 中是什么意思?
在我阅读高级类型章节时偶然发现了这个语法。 Send
是一个 trait,但是将生命周期(在这种情况下为'static
)与 trait(Send
)相加意味着什么?另外,Fn()
是什么意思?
Box<Fn() + Send + 'static>
在 Rust 中是什么意思?
在我阅读高级类型章节时偶然发现了这个语法。 Send
是一个 trait,但是将生命周期(在这种情况下为'static
)与 trait(Send
)相加意味着什么?另外,Fn()
是什么意思?
让我们逐个分解它。
Box<T>
是指向堆上分配的T
的指针。我们在这里使用它,因为特质对象只能存在于指针后面。
在Box<Fn() + Send + 'static>
中,Fn() + Send + 'static
是一种trait object类型。将来,它将被写成 Box<dyn (Fn() + Send + 'static)>
以避免混淆。
dyn
内部限制了原始类型。只有当T: Fn() + Send + 'static
时,Box<T>
才可以强制转换为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
表示该类型的值可以在线程间发送。由于这是一个自动特质, 它可以作为dyn类型(trait object types)的第二个限制条件 (trait object types).
'static
限定实际上,dyn
类型(trait object types)必须有一个生命周期限定。当省略时会被推断。推断规则在RFC 0192 和 RFC 1156中描述。基本规则如下:
Box<Any>
是 Box<Any + 'static>
,因为 Any: 'static
。&'a Fn()
是 &'a (Fn() + 'a)
。'static
(对于函数签名)或匿名生命周期(对于函数体)。f: Box<Fn() + Send + 'static>
是一个拥有指向可调用值(原始类型未知且可动态更改),例如没有参数或没有返回值的闭包的所有权指针,可以跨线程发送并在程序本身存在期间保持活动状态。
我发现最受欢迎的答案中,'static
部分需要更详细的解释。
将底层具体类型称为A
。
特质对象Box<dyn Fn() + Send + 'static>
可以由A
的实例构建,这意味着A:Fn() + Send + 'static
。也就是说,具体类型A
受到'static
寿命的限制。
trait bound中对'static
的解释:
作为一个特质边界,它意味着该类型不包含任何非静态引用。例如,接收方可以持有该类型,直到他们放弃它为止,它永远不会失效。
重要的是要明白,这意味着任何拥有的数据始终通过
'static
生命周期绑定传递,但对该拥有数据的引用通常不会这样做。
对于使用任何生命周期作为特质边界的情况,有一个生成式的解释:
T:'a表示T的所有生命周期参数必须比'a'更长。例如,如果'a'是无约束的生命周期参数,那么i32:'static和&'static str:'a就是满足的,但Vec<&'a ()>: 'static则不是。
对于我们的情况,A
的所有生命周期参数都必须比'static
更长,例如
pub struct A<'a> {
buf: &'a[u8]
}
无法满足 A: 'static
要求。
Box<&i32>
是否意味着它将在堆
中分配指针/引用,并且借用的内容(i32)
(它指向的数据)可能在堆栈上,而*b
将给我&i32
,**b
将给我100(假设let m = 100; let b:Box<&i32> = Box::new(&m);
);不考虑println!
这里的autorefs
。 - soupybionics