Константа, связанная с трейтом, недоступна в контексте определения трейта, несмотря на соответствующую привязку трейта.

Вот над чем я сейчас работаю (игровая площадка):

pub trait DisplayWidth {
    const DISPLAY_WIDTH: usize;

    fn chunks<'a>(s: &'a str) -> Chunks<'a, Self> {
        Chunks(s.chars(), PhantomData)
    }
}

pub struct Chunks<'a, T: ?Sized>(std::str::Chars<'a>, PhantomData<T>);

impl<'a, T: DisplayWidth> Iterator for Chunks<'a, T> {
    // 4 bytes in a max-width char
    type Item = SmallString<[u8; 4 * T::DISPLAY_WIDTH]>;

    fn next(&mut self) -> Option<Self::Item> {
        let mut s = SmallString::new();
        for _ in 0..T::DISPLAY_WIDTH {
            s.push(self.0.next()?);
        }
        Some(s)
    }
}

Это генерирует E0599, но только для определения type Item:

error[E0599]: no associated item named `DISPLAY_WIDTH` found for type parameter `T` in the current scope
  --> src/geometry/tile.rs:23:41
   |
23 |     type Item = SmallString<[u8; 4 * T::DISPLAY_WIDTH]>;
   |                                         ^^^^^^^^^^^^^ associated item not found in `T`
   |
   = help: items from traits can only be used if the type parameter is bounded by the trait

Интересен тот факт, что rustc вообще не жалуется на использование ассоциированной константы в цикле for; только в связанном определении типа.

Я подозреваю, что это ошибка компилятора: учитывая, что T ограничено DisplayWidth, он должен быть доступен в контексте определения типа, связанного с трейтом, но его просто нет. Тем не менее, я спрашиваю здесь, прежде чем подавать отчет об ошибке в rustc, потому что я не уверен в этом на 100%.

Обходной путь, который я использую на данный момент, прост: определите отдельную константу и используйте ее:

pub const CHUNK_WIDTH: usize = 4;
    type Item = SmallString<[u8; 4 * CHUNK_WIDTH]>;

Есть ли решение, которое позволило бы использовать DisplayWidth::DISPLAY_WIDTH?


person coriolinus    schedule 11.12.2020    source источник
comment
Эта ошибка отслеживается здесь: github.com/rust-lang/rust/issues/60551.   -  person Ibraheem Ahmed    schedule 11.12.2020


Ответы (1)


Это ограничение длины массива; он не может использовать какие-либо параметры или общие границы, даже если они являются областью действия. Проблема возникла во время стабилизации связанных констант, и было принято решение стабилизировать их без нее.

Это ограничение специфично для параметров длины массива, все остальное работает:

pub trait Shape {
    const SIDES: usize;
}

pub trait SimpleIter {
    const Item: usize;    
}

impl<T: Shape> SimpleIter for T {
    // this is fine
    const Item: usize = T::SIDES;
}

Проблему можно отследить здесь и здесь

person Ibraheem Ahmed    schedule 11.12.2020