一个 implement/derive 可以在没有 #[derive(Serialize)] 的情况下对枚举进行序列化吗?
Can one implement/derive Serialize on an enum without #[derive(Serialize)]?
我正在使用 rust + rocket + diesel (orm) + serde_derive 休息一下 api。目前,如果 diesel 由于某种原因未能插入用户,我正在处理 api 的错误处理。看起来像这样:
pub fn create(user: InsertableUser, connection: &MysqlConnection) -> ApiResponse {
let result = diesel::insert_into(users::table)
.values(&InsertableUser::hashed_user(user))
.execute(connection);
match result {
Ok(_) => ApiResponse {
json: json!({"success": true, "error": null}),
status: Status::Ok,
},
Err(error) => {
println!("Cannot create the recipe: {:?}", error);
ApiResponse {
json: json!({"success": false, "error": error}),
status: Status::UnprocessableEntity,
}
}
}
}
但是,json: json!({"success": false, "error": error}),
给我这个错误:
the trait bound `diesel::result::Error: user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not satisfied
the trait `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not implemented for `diesel::result::Error`
note: required because of the requirements on the impl of `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` for `&diesel::result::Error`
note: required by `serde_json::value::to_value`rustc(E0277)
<::serde_json::macros::json_internal macros>(123, 27): the trait `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not implemented for `diesel::result::Error`
听上去,diesel::result::Error
不是 #[derive(Serialize)]
,因此不能用 json!
宏序列化。因此,我需要一些方法来制作 diesel::result::Error
implement/derive Serialize
.
在此先感谢您的帮助。
顺便说一句,ApiResponse 看起来像:
use rocket::http::{ContentType, Status};
use rocket::request::Request;
use rocket::response;
use rocket::response::{Responder, Response};
use rocket_contrib::json::JsonValue;
#[derive(Debug)]
pub struct ApiResponse {
pub json: JsonValue,
pub status: Status,
}
impl<'r> Responder<'r> for ApiResponse {
fn respond_to(self, req: &Request) -> response::Result<'r> {
Response::build_from(self.json.respond_to(&req).unwrap())
.status(self.status)
.header(ContentType::JSON)
.ok()
}
}
Serde 提供了一种为外部 crate 导出序列化实现的解决方法 - 请参阅其文档中的 Derive for remote crates 部分。
您必须定义一个与您尝试序列化的枚举具有相同定义的枚举(在您的情况下为 diesel::result::Error
),然后将其识别为您尝试序列化的类型的一种代理序列化,像这样:
#[derive(Serialize, Deserialize)]
#[serde(remote = "diesel::result::Error")]
struct ErrorDef {
// Definition in here the same as the enum diesel::result::Error
// ...
}
当然,您也必须对 Error
类型中包含的所有类型(或至少任何尚未实现序列化的类型)执行相同的操作。
文档指出 Serde 根据 'remote' 包中的定义检查您提供的定义,如果它们不同则抛出错误,这将有助于保持它们同步。
另请注意,这不会导致 diesel::result::Error
实现序列化 - 而是您现在有一个可以像这样使用的替代类型:
struct JsonErrorRespone {
pub success: bool,
#[serde(with = "ErrorDef")]
pub error: diesel::result::Error,
}
然后您将序列化上述结构的实例,而不是现有的 json!
宏调用。
此外,上面链接的文档还提供了一些有关手动调用正确的序列化/反序列化实现的提示。
免责声明:我还没有使用过这个工具,以上内容仅从文档中收集。
简短回答:yes you can。我个人一直觉得有点难。
作为折衷方案,您可以只提取与您相关的错误部分,甚至可以这样做:
ApiResponse {
json: json!({"success": false, "error": error.to_string() }),
status: Status::UnprocessableEntity,
}
如果您对错误的文本表示感到满意。
我正在使用 rust + rocket + diesel (orm) + serde_derive 休息一下 api。目前,如果 diesel 由于某种原因未能插入用户,我正在处理 api 的错误处理。看起来像这样:
pub fn create(user: InsertableUser, connection: &MysqlConnection) -> ApiResponse {
let result = diesel::insert_into(users::table)
.values(&InsertableUser::hashed_user(user))
.execute(connection);
match result {
Ok(_) => ApiResponse {
json: json!({"success": true, "error": null}),
status: Status::Ok,
},
Err(error) => {
println!("Cannot create the recipe: {:?}", error);
ApiResponse {
json: json!({"success": false, "error": error}),
status: Status::UnprocessableEntity,
}
}
}
}
但是,json: json!({"success": false, "error": error}),
给我这个错误:
the trait bound `diesel::result::Error: user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not satisfied
the trait `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not implemented for `diesel::result::Error`
note: required because of the requirements on the impl of `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` for `&diesel::result::Error`
note: required by `serde_json::value::to_value`rustc(E0277)
<::serde_json::macros::json_internal macros>(123, 27): the trait `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not implemented for `diesel::result::Error`
听上去,diesel::result::Error
不是 #[derive(Serialize)]
,因此不能用 json!
宏序列化。因此,我需要一些方法来制作 diesel::result::Error
implement/derive Serialize
.
在此先感谢您的帮助。
顺便说一句,ApiResponse 看起来像:
use rocket::http::{ContentType, Status};
use rocket::request::Request;
use rocket::response;
use rocket::response::{Responder, Response};
use rocket_contrib::json::JsonValue;
#[derive(Debug)]
pub struct ApiResponse {
pub json: JsonValue,
pub status: Status,
}
impl<'r> Responder<'r> for ApiResponse {
fn respond_to(self, req: &Request) -> response::Result<'r> {
Response::build_from(self.json.respond_to(&req).unwrap())
.status(self.status)
.header(ContentType::JSON)
.ok()
}
}
Serde 提供了一种为外部 crate 导出序列化实现的解决方法 - 请参阅其文档中的 Derive for remote crates 部分。
您必须定义一个与您尝试序列化的枚举具有相同定义的枚举(在您的情况下为 diesel::result::Error
),然后将其识别为您尝试序列化的类型的一种代理序列化,像这样:
#[derive(Serialize, Deserialize)]
#[serde(remote = "diesel::result::Error")]
struct ErrorDef {
// Definition in here the same as the enum diesel::result::Error
// ...
}
当然,您也必须对 Error
类型中包含的所有类型(或至少任何尚未实现序列化的类型)执行相同的操作。
文档指出 Serde 根据 'remote' 包中的定义检查您提供的定义,如果它们不同则抛出错误,这将有助于保持它们同步。
另请注意,这不会导致 diesel::result::Error
实现序列化 - 而是您现在有一个可以像这样使用的替代类型:
struct JsonErrorRespone {
pub success: bool,
#[serde(with = "ErrorDef")]
pub error: diesel::result::Error,
}
然后您将序列化上述结构的实例,而不是现有的 json!
宏调用。
此外,上面链接的文档还提供了一些有关手动调用正确的序列化/反序列化实现的提示。
免责声明:我还没有使用过这个工具,以上内容仅从文档中收集。
简短回答:yes you can。我个人一直觉得有点难。
作为折衷方案,您可以只提取与您相关的错误部分,甚至可以这样做:
ApiResponse {
json: json!({"success": false, "error": error.to_string() }),
status: Status::UnprocessableEntity,
}
如果您对错误的文本表示感到满意。