期望一个实现了 `Fn` 特质的闭包,但这个闭包只实现了 `FnOnce`。

3

我想使用Hyper实现一个Web服务。我从hello world示例中复制了代码并成功运行。但是,当我尝试向HelloWorld结构体中添加数据访问对象时,出现了错误,我不知道如何修复它。如何向Hyper服务器添加trait成员?

extern crate futures;
extern crate hyper;

use futures::future::Future;
use hyper::header::ContentLength;
use hyper::server::{Http, Request, Response, Service};

trait Dao {}

struct MysqlDao;

impl Dao for MysqlDao {}

struct HelloWorld {
    dao: Box<Dao>,
}

const PHRASE: &'static str = "Hello, World!";

impl Service for HelloWorld {
    // boilerplate hooking up hyper's server types
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    // The future representing the eventual Response your call will
    // resolve to. This can change to whatever Future you need.
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, _req: Request) -> Self::Future {
        // We're currently ignoring the Request
        // And returning an 'ok' Future, which means it's ready
        // immediately, and build a Response with the 'PHRASE' body.
        Box::new(futures::future::ok(
            Response::new()
                .with_header(ContentLength(PHRASE.len() as u64))
                .with_body(PHRASE),
        ))
    }
}

fn main() {
    let addr = "127.0.0.1:3000".parse().unwrap();
    let dao = Box::new(MysqlDao);
    let server = Http::new().bind(&addr, || Ok(HelloWorld { dao })).unwrap();
    server.run().unwrap();
}

错误信息:

错误信息:

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
  --> src/main.rs:44:42
   |
44 |     let server = Http::new().bind(&addr, || Ok(HelloWorld { dao })).unwrap();
   |                              ----        ^^^^^^^^^^^^^^^^^^^^^^^^^
   |                              |
   |                              the requirement to implement `Fn` derives from here
   |
note: closure is `FnOnce` because it moves the variable `dao` out of its environment
  --> src/main.rs:44:61
   |
44 |     let server = Http::new().bind(&addr, || Ok(HelloWorld { dao })).unwrap();
   |                                                             ^^^

不清楚你具体在问什么。编译器告诉你必须提供一个满足一定限制的类型,而你没有这样做。也许你正在寻找何时闭包实现Fn、FnMut和FnOnce?对于在处理程序之间共享内容,也许你想要如何在Hyper处理程序之间共享HashMap - Shepmaster
1
@Shepmaster 非常感谢。我查看了您提供的链接,但我认为这些与我的情况不符。问题出在“实现Fn特质的闭包”,我不知道如何在HelloWorld中修复它! - llxxbb
1
第二个链接非常接近你的问题,如果你完全理解了第一个链接,你应该能够将解决方案适应到第二个链接中。换句话说,第一个链接解释了为什么会出现编译器错误,而第二个链接则解释了如何修复它。 - Sebastian Redl
1
@SebastianRedl,我仔细阅读了这些链接,并且知道它们所说的内容,但是我就是无法让它工作。你能帮我修复一下代码吗?我会非常感激! - llxxbb
1个回答

2

我对HelloWorld结构体进行了以下更改:

struct HelloWorld<'a> {
    dao: &'a Dao,
}

我把let server语句改成了以下内容:
let server = Http::new()
    .bind(&addr, move || Ok(HelloWorld { dao: &dao }))
    .unwrap();

整个代码:
extern crate futures;
extern crate hyper;

use futures::future::Future;
use hyper::header::ContentLength;
use hyper::server::{Http, Request, Response, Service};

trait Dao {}

struct MysqlDao;

impl Dao for MysqlDao {}

struct HelloWorld<'a> {
    dao: &'a Dao,
}

const PHRASE: &'static str = "Hello, World!";

impl<'a> Service for HelloWorld<'a> {
    // boilerplate hooking up hyper's server types
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    // The future representing the eventual Response your call will
    // resolve to. This can change to whatever Future you need.
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, _req: Request) -> Self::Future {
        // We're currently ignoring the Request
        // And returning an 'ok' Future, which means it's ready
        // immediately, and build a Response with the 'PHRASE' body.
        Box::new(futures::future::ok(
            Response::new()
                .with_header(ContentLength(PHRASE.len() as u64))
                .with_body(PHRASE),
        ))
    }
}

fn main() {
    let addr = "127.0.0.1:3000".parse().unwrap();
    let dao = MysqlDao;
    let server = Http::new()
        .bind(&addr, move || Ok(HelloWorld { dao: &dao }))
        .unwrap();
    server.run().unwrap();
}

HelloWorld 中,您可以使用 &'a Dao 而不是 Box<&'a Dao>。这里没有理由对引用进行盒装。 - Francis Gagné

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