【发布时间】:2018-06-09 13:56:27
【问题描述】:
Box<Fn() + Send + 'static> 在 rust 中是什么意思?
我在阅读高级类型章节时偶然发现了这种语法。 Send 是一个特征,但是在类型参数化中,+ 一生对特征(在这种情况下为 'static)意味着什么?还有Fn()是什么?
【问题讨论】:
标签: types rust traits lifetime lifetime-scoping
Box<Fn() + Send + 'static> 在 rust 中是什么意思?
我在阅读高级类型章节时偶然发现了这种语法。 Send 是一个特征,但是在类型参数化中,+ 一生对特征(在这种情况下为 'static)意味着什么?还有Fn()是什么?
【问题讨论】:
标签: types rust traits lifetime lifetime-scoping
我发现'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 的要求。
【讨论】:
leak 堆内存。完全控制底层内存生命周期是一件好事。如果你决定过度使用它,你需要承担后果。我认为这是公平的。
让我们一一分解。
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