Почему компилятор Rust не использует реализацию ожидаемой черты, когда я добавляю реализацию для Vec <T>? - PullRequest
0 голосов
/ 03 сентября 2018

Я пытаюсь реализовать читатель, который мог бы извлечь значения из разных типов из файла. Существует структура File, которая представляет файловый ресурс (и методы для доступа к его содержимому), и признак Reader, который позволяет извлекать значения на основе результирующего типа. Реализация (фиктивная) выглядит следующим образом ( детская площадка ):

use std::io::Result;

mod file {
    use std::io::Result;

    pub struct File {/* ... */}

    pub trait Reader<T> {
        fn read(&mut self) -> Result<T>;
    }

    impl Reader<u32> for File {
        fn read(&mut self) -> Result<u32> {
            // Dummy implementation
            Ok(10)
        }
    }

    impl Reader<u8> for File {
        fn read(&mut self) -> Result<u8> {
            // Dummy implementation
            Ok(0)
        }
    }

    impl Reader<bool> for File {
        fn read(&mut self) -> Result<bool> {
            // Dummy implementation
            Ok(false)
        }
    }
}

use file::{File, Reader};

impl<T: Default> Reader<Vec<T>> for File
where
    File: Reader<T> + Reader<u32>,
{
    fn read(&mut self) -> Result<Vec<T>> {
        let count: u32 = self.read()?;
        let mut array: Vec<T> = Vec::with_capacity(count as usize);
        for _ in 0..count {
            let mut item: T = self.read()?;
            array.push(item);
        }

        Ok(array)
    }
}

fn main() {
    let mut file = File {};
    let _v: Vec<u8> = file.read().unwrap();
}

Все работало, пока я не добавил реализацию Reader<Vec<T>>. Векторы хранятся в файле как u32, обозначая количество элементов, за которым следует представление элемента. Компилятор выдает следующую ошибку:

error[E0308]: try expression alternatives have incompatible types
  --> src/main.rs:41:26
   |
41 |         let count: u32 = self.read()?;
   |                          ^^^^^^^^^^^^
   |                          |
   |                          expected u32, found type parameter
   |                          help: try wrapping with a success variant: `Ok(self.read()?)`
   |
   = note: expected type `u32`
              found type `T`

Несмотря на то, что я указал, что File реализует как Reader<T>, так и Reader<u32>, похоже, он застрял на Reader<T>.

Что еще более странно, так это то, что если я оставлю только 2 реализации черты Reader (например, удаляя Reader<bool>), код скомпилируется без проблем ( plays ).

Почему компилятор не может узнать, что он должен использовать реализацию Reader<u32> для инициализации count? Что я должен изменить?

Я нашел обходной путь, но мне все еще интересно понять, почему компилятор не может понять это автоматически:

let count: u32 = (self as &mut Reader<u32>).read()?;
<Ч />

О проблеме сообщалось как rust-lang / rust # 54344 .

1 Ответ

0 голосов
/ 19 сентября 2018

Нет веской причины, по которой компилятор не может понять, что он должен использовать реализацию Reader<u32> для let count: u32 = .... Это ошибка компилятора, потому что T не имеет никакого отношения к тому, как self.read() используется в этой строке. Тип возврата одного вызова .read(), по-видимому, определяет тип возврата другого вызова .read(), когда этого не должно быть!

Кроме того, если бы это не было ошибкой, то не имело бы значения, какие реализации Reader<T> существуют, кроме Reader<u8> и Reader<u32>, но, как указал @rodrigo, наличие Reader<bool> реализация вызывает эту ошибку.

Обратите внимание, что ? (что эквивалентно match, показанному ниже) не имеет ничего общего с ошибкой, поскольку вы все равно получаете ошибку, когда Result<u32> получен напрямую:

let count_result: Result<u32> = self.read(); // error happens here
let count: u32 = match count_result {
    std::result::Result::Ok(val) => val,
    std::result::Result::Err(err) => {
        return std::result::Result::Err(std::convert::From::from(err))
    }
};
...