Как решить «ожидаемая структура, параметр найденного типа» при назначении?

#rust

#Ржавчина

Вопрос:

Только начал работать с Rust пару дней назад. Я сейчас переношу некоторый код на C , и этот вопрос, похоже, является обратным обычной сортировке «ожидаемая структура, полученный тип». Этот код включает в себя два класса: класс контейнера A и класс клиента B.

 use std::vec::Vec;

struct  A<T:FooTrait> {
    children: Vec<*mut T>
}

impl <T:FooTrait> A<T> {
    fn insert(amp;mut self, val: amp;mut T) -> Handle<T> {
        self.children.push(val);
        return Handle{owner: self};
    }
}
struct B {
    handle: Handle<B>
}

trait FooTrait {
    fn set_handle<T:FooTrait>(amp;mut self, h: Handle<T>);
}

impl FooTrait for B {
    fn set_handle<B:FooTrait>(amp;mut self, h: Handle<B>) {
        self.handle = h;  // <-- Here is the problem
    }
}

struct  Handle<T:FooTrait> {
    owner: *mut A<T>
}

impl <T:FooTrait> Default for Handle<T> {
    fn default()->Handle<T> {
        Handle {
            owner: std::ptr::null_mut()
        }
    }
}
fn main() {
    let mut foo =  A::<B> { children: Default::default() };
    let mut b = B{handle: Default::default()};
    b.handle = foo.insert(amp;mut b);
}
  

Получение ошибки:

 error[E0308]: mismatched types
  --> src/main.rs:23:23
   |
22 |     fn set_handle<B:FooTrait>(amp;mut self, h: Handle<B>) {
   |                   - this type parameter
23 |         self.handle = h;
   |                       ^ expected struct `B`, found type parameter `B`
   |
   = note: expected struct `Handle<B>` (struct `B`)
              found struct `Handle<B>` (type parameter `B`)
  

Ответ №1:

Упрощенная версия (игровая площадка):

 use std::marker::PhantomData;

struct B {
    handle: PhantomData<B>,
}

trait FooTrait {
    fn set_handle<T: FooTrait>(amp;mut self, h: PhantomData<T>);
}

impl FooTrait for B {
    fn set_handle<BType: FooTrait>(amp;mut self, h: PhantomData<BType>) {
        self.handle = h;
    }
}
  

Обратите внимание, что я изменил имя параметра типа в set_handle . Теперь ошибка более понятна:

 error[E0308]: mismatched types
  --> src/lib.rs:13:23
   |
12 |     fn set_handle<BType: FooTrait>(amp;mut self, h: PhantomData<BType>) {
   |                   ----- this type parameter
13 |         self.handle = h;
   |                       ^ expected struct `B`, found type parameter `BType`
   |
   = note: expected struct `std::marker::PhantomData<B>`
              found struct `std::marker::PhantomData<BType>`
  

В вашем случае ошибка по существу та же, поскольку общий параметр представляет собой новый тип, который затеняет глобальный struct B .

Теперь, что делать? Это зависит от того, что вы хотите получить.

  • Если struct B определение правильное и set_handle требуется обрабатывать только B s, просто удалите общий параметр из set_handle (игровая площадка):
 trait FooTrait {
    fn set_handle(amp;mut self, h: PhantomData<B>);
}

impl FooTrait for B {
    fn set_handle(amp;mut self, h: PhantomData<B>) {
        self.handle = h;
    }
}
  
  • Если struct B определение правильное, но set_handle должна быть возможность использовать разные типы обработчиков в зависимости от Self , используйте связанный тип (игровая площадка):
 trait FooTrait {
    type T: FooTrait;
    fn set_handle(amp;mut self, h: PhantomData<Self::T>);
}

impl FooTrait for B {
    type T = B;
    fn set_handle(amp;mut self, h: PhantomData<B>) {
        self.handle = h;
    }
}
  

Теперь блок реализации выберет, какой аргумент (обработчик, в вашем случае) он получит.

  • Если set_handle определение правильное, т. Е. Вызывающий может выбрать тип обработчика, то struct B оно также должно быть универсальным. Однако в этом случае вы, по сути, не можете использовать подход, основанный на признаках, поскольку признак также должен быть общим, и вы не сможете просто использовать его в любой общей привязке без предоставления параметров (которые тоже должны быть привязаны до бесконечности).

Комментарии:

1. Спасибо! В какой-то момент я был довольно близок к этому, но не хватало :FooTrait; в typeT:FooTrait; Это была недостающая часть головоломки.

Ответ №2:

Здесь есть два разных B . Оригинал, который B вы определили в struct B , и второй <B:FooTrait> параметр типа. Второе затеняет первое. Вот как это видит компилятор:

 impl FooTrait for B {
    fn set_handle<AnyFoo:FooTrait>(amp;mut self, h: Handle<AnyFoo>) {
        self.handle = h;  // <-- Here is the problem
    }
}
  

То, как вы определили вещи, FooTrait::set_handle должно работать с любым типом, который реализует FooTrait , но поле дескриптора B может хранить только Handle<B> . Вам нужно переосмыслить, что вы хотите FooTrait делать и как B это удовлетворяет.