если я явно укажу тип через турбофиш то все компилируется и axum принимает хендлер например
pub fn routes() -> Router {
Router::new().route("/", get(data_all_handler::<ApiDataBase<Language>>))
}
Но если превратить функцию в генеративную data_default_routes то аксум не хочет принимать на этапе компиляции.
pub async fn data_all_handler<T>(Extension(db): Extension<T>) -> Json<DataAllResponse<T::Item>>
where
T: AllDB,
T::Item: ApiItem,
{
let res = db.all().await;
Json::from(res.map_err(|e| e.to_string()))
}
pub fn data_default_routes<T>() -> Router
where
T: AllDB,
T::Item: ApiItem,
{
Router::new().route("/", get(data_all_handler::<T>))
}
Получаю следующую ошибку:
error[E0277]: the trait bound `fn(Extension<T>) -> impl Future<Output = Json<Result<Vec<<T as AllDB>::Item>, std::string::String>>> {data_all_handler::<T>}: Handler<_, _, _>` is not satisfied
--> src/web/api/crud_handlers.rs:34:34
|
34 | Router::new().route("/", get(data_all_handler::<T>))
| --- ^^^^^^^^^^^^^^^^^^^^^ the trait `Handler<_, _, _>` is not implemented for fn item `fn(Extension<T>) -> impl Future<Output = Json<Result<Vec<<T as AllDB>::Item>, std::string::String>>> {data_all_handler::<T>}`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Handler<T, S, B>`:
<Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>
<MethodRouter<S, B> as Handler<(), S, B>>
note: required by a bound in `axum::routing::get`
--> /home/dima/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.6.18/src/routing/method_routing.rs:403:1
|
403 | top_level_handler_fn!(get, GET);
| ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^
| | |
| | required by a bound in this function
| required by this bound in `get`
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
Попробуй использовать debug_handler из axum_macros для хендлера
debug_handler не поддерживает дженерики
Жалко код не рабочий. Ну да ладно. Похоже что компилятор просто не может вывести нужные зависимости, или вы не указали все необходимые ограничения по трейтам. Может попросить помочь сам компилятор? То есть сделать чтобы data_all_handler возвращал impl Handler
Может вы имели в виду impl IntoResponse?
По ограничениям вроде все есть, сам же data_all_handler работает. Проблема в data_default_routes, ограничения такие же как и в data_all_handler
Наверное что то все таки не хватает)) вот я и думал как сделать так чтобы компилятор точно сказал чего не хватает. Если при одних данных data_all_handler выдает нужные выходные данные, а при других нет, значит проблема наверное с интерпретацией T::Item. То есть идея сперва работать с вариантом get(data_all_handler::<ApiDataBase<Language>>), попробовав чтобы data_all_handler возвращал impl Handler или impl IntoResponse (вам виднее), все настроить, а уже потом добиться того чтобы data_default_routes работал с дженериком.
data_all_handler работает с impl IntoResponse в указанным типом
Попробуйте сделать T и/или DataAllResponse: Serialize.
Вернусь к данному вопросу. Вот сделал простой пример что бы можно было запустить у себя. Кто то может подсказать чего требует компилятор: use axum::handler::Handler; use axum::response::Html; use axum::routing::get; use axum::{Extension, Router}; //use axum_macros::debug_handler; use std::error::Error; use std::net::SocketAddr; use std::str::FromStr; trait Data: Clone { type Item: Into<String>; fn get_item(&self) -> Self::Item; } #[derive(Clone)] struct Container<T>(T) where T: Into<String> + Clone; impl<T> Data for Container<T> where T: Into<String> + Clone, { type Item = T; fn get_item(&self) -> Self::Item { return self.0.clone(); } } //#[debug_handler] doesn't support generic functions async fn handle<T: Data>(Extension(data): Extension<T>) -> Html<String> { let res: String = data.get_item().into(); Html::from(res) } fn router<T: Data>() -> Router { Router::new().route("/", get(handle::<T>)) } #[tokio::main] async fn main() -> Result<(), Box<dyn Error + Send + Sync>> { let data = Container("hello world".to_string()); let router = router::<Container<String>>().layer(Extension(data)); // this work // let router = Router::new() // .route("/", get(handle::<Container<String>>)) // .layer(Extension(data)); let addr = SocketAddr::from_str("127.0.0.1:3001").unwrap(); axum::Server::bind(&addr) .serve(router.into_make_service()) .await .unwrap(); Ok(()) } Я уже что только не перепробовал. Или тут стоит на github в axum писать?
У тебя, как я понимаю, дженерик Json не реализует, попробуй
Он и не должен же
Json это же не трейт а структура
Ну сейчас пробегусь снова по ошибке, не удобно читать в таком формате
Попробуй добавить типаж Handler: T: Data + Handler
А еще лучше сразу в трейт Data: pub trait Data: Handler + Clone + Send + Sync + 'static
Там проблема мне кажется не в Data трейте а в самом. Так как функция handler работает и компилится. let router = Router::new() .route("/", get(handle::<Container<String>>)) .layer(Extension(data)); так все работает и проблема мне кажется не в описании дженерика а в чем то другом
Обсуждают сегодня