Границы признака с более высоким рейтингом и параметры функции

#rust #higher-rank-types #bevy

#Ржавчина #типы с более высоким рангом #множество

Вопрос:

Я пытаюсь понять реализацию IntoForEachSystem признака Беви и то, как он взаимодействует с базовыми Hec Query и Fetch признаками. В Hecs есть типы запросов (то, что вы запрашиваете при вызове query::<T> ) и типы элементов (то, что возвращается запросом). Идея заключается в том, что IntoForEachSystem это реализовано для замыканий, тип запроса которых соответствует типу элемента запроса, и fn f(amp;i32) работает, потому что amp;i32 запрос возвращает amp;i32 элемент.

Я думаю, что я извлек соответствующие части дизайна из этого фрагмента, но я не могу заставить его проверять тип:

 // Hecs Query trait
trait Query {
    type Fetch: for<'a> Fetch<'a>;
}

// Hecs Query trait implementation for read-only references
impl<'a, T> Query for amp;'a T
where
    T: 'static,
{
    type Fetch = FetchRead<T>;
}

// Hecs Fetch trait
trait Fetch<'a>: Sized {
    type Item;
}

// Hecs Fetch trait implementation for read-only references
struct FetchRead<T>(std::marker::PhantomData<T>);

impl<'a, T> Fetch<'a> for FetchRead<T>
where
    T: 'static,
{
    type Item = amp;'a T;
}

// Bevy IntoForEachSystem trait, simplified
trait IntoForEachSystem<R> {
    fn system(self);
}

// Bevy IntoForEachSystem trait implementation for functions of one argument
impl<F, R> IntoForEachSystem<R> for F
where
    F: Fn(R),
    F: Fn(<<R as Query>::Fetch as Fetch>::Item),
    R: Query,
{
    fn system(self) {
        println!("hello");
    }
}

fn hmm(_x: amp;i32) {
    todo!()
}

fn main() {
    IntoForEachSystem::system(hmm)
}
  

Ошибки:

 error[E0631]: type mismatch in function arguments
   |
31 |     fn system(self);
   |     ---------------- required by `IntoForEachSystem::system`
...
46 | fn hmm(_x: amp;i32) {
   | ---------------- found signature of `for<'r> fn(amp;'r i32) -> _`
...
51 |     IntoForEachSystem::system(hmm)
   |                               ^^^ expected signature of `for<'r> fn(<FetchRead<i32> as Fetch<'r>>::Item) -> _`
   |
   = note: required because of the requirements on the impl of `IntoForEachSystem<amp;i32>` for `for<'r> fn(amp;'r i32) {hmm}`
  

Я думаю, что компилятор рассматривает предполагаемое время жизни 'r в fn hmm<'r>(amp;'r i32) как отличное от времени жизни forall 'a в type Fetch: for<'a> Fetch<'a> . Я не вижу трюка, который использует Bevy для достижения того же самого.

Ответ №1:

Вы действительно очень близки!

 fn main() {
    hmm.system();
}
  

Это … очень неприятно, потому что, насколько мне известно, IntoForEachSystem::system(hmm) должно быть эквивалентно hmm.system() . Может быть, это ошибка в компиляторе Rust?

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

1. Ну, это странно. Действительно, это то, что делает реальный код в Bevy. Я только изменил его на UFC, чтобы сделать сообщения об ошибках более четкими…