2016-10-02 1 views
3

У меня есть не-общая структура, которая реализует общий признак. Когда я вызываю функцию на структуры, я получаю следующее сообщение об ошибке:Вызов реализации конкретного признака на не-генерической структуре

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 

Я попытался добавить аннотацию типа и общие привязки параметров, но я явно делаю что-то неправильно; Я до сих пор не могу его скомпилировать. У меня есть аналогичный код в другом месте с общей структурой, которая работает, по-видимому, потому, что общие границы, разделяемые структурой и признаком trait, позволяют компилятору вывести реальную реализацию метода для вызова.

Лучший способ проиллюстрировать этот вопрос является с уменьшенным, например:

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 `_` 
} 

Пожалуйста, простите за плохое название, но это лучший способ я знаю, как описать проблему.

ответ

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 к 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 {} 
    
  3. Вы можете добавить PhantomData члена NoOpDebugger и сделать NoOpDebugger сам родовое, так что каждый NoOpDebugger<M> реализует только Debugger<M> для того же M. В вашем примере, M для 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(); 
    } 
    
  4. Если реализации Debugger не зависят от M, и если вы не используете Debugger в качестве объекта признака, то вы можете переместить параметр типа для методов, которые нуждаются в ней и опустить его на методы, которые ему не нужны.

    trait Debugger { 
        fn attach(&mut self) {} 
        fn step<M: Memory>(mem: &M) {} 
    } 
    
Смежные вопросы