Rust in Everything
基于 tower 0.5.3

the method oneshot exists for struct Filter<ServiceFn<{closure@...}>, _>, but its trait bounds were not satisfied

主线位置:装配阶段。AsyncFilter::layer 造出的服务是同步的 Filter,异步谓词进不了它的请求主线,编译器在用这个服务的地方报错。

flowchart TB
  l["AsyncFilter::layer(check)"] --> fl["返回 FilterLayer"]
  fl --> f["包出的是 Filter"]
  f --> need["要求 Predicate"]
  need --> no["只是 AsyncPredicate"]
  no --> err["不是 Service:E0599"]

复现

想加一个异步检查,照着 Filter::layer 的样子写 AsyncFilter::layer:

tower = { version = "=0.5.3", features = ["filter", "util"] }
tokio = { version = "=1.54.1", features = ["full"] }
use tower::filter::AsyncFilter;
use tower::{service_fn, BoxError, ServiceBuilder, ServiceExt};

async fn check(user: String) -> Result<String, BoxError> {
  if user == "mallory" { Err("banned".into()) } else { Ok(user) }
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
  let echo = service_fn(|s: String| async move { Ok::<_, BoxError>(s) });
  let svc = ServiceBuilder::new()
    .layer(AsyncFilter::layer(check))
    .service(echo);
  println!("{:?}", svc.oneshot("alice".to_string()).await);
}

rustc 1.99.0 的报错(中间一段指向 filter/mod.rs 第 45 行 pub struct Filter<T, U> 的源码片段省略,它标注这个 Filter 不满足 Service<_> 和 ServiceExt<_>;note: 下面还有 &Filter<...>、&mut Filter<...> 两组同样形状的约束和长类型写入文件的提示,也省略):

error[E0599]: the method `oneshot` exists for struct `Filter<ServiceFn<{closure@...}>, _>`, but its trait bounds were not satisfied
  --> examples/afl_infer.rs:14:24
   |
