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

时间:2016-10-02 01:09:56

标签: rust traits

我有一个实现通用特征的非泛型结构。当我在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

我尝试过添加类型注释和泛型参数绑定,但我显然做错了;我仍然无法编译。我在其他地方有类似的代码,它有一个通用的结构,可能是因为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 `_`
}

请原谅这个糟糕的头衔,但这是我知道如何描述问题的最佳方式。

1 个答案:

答案 0 :(得分:6)

您有几种选择。

  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. 您可以将PhantomData成员添加到NoOpDebugger,并使NoOpDebugger本身成为通用成员,这样每个NoOpDebugger<M>仅对Debugger<M>实施M M。在您的示例中,NoOpDebugger的{​​{1}}将从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) {}
    }