#workaround #polonius #stable #borrow #reference #replace #return

polonius_workaround

稳定 Rust 中 Polonius 的安全替代方案

1 个不稳定版本

使用旧的 Rust 2015

0.1.0 2022年2月8日

#6 in #workaround

MIT 许可证

12KB

Polonius_workaround

Crate docs

此包提供了简单且逻辑安全的 API,用于解决 Polonius 将解决的借用检查器限制的不安全解决方案。

许可证

MIT


lib.rs:

此包提供了 API 来解决由当前 Rust 借用检查限制引起的借用检查错误。存在下一个版本的 Rust 借用检查器,称为 Polonius,它应该消除此类限制,但它始终不稳定,没有当前的稳定计划。而且,在稳定 Rust 中,通常只能通过使用不安全代码来绕过这些限制,这可能导致某些形式的回归。但是,对于这样简单的事情,被要求使用不安全代码是令人烦恼的,而且很容易出错,更不用说它只是一个延迟的炸弹,等待着某些粗心的重构来释放它。

所有功能都通过 PoloniusExt 扩展 trait 提供。它有 3 个方法

  • try_get_with/try_get_mut_with 适用于需要返回共享/可变引用的简单情况。它应该正常工作,在大多数情况下就足够了。但有时你需要返回的不是引用,而是包含引用的另一种类型。这时你需要
  • try_get_with2 它允许你返回任何包含引用的类型,但由于 Rust 类型推断中的 HRTB 故障,它的使用有点令人烦恼。有关更多详细信息,请参阅其文档。

据作者所知,它可以解决任何类型的借用检查器问题,这些问题将由 Polonius 解决。尽管你仍然需要足够自信,知道你的代码实际上是正确的,只是没有被当前的借用检查器接受。因此,尽管使用此包你不再需要 Polonius,但它仍然是一般上很好的东西。

代码从 Rust 1.0 开始编译,但 try_get_with2 实际上只能在 Rust 1.41 及以上版本中使用。

以下是一个实际示例,没有显著的性能回归或不安全代码,你无法解决这个问题。

trait LinkedListExt<T> {
    fn find_or_create<F, C>(&mut self, predicate: F, create: C) -> &mut T
    where
        F: FnMut(&T) -> bool,
        C: FnMut() -> T;
}

impl<T: 'static> LinkedListExt<T> for LinkedList<T> {
    fn find_or_create<F, C>(&mut self, mut predicate: F, mut create: C) -> &mut T
    where
        F: FnMut(&T) -> bool,
        C: FnMut() -> T,
    {
        if let Some(x) = self.iter_mut().find(|e| predicate(&*e)){
            return x;
        }
        self.push_back(create());
        self.back_mut().unwrap()
    }
}

现在,使用此包,你只需将两个分支包裹在闭包中,然后调用 try_get_mut_with,然后就可以了

impl<T: 'static> LinkedListExt<T> for LinkedList<T> {
    fn find_or_create<F, C>(&mut self, mut predicate: F, mut create: C) -> &mut T
    where
        F: FnMut(&T) -> bool,
        C: FnMut() -> T,
    {
        self.try_get_mut_with(|x| x.iter_mut().find(|e| predicate(&*e)))
            .unwrap_or_else(|x| {
                x.push_back(create());
                x.back_mut().unwrap()
            })
    }
}

无运行时依赖