如何将 hyper::server::Server 存储为结构中的字段?

mus*_*kox 7 rust hyper

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

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 }
    }
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

正如预期的那样,错误是:

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]>`
Run Code Online (Sandbox Code Playgroud)

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

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

超级文档引用了make_service_fn返回 a的函数,MakeServiceFn但该类型不是公共的,因此我不能在inner.

小智 2

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

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

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

pub struct App<T> {
    inner: Server<AddrIncoming, T>,
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

结论

对于您的情况,我会推荐第一个,因为第二个类型参数的类型Server很难找到,并且在程序开发过程中很可能会发生变化,因此在结构上仅使用类型参数要容易得多。

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

pub struct App<T: Service> {
    inner: Server<AddrIncoming, T>,
}
Run Code Online (Sandbox Code Playgroud)

建议不要将类型参数放在结构本身上,而只将它们放在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.
}
Run Code Online (Sandbox Code Playgroud)

您也可以对这样的函数执行相同的操作:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢你的回答![添加类型参数不起作用](https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=cdd2c8af1e1c442688fc677c7e90ba9f)因为我的应用程序对于不同类型不是通用的,它使用特定类型。查找“MakeService”的类型正是我遇到的问题,它是一个返回“hyper”私有类型的闭包。 (4认同)