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

10

我有一个使用hyper库的程序。我希望用户能够创建一个包含内部处理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 }
    }
}

(游乐园链接)

错误就如预期的那样:

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而不使用闭包的方法?

Hyper文档提到了函数make_service_fn,它返回一个MakeServiceFn,但是该类型不是公开的,因此我无法在inner的类型中使用它。


看起来你的问题可能可以通过 How do I store a closure in a struct in Rust? 的答案得到解决。如果不行,请**[编辑]**你的问题以解释区别。否则,我们可以将此问题标记为已回答。 - Shepmaster
简而言之,重复:是的,将闭包或包含闭包的东西装箱,并创建一个带有封装 trait 的对象。 - Shepmaster
2
我大致了解Boxed Trait Objects的工作原理,但不确定如何将其应用于我的问题。Boxed闭包应该具有什么类型?具体来说,返回类型是什么? - muskox
@muskox 你解决了吗?我也有同样的问题。 - Erigami
1个回答

2

这个问题是由于类型不匹配引起的。在Rust中,类型参数是结构体类型的一部分,因此你的结构体中服务器的类型参数必须与你定义的类型参数匹配。但在你的情况下,它们并不匹配。

有两种解决方案可以解决你的问题。

为结构体的第二个服务器参数添加一个类型参数

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.
}

你也可以对这样的函数做同样的操作:

将"Original Answer"翻译成"最初的回答"
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
}

4
谢谢您的回复!添加类型参数无法解决问题,因为我的应用程序不适用于不同类型,它使用特定类型。找到MakeService类型正是我困扰的问题,它是返回hyper私有类型的闭包。 - muskox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接