1

I want to add some error handler in the rust function, so I define the rust function response like this so that I could return the error message if encount the recoverable error:

pub fn add_bill_book() -> Result<BillBook,String> {
    return Err("failed".parse().unwrap())
}

and box the result to return to client like this;

fn main() {
    let result = add_bill_book();
    box_rest_response(result);
}

but when I compile the project, shows error like this:

    ➜  rust-learn git:(multiple-statement) ✗ cargo build
   Compiling rust-learn v0.1.0 (/Users/xiaoqiangjiang/source/reddwarf/backend/rust-learn)
error[E0277]: the trait bound `Result<BillBook, std::string::String>: std::default::Default` is not satisfied
  --> src/main.rs:8:23
   |
8  |     box_rest_response(result);
   |     ----------------- ^^^^^^ the trait `std::default::Default` is not implemented for `Result<BillBook, std::string::String>`
   |     |
   |     required by a bound introduced by this call
   |
note: required by a bound in `box_rest_response`
  --> src/main.rs:11:87
   |
11 | pub fn box_rest_response<T>(data: T) -> content::RawJson<String> where T: Serialize + Default {
   |                                                                                       ^^^^^^^ required by this bound in `box_rest_response`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `rust-learn` due to previous error

what should I do to fix it? I think it is hard to implement the default trait for all type of Result. This is the full minimal reproduce example:

use rocket::response::content;
use rust_wheel::model::response::api_response::ApiResponse;
use serde::Serialize;
use serde::Deserialize;

fn main() {
    let result = add_bill_book();
    box_rest_response(result);
}

pub fn box_rest_response<T>(data: T) -> content::RawJson<String> where T: Serialize + Default {
    let res = ApiResponse {
        result: data,
        ..Default::default()
    };
    let response_json = serde_json::to_string(&res).unwrap();
    return content::RawJson(response_json);
}

#[derive(Debug,Serialize,Deserialize,Default,Clone)]
pub struct BillBook {
    pub id: i64,
    pub created_time: i64,
    pub updated_time: i64,
    pub deleted: i32,
    pub creator: i64,
    pub bill_book_template_id: i32,
    pub remark: Option<String>,
    pub contents: Option<String>,
}

pub fn add_bill_book() -> Result<BillBook,String> {
    return Err("failed".parse().unwrap())
}

and this is the Cargo.toml dependencies:

[package]
name = "rust-learn"
version = "0.1.0"
edition = "2018"

[dependencies]
rocket = { version = "=0.5.0-rc.2", features = ["json"] }
serde = { version = "1.0.64", features = ["derive"] }
serde_json = "1.0.64"
serde_derive = "1.0"
# database
diesel = { version = "1.4.7", features = ["postgres","serde_json"] }
dotenv = "0.15.0"
jsonwebtoken = "7"
chrono = "0.4"
config = "0.11"
ring = "0.16.20"
md5 = "0.7.0"
data-encoding = "2.3.2"

# reddwarf public component
rust_wheel = { git = "https://github.com/jiangxiaoqiang/rust_wheel.git" }

I tried this way to solve this problem:

return match contents {
        Ok(_) => {
            box_rest_response(contents.unwrap())
        },
        Err(_) => {
            box_rest_response(contents.unwrap_err())
        }
    }

but the new problem is that I have to match the result in many places, is it possible to optimized it? I tried to add a new function in public lib like this:

pub fn box_rest_result<T,E>(result: Result<T,E>) -> content::RawJson<String> where T: Serialize + Default, E: std::default::Default{
    return match result {
        Ok(_) => {
            box_rest_response(result.unwrap())
        },
        Err(_) => {
            box_rest_response(result.unwrap_err())
        }
    }
}

still facing the same problem.

Dolphin
  • 29,069
  • 61
  • 260
  • 539

1 Answers1

3

Result does not implement Default because there is no one-fits-all default value.

You can create a newtype struct and implement Default on it, as in How do I implement a trait I don't own for a type I don't own?.

Note that match with unwrap() is a very bad idea, since match can already extract the value:

match contents {
    Ok(v) => box_rest_response(v),
    Err(e) => box_rest_response(e),
}
Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77