在 non-generic 结构上调用特定特征实现

Calling specific trait implementation on a non-generic struct

我有一个实现通用特征的 non-generic 结构。当我在结构上调用函数时,出现以下错误:

error[E0282]: unable to infer enough type information about `_`
  --> src/main.rs:35:18
   |
35 |     cpu.debugger.attach();
   |                  ^^^^^^ cannot infer type for `_`
   |
   = note: type annotations or generic parameter binding required

我试过添加类型注释和泛型参数绑定,但显然我做错了什么;我仍然无法编译它。我在其他地方有类似的代码,其中有一个通用结构可以工作,大概是因为结构和特征实现共享的 generic-bounds 允许编译器推断要调用的实际方法实现。

说明问题的最佳方式是使用简化示例:

struct Cpu<M: Memory, D: Debugger<M>> {
    mem: M,
    debugger: D,
}

impl<M: Memory, D: Debugger<M>> Cpu<M, D> {
    fn new(mem: M, debugger: D) -> Self {
        Cpu {
            mem: mem,
            debugger: debugger,
        }
    }
}

trait Memory {}

struct SimpleMemory;

impl Memory for SimpleMemory {}

trait Debugger<M: Memory> {
    fn attach(&mut self) {}
    fn step(mem: &M) {}
}

struct NoOpDebugger;

impl<M: Memory> Debugger<M> for NoOpDebugger {}

fn main() {
    let mut cpu = Cpu::new(SimpleMemory, NoOpDebugger);
    cpu.debugger.attach(); // <-- cannot infer type for `_`
}

请原谅糟糕的标题,但这是我所知道的描述问题的最佳方式。

您有多种选择。

  1. 您可以指定要调用 attach 方法的特定特征。

    fn main() {
        let mut cpu = Cpu::new(SimpleMemory, NoOpDebugger);
        Debugger::<SimpleMemory>::attach(&mut cpu.debugger);
    }
    

    fn main() {
        let mut cpu = Cpu::new(SimpleMemory, NoOpDebugger);
        <NoOpDebugger as Debugger<SimpleMemory>>::attach(&mut cpu.debugger);
    }
    
  2. 您可以将 attach 方法移动到非泛型的超特征。

    trait DebuggerBase {
        fn attach(&mut self) {}
    }
    
    trait Debugger<M: Memory>: DebuggerBase {
        fn step(mem: &M) {}
    }
    
    impl DebuggerBase for NoOpDebugger {}
    impl<M: Memory> Debugger<M> for NoOpDebugger {}
    
  3. 你可以在NoOpDebugger中添加一个PhantomData成员并使NoOpDebugger本身成为通用的,这样每个NoOpDebugger<M>只实现Debugger<M> 同样 M。在您的示例中,NoOpDebuggerM 将从对 Cpu::new.

    的调用中推断出来
    use std::marker::PhantomData;
    
    struct NoOpDebugger<M>(PhantomData<M>);
    
    impl<M: Memory> Debugger<M> for NoOpDebugger<M> {}
    
    fn main() {
        let mut cpu = Cpu::new(SimpleMemory, NoOpDebugger(PhantomData));
        cpu.debugger.attach();
    }
    
  4. 如果 Debugger 的实现不依赖于 M,并且如果你不使用 Debugger 作为特征对象,那么你可以将类型参数移动到需要它的方法,并在不需要它的方法上省略它。

    trait Debugger {
        fn attach(&mut self) {}
        fn step<M: Memory>(mem: &M) {}
    }