Reputation: 6060
I'm new to Rust and there is a function in actix-web
that intrigue me. To create a router in actix
, we need to pass a function (handle_get_insert
for example) that implements actix_web::Responder
// main.rs
cfg.service(
web::resource("/items/get")
.route(web::get().to(handle_get_item))
.route(web::head().to(|| HttpResponse::MethodNotAllowed())),
// handle_get_item is a function that returns any type that implement use actix_web::Responder
// Here Responder means any type that it return must have #[derive(Serialize, Deserialize)]
pub async fn handle_get_item(....) -> impl Responder {
match reply {
Ok(item_doc) => {
let result = GetReply {
id: String::from(inf.id.to_string()),
doc: Some(item_doc),
ok: true,
};
// convert the result into json
return web::Json(result);
}
Err(e) => {
let result = ErrorReply {
error: format!("{}", e),
ok: false,
};
// error is occurred here: expected struct "GetReply", found struct "ErrorReply"
return web::Json(result);
}
}
}
this handle_get_item
can return two type of value (GetReply
for data and ErrorReply
if an error occurred). Both types have the same traits but with different fields in it.
To my surprise, Rust only recognize one of them as the return type, and throws an error on the ErrorReply
:
error: mismatched types
label: expected struct "GetReply", found struct "ErrorReply"
which means that Rust only recognizes GetReply
as the returned value and forces each exit point to implements the same GetReply
type.
Does it possible to return two types ? or this is not supposed to be happen in actix
?
Upvotes: 1
Views: 1937
Reputation: 42282
Both types have the same traits but with different fields in it.
Yes but as Ivan C noted that's not what impl Trait
does. impl Trait
is essentially a placeholder for a normal type which implements the trait (it also makes the return type opaque which lets you e.g. return private types from pub functions).
Does it possible to return two types ?
Technically no, a Rust function can only return values of one type, however there are usually ways around this. One is to return a dynamically dispatched object via Box
. This is slightly less efficient, but if the trait is object-safe (note: I've no idea if Responder is) then it lets you leverage trait objects to kinda-sorta return different types from the same function.
An alternative is that the one trait is basically just an intermediate step and ends up converting to a single concrete type at the end. While you'd usually return something implementing the trait for convenience you can… take the final step yourself "by hand".
In Actix, I expect that's HttpResponse
, which you can either build "by hand" or using Responder::respond_to
.
Upvotes: 2