繁体   English   中英

如何使用 rust Try trait with Option NoneError?

[英]How can I use rust Try trait with Option NoneError?

我编写了一个自定义协议,在其中为帧定义了自己的结构,并从字节中解析。 我的 function 接受Vec并相应地解析元素。 为了解决无效帧,我返回一个Result<Frame>并在字节数组上调用.get() 这是我的代码:

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>) -> std::io::Result<Self> {
        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
        })
    }
}

但是,当我尝试使用此模式时,我收到以下编译错误,并且在尝试实现该特征时,我收到一个错误,即 Try 特征不稳定。

error[E0277]: `?` couldn't convert the error to `std::io::Error`
   --> src/stack/frame.rs:121:34
    |
121 |         let txflag = bytes.get(0)?.clone();
    |                                  ^ the trait `std::convert::From<std::option::NoneError>` is not implemented for `std::io::Error`

不太确定如何进行,但我想使用稳定的功能来解决这个问题。 这里的目标是能够解析字节并根据需要处理无效帧。

这可能是你想要的

use std::io::{Error, ErrorKind};

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>) -> std::io::Result<Self> {
        let txflag = bytes.get(0).ok_or(Error::from(ErrorKind::InvalidData))?.clone();
        let msgtype = bytes.get(1).ok_or(Error::from(ErrorKind::InvalidData))?.clone();
        let sender = bytes.get(2).ok_or(Error::from(ErrorKind::InvalidData))?.clone();
        let routesoffset = bytes.get(3).ok_or(Error::from(ErrorKind::InvalidData))?.clone();
        let routes = bytes
            .get(4..(4 + routesoffset as usize))
            .ok_or(Error::from(ErrorKind::InvalidData))?
            .clone();
        let (_, right) = bytes.split_at(2);
        let data = Vec::from(right);

        Ok(Frame {
            txflag,
            msgtype,
            sender,
            routeoffset: routesoffset,
            route: Vec::from(routes),
            payload: data,
        })
    }
}

这里是Rust 游乐场

你想打电话? Option上。 您必须将Option转换为Result (如果您仍想使用? )。

我想补充一下 Đorðe Zeljić 所说的话:

正如他已经指出的那样bytes.get(0)的结果是std::option::Option 当你使用? 操作员说你已经离开了稳定的 Rust 的理由。 目前仅在不稳定的 Rust 中支持此应用程序。

如果你想保持稳定的 Rust,最好按照 Đorðe 写的去做。 如果你想继续使用? 运算符,因为它会生成更好看的代码,这是发生了什么:

Rust 有很多错误类型,每一种都只能代表它们的用途。 如果您使用的是std::io::Result这隐式使用错误类型std::io::Error只能表示典型的 I/O 错误。 这种类型不能代表“当我期望的时候没有价值”。 这就是为什么从申请? 对于具有None值的Option ,您不会得到std::io::Error而是另一种错误: std::option::NoneError

当您的 Rust 应用程序增长时,它会经常发生,您必须返回一个可能包含不同类型错误的Result 在这种情况下,您通常定义自己的错误类型(枚举),它可以表示不同类型的错误。 然后对于每个可以包含的错误,您必须在自己的枚举上定义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 function 然后必须返回使用您的新错误类型的std::result::ResultResult<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"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM