Почему я получаю ошибку компиляции Rust при объединении границ признака более высокого ранга со связанными типами? - PullRequest
2 голосов
/ 18 февраля 2020

Я пишу некоторый код Rust, который включает обобщенные c признаки и не 'static типы, и в результате я столкнулся с необходимостью приблизить generi c связанные типы . Я понимаю, что GAT нельзя элегантно эмулировать в текущем Rust, но я подумал, что нашел (неэлегантный) обходной путь, который бы сработал для моей конкретной ситуации c, используя характеристики с параметрами времени жизни и границы признаков более высокого ранга. Тем не менее, я получаю ошибки компилятора, которые я не понимаю, относительно реализации отсутствующих признаков для связанных типов.

Следующий код показывает минимальный пример, который воспроизводит ошибку.

use std::fmt::Debug;

trait Resource<'r> {
    type Value;
}

struct ResourceImpl();

impl<'r> Resource<'r> for ResourceImpl {
    type Value = u32;
}

fn test_generic<R>()
where
    for<'r> R: Resource<'r>,
    for<'r> <R as Resource<'r>>::Value: Debug,
{
}

fn test_specific() {
    test_generic::<ResourceImpl>();
}

Когда Я пытаюсь скомпилировать этот код (rustc 1.41.0), я получаю следующее сообщение об ошибке:

error[E0277]: `<ResourceImpl as Resource<'r>>::Value` doesn't implement `std::fmt::Debug`
  --> src/lib.rs:21:5
   |
13 | fn test_generic<R>()
   |    ------------
...
16 |     for<'r> <R as Resource<'r>>::Value: Debug,
   |                                         ----- required by this bound in `test_generic`
...
21 |     test_generic::<ResourceImpl>();
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<ResourceImpl as Resource<'r>>::Value` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
   |
   = help: the trait `for<'r> std::fmt::Debug` is not implemented for `<ResourceImpl as Resource<'r>>::Value`

Сообщение об ошибке звучит так, как будто говорится, что u32 не реализует Debug, что не имеет смысла. Должно быть, я неправильно понимаю, что означает сообщение об ошибке, но я не могу понять, в чем проблема.

Ответы [ 2 ]

2 голосов
/ 19 февраля 2020

Существует открытый выпуск об этой проблеме.

В вашем случае можно обойти это, связав Debug со связанным типом Resource::Value?

trait Resource<'r> {
    type Value: Debug;
}.
0 голосов
/ 20 февраля 2020

Как указывает attdona, это, похоже, ошибка компилятора (с открытой проблемой здесь ). Обсуждение этого вопроса указывает на этот вопрос о переполнении стека , который предоставляет обходной путь, который сработал для меня. Ключевым моментом обходного решения является то, что признак, упомянутый внутри границы признака более высокого ранга, должен иметь параметры времени жизни, совпадающие с параметрами внутри for<_>. Это может быть достигнуто путем создания свойства обертки (в данном случае около Debug) с необходимыми параметрами времени жизни.

В случае минимального примера, приведенного в вопросе, обходной путь выглядит следующим образом:

use std::fmt::Debug;

trait Resource<'r> {
    type Value;
}

struct ResourceImpl();

impl<'r> Resource<'r> for ResourceImpl {
    type Value = u32;
}

trait DebugWithLifetime<'r>: Debug {}

impl<'r, T> DebugWithLifetime<'r> for T where T: Debug {}

fn test_generic<R>()
where
    for<'r> R: Resource<'r>,
    for<'r> <R as Resource<'r>>::Value: DebugWithLifetime<'r>,
{
}

fn test_specific() {
    test_generic::<ResourceImpl>();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...