在非泛型结构上调用特定的trait实现

w.b*_*ian 3 traits rust

我有一个实现通用特征的非泛型结构.当我在struct上调用一个函数时,我收到以下错误:

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
Run Code Online (Sandbox Code Playgroud)

我已经尝试添加类型注释和泛型参数绑定,但我显然做错了什么; 我仍然无法编译.我在其他地方有一个类似的代码,它有一个通用的结构,可能是因为struct和trait impl共享的泛型边界允许编译器推断要调用的实际方法实现.

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

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 `_`
}
Run Code Online (Sandbox Code Playgroud)

请原谅可怜的头衔,但这是我知道如何描述问题的最佳方式.

Fra*_*gné 6

你有几个选择.

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

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

    要么

    fn main() {
        let mut cpu = Cpu::new(SimpleMemory, NoOpDebugger);
        <NoOpDebugger as Debugger<SimpleMemory>>::attach(&mut cpu.debugger);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您可以将attach方法移动到非通用的supertrait.

    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 {}
    
    Run Code Online (Sandbox Code Playgroud)
  3. 您可以添加PhantomData成员NoOpDebugger并使其NoOpDebugger自身具有通用性,以便每个成员NoOpDebugger<M>只实现Debugger<M>相同的成员M.在您的示例中,Mfor NoOpDebugger将从调用推断出来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();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 如果实现Debugger不依赖于M,并且如果不使用Debugger作为特征对象,则可以将type参数移动到需要它的方法,并在不需要它的方法上省略它.

    trait Debugger {
        fn attach(&mut self) {}
        fn step<M: Memory>(mem: &M) {}
    }
    
    Run Code Online (Sandbox Code Playgroud)