【问题标题】:How to store a hyper::server::Server as a field in a struct?如何将 hyper::server::Server 作为字段存储在结构中?
【发布时间】:2019-10-21 11:54:28
【问题描述】:

我有一个在内部使用 hyper 的库。我希望用户能够创建一个 App,其中包含一个内部处理 HTTP 连接的 Server

use hyper::server::conn::AddrIncoming;
use hyper::server::Server;
use hyper::service::service_fn_ok;
use std::net::SocketAddr;

pub struct App {
    inner: Server<AddrIncoming, ()>,
}

impl App {
    pub fn new() -> Self {
        let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
        let inner = Server::bind(&addr).serve(|| service_fn_ok(|_req| unimplemented!()));

        App { inner }
    }
}

(Playground link)

如预期的那样,错误是:

error[E0308]: mismatched types
  --> src/lib.rs:15:15
   |
15 |         App { inner }
   |               ^^^^^ expected (), found closure
   |
   = note: expected type `hyper::server::Server<_, ()>`
              found type `hyper::server::Server<_, [closure@src/lib.rs:13:47: 13:88]>`

没有很好的文档记录,但Server 的第二个类型参数是它使用的MakeService 类型。

我不知道如何引用inner 类型的闭包。有什么方法可以让我可以将闭包装箱以使代码编译?有没有办法手动实现MakeService,而不是使用闭包?

超文档引用了函数make_service_fn,它返回一个MakeServiceFn,但是类型不是公开的,所以我不能在inner的类型中使用它。

【问题讨论】:

  • 看来How do I store a closure in a struct in Rust? 的答案可能会回答您的问题。如果没有,请edit您的问题来解释差异。否则,我们可以将此问题标记为已回答。
  • TL;DR 副本:是的,将闭包或包含闭包的东西装箱,并创建一个装箱的 trait 对象。
  • 我了解盒装特征对象的一般工作原理,但我不确定如何将它们应用于我遇到的问题。盒装封口应该有什么类型?具体来说,返回类型是什么?
  • @muskox 你解决了吗?我有同样的问题。

标签: rust hyper


【解决方案1】:

问题是由于类型不匹配造成的。在 Rust 中,类型参数是结构类型的一部分,因此结构中服务器的类型参数必须与您在结构中定义的类型参数匹配。在你的情况下,他们没有。

您的问题有 2 个解决方案。

将第二个服务器参数的类型参数添加到您的结构中

pub struct App<T> {
    inner: Server<AddrIncoming, T>,
}

现在您将能够为服务器的第二个类型参数创建具有不同类型的应用程序

查找您正在创建的服务器的第二个参数的类型

在你的例子中,第二个参数的类型是 ``,所以你可以像这样声明你的结构:

type Service = ?; // This is really hard to find in this case.
pub struct App {
    inner: Server<AddrIncoming, Service>,
}

结论

在你的情况下,我会推荐第一个,因为Server 的第二个类型参数的类型很难找到,并且在你的程序开发过程中很可能会发生变化,所以只有一个类型要容易得多结构上的参数。

但是,有时如果您不知道服务器的类型参数没有实现某些特征,您将无法在服务器上使用某些方法,因此您可以将这些特征添加到您的类型参数中,如下所示:

pub struct App<T: Service> {
    inner: Server<AddrIncoming, T>,
}

建议不要将类型参数放在结构本身上,只放在impl块上:

pub struct App<T> {
    inner: Server<AddrIncoming, T>,
}

impl App<T: Service> {
   // Here you'll be able to use the method from Server where T has to be a Service.
}

你也可以对这样的函数做同样的事情:

pub struct App<T> {
    inner: Server<AddrIncoming, T>,
}

fn some_function(app: App<T: Service>) {
   // Here you'll be able to use the method from Server where T has to be a Service
}

【讨论】:

  • 感谢您的回答! Adding a type parameter doesn't work 因为我的应用程序对于不同类型不是通用的,它使用特定类型。查找MakeService 的类型正是我遇到的问题,它是一个返回hyper 私有类型的闭包。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多