#rust #traits
#Ржавчина #Трейты
Вопрос:
У меня есть неродовая структура, которая реализует общую черту. Когда я вызываю функцию в структуре, я получаю следующую ошибку:
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(amp;mut self) {}
fn step(mem: amp;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(amp;mut cpu.debugger); }
или
fn main() { let mut cpu = Cpu::new(SimpleMemory, NoOpDebugger); <NoOpDebugger as Debugger<SimpleMemory>>::attach(amp;mut cpu.debugger); }
-
Вы можете переместить
attach
метод в супер-признак, который не является универсальным.trait DebuggerBase { fn attach(amp;mut self) {} } trait Debugger<M: Memory>: DebuggerBase { fn step(mem: amp;M) {} } impl DebuggerBase for NoOpDebugger {} impl<M: Memory> Debugger<M> for NoOpDebugger {}
-
Вы можете добавить
PhantomData
элементNoOpDebugger
и сделатьNoOpDebugger
его универсальным, чтобы каждыйNoOpDebugger<M>
реализовывал толькоDebugger<M>
для одного и того жеM
. В вашем примереM
forNoOpDebugger
будет выведен из вызова toCpu::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(); }
-
Если реализации
Debugger
не зависят отM
, и если вы не используетеDebugger
в качестве объекта признака, то вы можете переместить параметр типа в методы, которые в нем нуждаются, и опустить его в методах, которые в нем не нуждаются.trait Debugger { fn attach(amp;mut self) {} fn step<M: Memory>(mem: amp;M) {} }