Rust 编译器请求在泛型类型上添加一些被忽视的特征边界的情况发生在右、左和中。没什么好喊的。
然而我碰巧试图弄清楚为什么有人建议我添加
'static
trait bound。由于该程序太复杂,我试图记下一些简洁的内容,以在小范围内对程序行为进行建模。尽管如此,我还是没能想出这样一个宠物程序,它需要将 'static
特征绑定到泛型上。
我可以说,有问题的大程序需要
'static
类型的特征界限,这些类型通过 tokio::sync::mpsc
/broadcast
通道发送,并且对于一些包裹在 Arc<T: Send + Sync + 'static>
. 中的泛型
但是我无法在小型程序中重现
'static
的需求。我想有人可能会给我提供这样一个例子,在Send + Sync
之上我也必须坚持使用'static
类型。
只要有静态上下文的东西使用你的通用参数,它就得到了生命周期的限制,这真的很简单
'static
:
fn needs_static<T: Send + 'static>(r: T) {
// requires `T: 'static` because it takes a `FnOnce() -> T + 'static`
std::thread::spawn(move || r);
}
fn doesnt_need_static<T: Send>(r: T) {
//doesn't require static because there is no such bound on s.spawn
std::thread::scope(|s| {
s.spawn(move || r);
});
}
换句话说,生命周期边界与特征边界的工作方式完全相同,编译器会在检测到需要它们时建议它们。
您几乎不需要在自己的函数中指定
'static
特征绑定,除非它允许值异常转义,例如像您提到的 mpsc
和 spawn
。在这些情况下,Rust 无法静态检查引用是否有效。在内部,这些通常将值放入泄漏的Box
(作为指针)或静态变量,这两者都需要'static
值才能可用和可靠。
在普通代码中,引用只能通过将其提供给函数参数或返回它来转义函数,这正是 rust 的借用规则所检查的内容。
在某些情况下,值似乎会转义函数但不需要
'static
,这将涉及借用检查器之外的一些检查以确保稳健性。这就是 std::thread::scope
的工作原理,您可以在此处看到 将短暂的生命周期转化为 'static
以绕过借用规则并在内部使用常规 std::thread::spawn
。这是因为与 std::thread::Scope
类型交互的唯一方法是通过 std::thread::scope
函数,它使用相同的借用规则来确保 Scope
不会逃脱。