Reputation: 17367
I have a non-generic struct that implements a generic trait. When I call a function on the struct, I get the following error:
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
I've tried adding type annotations and generic parameter bindings, but I'm obviously doing something wrong; I still can't get it to compile. I have similar code elsewhere with a generic struct that works, presumably because the generic-bounds shared by the struct and trait impl allow the compiler to infer the actual method implementation to call.
The best way to illustrate the issue is with a reduced example:
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 `_`
}
Please excuse the poor title, but it's the best way I know how to describe the problem.
Upvotes: 6
Views: 1788
Reputation: 65657
You have several options.
You can specify on which specific trait you want to invoke the attach
method.
fn main() {
let mut cpu = Cpu::new(SimpleMemory, NoOpDebugger);
Debugger::<SimpleMemory>::attach(&mut cpu.debugger);
}
or
fn main() {
let mut cpu = Cpu::new(SimpleMemory, NoOpDebugger);
<NoOpDebugger as Debugger<SimpleMemory>>::attach(&mut cpu.debugger);
}
You can move the attach
method to a supertrait that is not generic.
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 {}
You can add a PhantomData
member to NoOpDebugger
and make NoOpDebugger
itself generic, so that each NoOpDebugger<M>
only implements Debugger<M>
for the same M
. In your example, the M
for NoOpDebugger
will be inferred from the call to 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();
}
If the implementations of Debugger
don't depend on M
, and if you don't use Debugger
as a trait object, then you can move the type parameter to the methods that need it and omit it on the methods that don't need it.
trait Debugger {
fn attach(&mut self) {}
fn step<M: Memory>(mem: &M) {}
}
Upvotes: 8