#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
это удовлетворяет.