简体   繁体   中英

Problems while instantiating an error in rust

I have a struct that contains the return code and the data retrieved from a postgres query. I have a new() function that initializes the struct:

impl <T> Response <T>
     {
     pub fn new() -> Response <T>
             {
             return Response
                 {
                 rc : RetCode::Ok,
 ------>         pg_err : Error::new(),
                 desc : "".to_string(),
                 data : Vec::new(), 
                 id : 0,
                }

but the postgres::Error::new() is private. Is there a way to create a new error ( i don't mind the type or content), just for placeholder for actual, future error? i don't need Null, just a fake error, because in RetCode i have ok, no-data-retrieved, postgre error, so i need to check the error just when retcode is pg_error.

As mentioned in the comments, there is no public way to create a postgres::Error . You can only get one from some other postgres operation that fails. You can use the linked answer and use an Option to create the pg_err with None before an error occurs, and filling it with Some(...) when it does.

However, that is not the way you should solve this particular problem. You have a single type that is designed to express multiple different forms of responses: "ok", "no-data", and "error" as you've mentioned in the comments. So it sounds like you have RetCode designed as such:

enum RetCode { Ok, NoData, Error }

But Rust enum s are much more powerful than in other languages, they can hold data exclusive to a specific variant. There is a philosophy to "make invalid states unrepresentable". In other words, why have a pg_err if no error occurred? Why have a data field if the status is NoData ?

You can restructure your objects like so:

enum ResponseKind<T> {
    Ok { data: Vec<T> },
    NoData,
    Error { pg_err: postgres::Error },
}

struct Response<T> {
    id: i32,
    desc: String,
    kind: ResponseKind<T>,
}

That way you don't have to worry about creating some dummy error type.

You should heed the other comments; don't fall into the trap of simply creating a dummy constructor just for the sake of it. And new() is just a convention which shouldn't be followed if there's no obvious default state for your type. You should have constructor functions with parameters that provide valid data to construct it with. Like:

impl<T> Response<T> {
    pub fn ok(id: i32, desc: String, data: Vec<T>) -> Response<T> {
        // or maybe id and desc are generated or dependent on
        // kind and don't need to be parameters?
        Response {
            id,
            desc,
            kind: ResponseKind::Ok { data },
        }
    }

    pub fn no_data(id: i32, desc: String) -> Response<T> { ... }
    pub fn error(id: i32, desc: String, error: Error) -> Response<T> { ... }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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