服务层的代码结构会影响Axum处理程序对trait的实现情况

后端开发 2026-07-11

我在用Rust和 Axum框架开发一个相当简单的CRUD REST API。它具有处理程序和服务的分层——处理程序通过 Arc 调用服务。

在开发 generate_unique_slug 函数时,我遇到了如下编译错误。

错误是:

error[E0277]: the trait bound `fn(State<Arc<AppState>>, ..., ..., ...) -> ... {create}: Handler<_, _>` is not satisfied
   --> src/mgmt/server.rs:48:18
    |
48  |             post(branch::create).get(branch::list),
    |             ---- ^^^^^^^^^^^^^^ the trait `axum::handler::Handler<_, _>` is not implemented for fn item `fn(State<Arc<AppState>>, UserId, Path<...>, ...) -> ... {create}`
    |             |
    |             required by a bound introduced by this call
    |
    = note: Consider using `#[axum::debug_handler]` to improve the error message
    = help: the following other types implement trait `axum::handler::Handler<T, S>`:
              `MethodRouter<S>` implements `axum::handler::Handler<(), S>`
              `axum::handler::Layered<L, H, T, S>` implements `axum::handler::Handler<T, S>`
note: required by a bound in `post`
   --> /Users/mateuszwozniak/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/axum-0.8.8/src/routing/method_routing.rs:445:1
    |
445 | top_level_handler_fn!(post, POST);
    | ^^^^^^^^^^^^^^^^^^^^^^----^^^^^^^
    | |                     |
    | |                     required by a bound in this function
    | required by this bound in `post`
    = note: the full name for the type has been written to '/Users/mateuszwozniak/repos/neond/target/debug/deps/neond-1ab29fe44f789f04.long-type-14284547332887205018.txt'
    = note: consider using `--verbose` to print the full type name to the console
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

导致此错误的代码位于 struct BranchServiceasync fn generate_unique_slug 里:

async fn generate_unique_slug(&self) -> Result<String> {
    let mut generator = Generator::default();

    for _ in 0..10 {
        let slug = generator
            .next()
            .unwrap_or_else(|| format!("branch-{}", Uuid::new_v4()));

        if self.branch_repo.find_by_slug(&slug).await?.is_none() {
            return Ok(slug);
        }
    }

    Ok(format!("branch-{}", Uuid::new_v4()))
}

然而,稍作修改——将 names::Generator::default() 移出循环后,代码就可以编译通过:

async fn generate_unique_slug(&self) -> Result<String> {
    for _ in 0..10 {
        let slug = Generator::default()
            .next()
            .unwrap_or_else(|| format!("branch-{}", Uuid::new_v4()));

        if self.branch_repo.find_by_slug(&slug).await?.is_none() {
            return Ok(slug);
        }
    }

    Ok(format!("branch-{}", Uuid::new_v4()))
}

有人能解释这是为什么吗?为什么这个小改动能修复编译错误?

使用的crate: https://crates.io/crates/names

解决方案

如同kmdreko提到的,这很可能是因为 Generator 不是 Send,意味着它不能被发送到不同的线程。你可以按照错误信息中的建议进行检查:

    = note: Consider using `#[axum::debug_handler]` to improve the error message

如果你的应用运行在多线程运行时(Tokio的默认设置),那么在 .await 期间它可能会被重新调度到另一条线程。这意味着你在 .await 时所持有的所有变量都需要能够移动到不同的线程上。

你第二个示例之所以能工作,是因为你在每次循环中创建了一个新的 Generator,因此当前的那个在 .await 之前被丢弃,所以它不需要与函数一起发送。

没有简单的修复方法。可能的解决方案有:

  • 在发生任何 .await 之前生成所有名称
  • 切换到一个不同的生成器,它是 Send
  • 不使用多线程运行时
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章