什么时候静态生命周期不合适?
When is a static lifetime not appropriate?
我在网上找到了很多关于 Rust 生命周期的信息,包括关于静态生命周期的信息。对我来说,在某些情况下,您必须保证引用将比一切都长。
例如,我有一个要传递给线程的引用,编译器要求将该引用标记为静态。在这种情况下,这似乎是有道理的,因为编译器无法知道线程将存活多长时间,因此需要确保传递的引用比线程存活得更久。 (我觉得这样对吗?)
我不知道这是从哪里来的,但我一直担心用静态生命周期标记某些东西是值得怀疑的,并尽可能避免。
所以我想知道这是否正确。我应该批评标记具有静态生命周期的东西吗?是否存在编译器需要一个但替代策略实际上可能更优化的情况?
有哪些具体方法可以让我推断静态生命周期的应用,并可能确定它何时不合适?
正如您可能已经猜到的那样,对此没有明确的技术答案。
作为 Rust 的新手,'static
引用似乎违背了借用系统的全部目的,并且有一种避免它们的想法。一旦你更有经验,这个想法就会消失。
首先,'static
并不像看起来那么糟糕,因为所有没有其他生命周期与之关联的事物都是 'static
,例如String::new()
。请注意 'static
确实 而不是 意味着所讨论的值确实永远存在。它只是意味着价值可以永生。在您的线程示例中,线程不能对自己的生命周期作出任何承诺,因此它需要能够使 传递给它的所有东西永远存在。任何不包括短于 'static
(如 vec![1,2,3]
) 生命周期的拥有价值都可以 永生(只要不破坏它们),因此 'static
.
其次,&'static
- 静态引用 - 并不经常出现。如果是这样,您通常会知道原因。你不会看到很多 fn foo(bar: &'static Bar)
因为它的用例并不多,而不是因为它被主动避免了。
有些情况下 'static
确实会以令人惊讶的方式出现。出乎我的意料:
- 一个
Box<dyn Trait>
是implicitly一个Box<dyn Trait + 'static>
。这是因为当 Box
中的值类型被删除时,它可能有与之相关的生命周期;只要 Box
存在,所有(不同的)类型都必须有效。因此,所有类型都需要在其生命周期内共享一个共同点,而 Rust 被定义为选择 'static
。这种选择通常没问题,但会导致令人惊讶的“需要‘静态’”错误。您可以将其明确概括为 Box<dyn Trait + 'a>
- 如果您的类型有自定义
impl Drop
,Drop-checker may 无法证明析构函数无法观察已被丢弃的值。为了防止 Drop
impl 访问对已经被删除的值的引用,编译器要求整个类型内部只有 'static
引用。这可以通过不安全的实现来克服,它提升了 'static
-requirement.
将 Arc<T>
传递给线程,而不是 &'static T
。这只有很小的成本,并确保使用寿命不会超过必要的时间。
我在网上找到了很多关于 Rust 生命周期的信息,包括关于静态生命周期的信息。对我来说,在某些情况下,您必须保证引用将比一切都长。
例如,我有一个要传递给线程的引用,编译器要求将该引用标记为静态。在这种情况下,这似乎是有道理的,因为编译器无法知道线程将存活多长时间,因此需要确保传递的引用比线程存活得更久。 (我觉得这样对吗?)
我不知道这是从哪里来的,但我一直担心用静态生命周期标记某些东西是值得怀疑的,并尽可能避免。
所以我想知道这是否正确。我应该批评标记具有静态生命周期的东西吗?是否存在编译器需要一个但替代策略实际上可能更优化的情况?
有哪些具体方法可以让我推断静态生命周期的应用,并可能确定它何时不合适?
正如您可能已经猜到的那样,对此没有明确的技术答案。
作为 Rust 的新手,'static
引用似乎违背了借用系统的全部目的,并且有一种避免它们的想法。一旦你更有经验,这个想法就会消失。
首先,'static
并不像看起来那么糟糕,因为所有没有其他生命周期与之关联的事物都是 'static
,例如String::new()
。请注意 'static
确实 而不是 意味着所讨论的值确实永远存在。它只是意味着价值可以永生。在您的线程示例中,线程不能对自己的生命周期作出任何承诺,因此它需要能够使 传递给它的所有东西永远存在。任何不包括短于 'static
(如 vec![1,2,3]
) 生命周期的拥有价值都可以 永生(只要不破坏它们),因此 'static
.
其次,&'static
- 静态引用 - 并不经常出现。如果是这样,您通常会知道原因。你不会看到很多 fn foo(bar: &'static Bar)
因为它的用例并不多,而不是因为它被主动避免了。
有些情况下 'static
确实会以令人惊讶的方式出现。出乎我的意料:
- 一个
Box<dyn Trait>
是implicitly一个Box<dyn Trait + 'static>
。这是因为当Box
中的值类型被删除时,它可能有与之相关的生命周期;只要Box
存在,所有(不同的)类型都必须有效。因此,所有类型都需要在其生命周期内共享一个共同点,而 Rust 被定义为选择'static
。这种选择通常没问题,但会导致令人惊讶的“需要‘静态’”错误。您可以将其明确概括为Box<dyn Trait + 'a>
- 如果您的类型有自定义
impl Drop
,Drop-checker may 无法证明析构函数无法观察已被丢弃的值。为了防止Drop
impl 访问对已经被删除的值的引用,编译器要求整个类型内部只有'static
引用。这可以通过不安全的实现来克服,它提升了'static
-requirement.
将 Arc<T>
传递给线程,而不是 &'static T
。这只有很小的成本,并确保使用寿命不会超过必要的时间。