代码之家  ›  专栏  ›  技术社区  ›  Taz

覆盖第三方库中的Drop特性

  •  0
  • Taz  · 技术社区  · 2 年前

    我正在使用普罗米修斯直方图计时器。
    此结构实现Drop trait

    impl Drop for HistogramTimer {
        fn drop(&mut self) {
            if !self.observed {
                self.observe(true);
            }
        }
    }
    

    我需要用noop实现来覆盖它。
    我试过了:

    struct CustomHistogramTimer(HistogramTimer);
    
    impl CustomHistogramTimer{
        pub fn stop_and_record(self) -> f64 {
            self.0.stop_and_record()
        }
    
        pub fn stop_and_discard(self) -> f64 {
            self.0.stop_and_discard()
        }
    }
    
    impl Drop for CustomHistogramTimer {
        fn drop(&mut self) {
            
        }
    }
    

    但这不起作用,因为我得到:

    无法移出类型 CustomHistogramTimer ,它实现 Drop 特质
    发生移动是因为 self.0 具有类型 HistogramTimer ,它不实现 Copy 特质

    我不知道如何解决这个问题。

    1 回复  |  直到 2 年前
        1
  •  0
  •   cdhowie    2 年前

    最简单的解决方案可能是使用 ManuallyDrop 并且简单地从不降低值。

    struct CustomHistogramTimer(ManuallyDrop<HistogramTimer>);
    

    然后你可以删除你的 Drop 实施删除此类型时,包含 HistogramTimer 将被遗忘(丢弃而不丢弃)。

    但是,请注意 直方图计时器 包含 Histogram ,依次包含 Arc 到直方图的内部状态。 这意味着不丢弃 直方图计时器 将导致直方图的状态永远不会被释放,因为 的引用计数永远不会变为零。

    然而,似乎有一个解决方案。的文档 HistogramTimer::stop_and_discard 说(强调我的):

    观察并返回计时器持续时间(秒)。

    它返回自计时器启动以来经过的浮点秒数, 而不记录到任何直方图。

    好的,很好,但这是一种消耗性的方法。我们不能在 &mut HistogramTimer ,这是我们在drop代码中所能得到的全部内容。

    值得庆幸的是,这与 手动下降 方法事实上,这种特殊情况是的主要用途之一 手动下降 。我们必须使用不安全的代码来调用 ManuallyDrop::take ,这给了我们内在的所有权 T 。只要我们从不使用 手动下降 再说一遍,由于我们将在drop代码中执行此操作,因此很容易确保。

    impl Drop for CustomHistogramTimer {
        fn drop(&mut self) {
            // SAFETY: The ManuallyDrop is being dropped and won't be used again.
            let timer = unsafe { ManuallyDrop::take(&mut self.0) };
    
            timer.stop_and_discard();
        }
    }
    

    如果您喜欢不使用不安全代码的方法,可以使用 Option 。虽然我们可以很容易地证明代码永远不会死机,但编译器不能,因此任何使用内部 直方图计时器 将有一个 None 检查已发出。

    struct CustomHistogramTimer(Option<HistogramTimer>);
    
    impl Drop for CustomHistogramTimer {
        fn drop(&mut self) {
            self.0.take().unwrap().stop_and_discard();
        }
    }
    
    impl CustomHistogramTimer {
        pub fn stop_and_record(self) -> f64 {
            self.0.unwrap().stop_and_record()
        }
    
        pub fn stop_and_discard(self) -> f64 {
            self.0.unwrap().stop_and_discard()
        }
    }
    
    推荐文章