为什么这会变成堆栈溢出?

Why does this turn into a stack overflow?

因堆栈溢出而失败的简单测试用例:

// trait to say FnMut has a clone_box method
pub trait ClonableFnMut<A>: FnMut(A) {
    fn clone_box(&self) -> Box<dyn ClonableFnMut<A> + Send + 'static>;
}

// overridden .clone() for Box<ClonableFnMut> that calls .clone_box on f
impl<A: 'static> Clone for Box<dyn ClonableFnMut<A> + Send + 'static> {
    fn clone(&self) -> Self {
        self.clone_box()
    }
}

// .clone_box() on FnMut clones itself and wraps itself in a new Box
impl<A, F: FnMut(A) + Clone + Send + 'static> ClonableFnMut<A> for F {
    fn clone_box(&self) -> Box<dyn ClonableFnMut<A> + Send + 'static> {
        Box::new(self.clone())
    }
}

fn main() {
    let mut f: Box<dyn ClonableFnMut<u8> + Send + 'static> = Box::new(|_x|{});

    println!("{:?}", f(3));
    println!("{:?}", f.clone()(4));
}

理论上:

  1. Box<ClonableFnMut> 上致电 .clone()
  2. 自定义实现在内部 FnMut 上调用 .clone_box()
  3. 内部 FnMut 现在可以调用 .clone() 自身,因为它被标记为克隆。
  4. .clone_box() returns 这克隆了 FnMut (自己)在一个新的 Box

但实际上:

  1. Box<ClonableFnMut> 上手动调用 .clone()
  2. 在内部 Box<FnMut> 调用 .clone_box()
  3. 调用 self.clone(),这似乎意味着 self = box
  4. 自定义 Box<FnMut> clone() 再次调用,从第 1 步开始。

发生第 4 步的真正原因是什么?

实际发生的事情略有不同:

  1. 有人在 Box 打电话给 clone...
  2. ...在 上调用 clone_box 相同的 Box...
  3. ...再次在 上调用 clone 相同的 Box,关闭循环。

发生这种情况是因为 Clone 的实现只调用了 self.clone_box(),但 clone_boxClonableFnMut 特征的一个方法。由于一揽子实施,此特征特别在 Box<dyn ClonableFnMut<A> + Send + 'static> 上实施,Box 本身满足 F: FnMut(A) + Clone + Send + 'static 的要求。

为避免这种情况,您需要强制 Clone 实现为 Box 的内容而不是 Box 本身调用 clone_box 方法。有两种风格略有不同的明显方式:

  1. Replace self.clone_box()self.deref().clone_box() 并在某处添加所需的导入 use std::ops::Deref;

  2. 或者,replace self.clone_box()(**self).clone_box(),不需要额外导入,但看起来有点神秘。请注意,clone 的参数 &self 基本上是 self: &Self 的语法糖,因此第一个 * 将其从 &Box<F> 取消引用到 Box<F>,第二个再次将其取消引用为 F。调用 clone_box 然后自动引用它到 &F 因为它也需要 &self