Почему при использовании ReadBytesExt для чтения целого числа из фрагмента байтов выдается ошибка «границы признаков не были выполнены»? - PullRequest
0 голосов
/ 10 января 2019

Следующий код Rust не компилируется.

extern create byteorder;
use byetorder::{LittleEndian, ReadBytesExt};

fn main() {                                                                          
    let buf: [u8; 12] = [                                                                     
        0x00, 0x42, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x30,               
    ];
    let id = &buf[0..1].read_u16::<LittleEndian>();              }

Сообщение от компилятора:

error[E0599]: no method named `read_u16` found for type `[u8]` in the current scope           
  --> src/main.rs:18:25                                                                       
   |                                                                                          
18 |     let id = &buf[0..1].read_u16::<LittleEndian>();                                      
   |                         ^^^^^^^^                                                         
   |                                                                                          
   = note: the method `read_u16` exists but the following trait bounds were not satisfied:    
           `[u8] : byteorder::ReadBytesExt`

Есть очень похожие вопросы о переполнении стека, которые я рассмотрел, но мои немного отличаются от тех, потому что я пытаюсь прочитать u16 из фрагмента. На практике я не уверен, почему мой пример существенно отличается, я уверен, что упускаю что-то очевидное.

В частности, мне не ясно, как то, что у меня есть, существенно отличается от того, что в принятом здесь ответе:

Как я могу преобразовать буфер фрагмента байтов (& [u8]) в целое число?

Разве я не имею &[u8], когда я говорю &buf[0..1]?

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Поскольку границы черты не были выполнены.

read_u16 необходимо, чтобы получатель был изменяемым эталоном :

pub trait ReadBytesExt: Read {
    fn read_u16<T: ByteOrder>(&mut self) -> Result<u16> { ... }
}

Это потому, что он вызовет Read, что требует того же:

impl<'a> Read for &'a [u8] {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize>
}

Обратите внимание, что Read реализован для &[u8], но занимает &mut self. Это означает, что self является &mut &[u8], изменяемой ссылкой на фрагмент.


Введение круглых скобок, как предложено Свеном Марнахом , создает срез (&[u8]) в качестве временного значения, а временные значения могут рассматриваться как неявно изменяемые.

В связанном вопросе начальная переменная - это изменяемый фрагмент. Звонок read_u16 может иметь изменяемую ссылку на buf:

let mut buf: &[u8] = &[0x00, 0x42];

В вашем случае у вас есть массив. Хотя это разыменовывает фрагмент, автоматические (де) правила ссылки Rust никогда не добавят два уровня ссылки. Ошибка поиска метода.

Смотри также:

0 голосов
/ 10 января 2019

Ваш код вызывает read_u16() для массива вместо слайса . Вы, вероятно, намереваетесь вызвать метод на &buf[0..1], но из-за приоритета оператора вы фактически вызываете его на buf[0..1]. Это можно исправить, просто добавив пару скобок:

let id = (&buf[0..1]).read_u16::<LittleEndian>();

Ваш исходный код интерпретируется как &(buf[0..1].read_u16::<LittleEndian>()), поэтому компилятор жалуется, что черта ReadBytesExt не реализована для [u8].

...