Я хочу добавить к тому, что сказал Жорде Зельич:
Как он уже указывал, результат bytes.get(0)
равен std::option::Option
. При использовании оператора ?
на этом вы уже оставили основания стабильного Rust. На данный момент это приложение поддерживается только в нестабильном Rust.
Если вы хотите остаться в стабильном Rust, лучше всего делать то, что написал ðorðe. Если вы хотите продолжать использовать оператор ?
, потому что он производит более красивый код, вот что происходит:
Rust имеет много типов ошибок, каждый из которых может представлять только то, для чего они созданы. Если вы используете std::io::Result
, это неявно использует тип ошибки std::io::Error
, который способен отображать только типичные ошибки ввода-вывода. Этот тип не может представлять «не было значения, когда я ожидал его». Вот почему при применении ?
к Option
со значением None
вы не получите std::io::Error
, но ошибка другого типа: std::option::NoneError
.
Когда ваше приложение Rust растет часто случается, что вы должны возвращать Result
, который может содержать различные типы ошибок. В этом случае вы обычно определяете свой собственный тип ошибки (enum), который может представлять различные виды ошибок. Затем для каждой ошибки, которая может содержаться, вы должны определить черту From
в своем собственном перечислении. Это может быть многократной работой, поэтому в quick-error
crate есть макрос, который помогает с этим и автоматически реализует черту From
для каждой ошибки, которая может содержаться.
Чтобы получить код для компиляции, вы можете определить следующее перечисление ошибки, которое может представлять std::io::Error
, а также std::option::NoneError
:
quick_error! {
#[derive(Debug)]
pub enum FrameError {
IoError(err: std::io::Error) {from() cause(err)}
MissingValue(err: std::option::NoneError) {from()}
}
}
Вместо std::io::Result<Self>
вашей функции from_bytes
тогда должен вернуть std::result::Result
, который использует ваш новый тип ошибки: Result<Self, FrameError>
.
Полностью собранный, который выглядит следующим образом:
#![feature(try_trait)]
use quick_error::*;
quick_error! {
#[derive(Debug)]
pub enum FrameError {
IoError(err: std::io::Error) {from() cause(err)}
MissingValue(err: std::option::NoneError) {from()}
}
}
fn main() {
let emptyvec = Vec::new();
match Frame::from_bytes(&emptyvec) {
Err(_e) => {
println!("Received invalid frame");
}
Ok(_frame) => {
println!("Received valid frame");
}
}
}
struct Frame {
txflag: u8, // indicates if chunked
msgtype: u8, // a flag for message type
sender: u8, // which node ID sent this frame?
routeoffset: u8, // size of array of route for frame
route: Vec<u8>, // a list of node IDs that frame should pass
payload: Vec<u8>, // payload data
}
impl Frame {
/// parse from raw bytes
pub fn from_bytes(bytes: &Vec<u8>) -> Result<Self, FrameError> {
let txflag = bytes.get(0)?.clone();
let msgtype = bytes.get(1)?.clone();
let sender = bytes.get(2)?.clone();
let routesoffset = bytes.get(3)?.clone();
let routes = bytes.get(4..(4 + routesoffset as usize))?;
let (left, right) = bytes.split_at(2);
let data = Vec::from(right);
Ok(Frame {
txflag,
msgtype,
sender,
routeoffset: routesoffset,
route: Vec::from(routes),
payload: data,
})
}
}
Чтобы использовать quick-error
ящик, у вас есть добавить следующее к вашему Cargo.toml
:
[dependencies]
quick-error = "1.2.3"