14 |   println!("{:?}", svc.oneshot("alice".to_string()).await);
   |                        ^^^^^^^ method cannot be called on `Filter<ServiceFn<{closure@...}>, _>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `tower::filter::Filter<ServiceFn<{closure@examples/afl_infer.rs:10:25: 10:36}>, fn(String) -> impl std::future::Future<Output = Result<String, Box<(dyn std::error::Error + Send + Sync + 'static)>>> {check}>: Service<_>`
           which is required by `tower::filter::Filter<ServiceFn<{closure@examples/afl_infer.rs:10:25: 10:36}>, fn(String) -> impl std::future::Future<Output = Result<String, Box<(dyn std::error::Error + Send + Sync + 'static)>>> {check}>: ServiceExt<_>`

线索在类型名里:写的是 AsyncFilter::layer,报错说的却是 Filter<..>,第二个类型参数是一个返回 impl Future 的函数。

单独写一行 let _layer = AsyncFilter::layer(check);,先碰到的是另一个错误:

error[E0282]: type annotations needed
 --> examples/afl_only.rs:9:16
  |
9 |   let _layer = AsyncFilter::layer(check);
  |                ^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `AsyncFilter`
  |
help: consider specifying the generic arguments
  |
9 |   let _layer = AsyncFilter::<T, _>::layer(check);
  |                           ++++++++

layer 定义在 impl<T, U> AsyncFilter<T, U> 上,T 是内层服务的类型,layer 根本用不到它。照提示写成 AsyncFilter::<(), _>::layer(check),这一行就能编译;一旦把包出来的服务拿去用,还是上面那条 E0599(把复现程序改成 turbofish 写法跑过,报错相同)。

源码:layer 返回了同步的 FilterLayer

AsyncFilter::layer 和 Filter::layer 一字不差:

    pub fn layer(predicate: U) -> FilterLayer<U> {
        FilterLayer::new(predicate)
    }

FilterLayer 的 Layer 实现 造出 Filter<S, U>。Filter 的 Service 实现 要求 U: Predicate<Request>,而闭包和函数只有在返回 Result 时才自动实现 Predicate;check 返回的是 future,满足的是 AsyncPredicate。Layer 本身没有任何 Service 约束(见 Layer 与 Stack),所以 .layer(...)、.service(...) 都编译通过,错误推迟到第一次把它当服务用的地方。两种 filter 的机制见 Filter。

📝NOTE
冷知识:这个错从 AsyncFilter 诞生那天就在

AsyncFilter 是 #508 重写 tower::filter 时加的,第一个包含它的版本是 tower 0.4.0;那次提交里 AsyncFilter::layer 就已经返回 FilterLayer<U>。issue #597(2021 年 8 月)报告:「This seems to be a copy/paste mistake. AsyncFilter::layer returns FilterLayer, its meant to return AsyncFilterLayer.」报告人自己也在问「I wonder if fixing this would be considered a breaking change」,维护者的回复是「This is technically a breaking change, but I think it might be semver-compliant to fix it in a minor version」。

修复它的 PR #875 只改返回类型,说明里写着「This is a copy/paste slip from the original filter rework (#508)」,并把它标成破坏性变更。写这一页时(2026 年 10 月)它还没有合并。

修法

用 AsyncFilterLayer::new 或 ServiceBuilder::filter_async,两者都造出 AsyncFilter:

use tower::filter::AsyncFilterLayer;
use tower::{service_fn, BoxError, ServiceBuilder, ServiceExt};

async fn check(user: String) -> Result<String, BoxError> {
  if user == "mallory" { Err("banned".into()) } else { Ok(user) }
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
  let echo = service_fn(|s: String| async move { Ok::<_, BoxError>(s) });

  let a = ServiceBuilder::new().layer(AsyncFilterLayer::new(check)).service(echo);
  let b = ServiceBuilder::new().filter_async(check).service(echo);
  for (name, svc) in [("AsyncFilterLayer::new", a), ("filter_async", b)] {
    for user in ["alice", "mallory"] {
      let r = svc.clone().oneshot(user.to_string()).await;
      println!("{name}({user:?}) = {:?}", r.map_err(|e| e.to_string()));
    }
  }
}

依赖同上,M2 Max、rustc 1.99.0、--release,连跑 3 次输出相同:

AsyncFilterLayer::new("alice") = Ok("alice")
AsyncFilterLayer::new("mallory") = Err("banned")
filter_async("alice") = Ok("alice")
filter_async("mallory") = Err("banned")

a 和 b 能放进同一个数组,说明两种写法造出的是同一个类型 AsyncFilter<ServiceFn<..>, ..>。

❗IMPORTANT
动脑筋:同步谓词交给 AsyncFilter::layer依赖同上。
use std::any::type_name_of_val;
use tower::filter::AsyncFilter;
use tower::{service_fn, BoxError, ServiceBuilder, ServiceExt};

#[tokio::main(flavor = "current_thread")]
async fn main() {
  let echo = service_fn(|s: String| async move { Ok::<_, BoxError>(s) });
  // A synchronous predicate this time.
  let svc = ServiceBuilder::new()
    .layer(AsyncFilter::<(), _>::layer(|s: String| Ok::<_, BoxError>(s)))
    .service(echo);
  println!("{}", type_name_of_val(&svc).split('<').next().unwrap());
  println!("{:?}", svc.oneshot("bob".to_string()).await.map_err(|e| e.to_string()));
}
它能编译吗?能的话,打印哪两行?

动脑筋答案

能编译。M2 Max、rustc 1.99.0、--release,连跑 3 次输出相同:

tower::filter::Filter
Ok("bob")
  • 第一行:AsyncFilter::layer 返回 FilterLayer,造出来的是 Filter,不是 AsyncFilter。
  • 第二行:闭包返回 Result,正好满足同步的 Predicate,Filter 是一个正常的服务,请求通过。

所以确实有代码在依赖这个错误的返回类型:把同一个同步闭包交给 AsyncFilterLayer::new,用的时候就报 the method `oneshot` exists for struct `AsyncFilter<ServiceFn<{closure@...}>, {closure@...}>`, but its trait bounds were not satisfied(E0599,试过),因为同步闭包不满足 AsyncPredicate。这就是 #875 要算破坏性变更的一个具体例子。

小结

  • 0.5.3 的 AsyncFilter::layer 和 Filter::layer 完全一样,返回 FilterLayer,造出同步的 Filter。
  • 交给它一个异步谓词,.layer、.service 都能编译,第一次当服务用时报 E0599,报错里的类型是 Filter<..>;单独写成 let _layer = AsyncFilter::layer(check); 时报的是 E0282,因为 T 推不出来。
  • 修法:AsyncFilterLayer::new(pred) 或 ServiceBuilder::filter_async(pred)。
  • 这个错从 #508(0.4.0)就在,#597 报告于 2021 年,修复 PR #875 因为改返回类型属于破坏性变更,写这一页时还没合并。

💬 关联讨论

发起讨论
加载中...