Невозможно определить тип для параметра типа T, когда тип явно указан в определении структуры - PullRequest
2 голосов
/ 29 февраля 2020

У меня есть определение структуры, которое включает, помимо прочего, это поле:

pub struct Separated<'a, I, T>
{
    ..., // other fields,
    separated: NonNull<dyn 'a + Iterator<Item = T>>,
}

Вскоре после этого в своем конструкторе я пытаюсь инициализировать это поле как висячий указатель:

let sep = Separated {
    ..., // other fields
    separated: NonNull::dangling(),
};

Это, как ни странно, приводит к этой ошибке:

error[E0282]: type annotations needed
   |
16 |             separated: NonNull::dangling(),
   |                        ^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`

В этом поле нет ничего загадочного; его тип явно указан в определении структуры. Я не понимаю, почему средство вывода типов не может определить подходящий тип для внедрения там.

Минимальный пример из 20 строк, приводящий к этой ошибке, можно найти ниже и на игровой площадке :

use std::pin::Pin;
use std::ptr::NonNull;

pub struct Separated<'a, T> {
    t: &'a T,
    separated: NonNull<dyn 'a + Iterator<Item = T>>,
}

impl<'a, T> Separated<'a, T>
where
    T: 'a + Copy + PartialEq,
{
    fn new(t: &'a T) -> Pin<Box<Self>> {
        let sep = Separated {
            t,
            separated: NonNull::dangling(),
        };
        unimplemented!()
    }
}

Мне нужно, чтобы separated был указателем на объект признака вместо мономорфизированного типа: объект реального признака, который он будет содержать, состоит из набора комбинаторов итераторов, включая такие, как Map и TakeWhile, чьи типы включают указатели на функции и поэтому не могут быть названы.

NonNull::dangling не является параметрической c функцией: структура NonNull<T> является параметрической c, но эта функция - нет. Поэтому я не могу просто turbofi sh мой выход из этого. Я не уверен, как бы я go вообще предоставил аннотации типов.


Контекст, если это полезно: единственная причина, по которой я иду по этому пути, в том, что я пытаюсь создать комбинатор итераторов, автоматически реализованный для всех соответствующих итераторов, который вставляет один элемент между каждым из N элементов исходного итератора. Не так сложно выполнить sh для одного итератора, но гораздо сложнее сделать это как обобщенный c комбинатор, поскольку структура IntoChunks, создаваемая комбинатором chunks() Itertools, сама по себе не является итератором, а просто структура, реализующая IntoIterator. Следовательно, нам нужно отслеживать структуру IntoChunks и ее итератор.

Подход, который я использую, заключается в создании самореференциальной структуры, Separated, которая содержит оба из них. Это должно быть безопасно, если структура всегда закреплена. Я тогда impl Iterator for Separated и просто откладываю next звонки на self.separated.

1 Ответ

4 голосов
/ 01 марта 2020

Согласно стандартным документам, определение NonNull::dangling() таково:

impl<T> NonNull<T> {
  pub const fn dangling() -> NonNull<T> {
    /* ... */
  }
}

И в вашем коде вы используете его в место, где выражение с типом NonNull<dyn 'a + Iterator<Item = T>>, поэтому возвращаемое значение должно иметь этот тип.

Тонкая вещь здесь в том, что параметры типа generi c имеют неявную привязку Sized (если только она не имеет ?Sized связан). Так как реализация NonNull::dangling не имеет ограничения ?Sized, Rust попытается вывести параметр типа NonNull на основе следующих требований:

  • Поскольку метод NonNull::<T>::dangling() делает не имеет границы T: ?Sized, он реализован только для типов с размерами T, а параметр типа должен иметь размер.
  • Параметр типа должен быть dyn 'a + Iterator<Item = T>.

Однако, поскольку объекты признаков ("dyn Trait types") не имеют размера, Rust не может одновременно удовлетворить оба требования, поэтому он "не может определить тип для параметра типа T".


Фактически, явно добавив тип к примеру с игровой площадкой, вы получите другое сообщение об ошибке, более подробное о проблеме:

let sep = Separated::<'a, T> {
  t,
  separated: NonNull::<dyn 'a + Iterator<Item = T>>::dangling(),
};
error[E0599]: no function or associated item named `dangling` found for type `std::ptr::NonNull<(dyn std::iter::Iterator<Item = T> + 'a)>` in the current scope
  --> src/lib.rs:16:64
   |
16 |             separated: NonNull::<dyn 'a + Iterator<Item = T>>::dangling(),
   |                                                                ^^^^^^^^ function or associated item not found in `std::ptr::NonNull<(dyn std::iter::Iterator<Item = T> + 'a)>`
   |
   = note: the method `dangling` exists but the following trait bounds were not satisfied:
           `dyn std::iter::Iterator<Item = T> : std::marker::Sized`
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...