0

我有一个 tokio tcp 服务器,它应该将单个传入连接传递给服务。如何正确处理间接,以便服务器可以使用不同的服务实现?我求助于tokio::spawn()在服务内部调用,因为我找不到间接返回未来的方法。

这是我正在做的一个最小示例:

extern crate tokio;

use tokio::prelude::future::FutureResult;
use tokio::prelude::*;

struct Subject {
    name: String,
}    
struct MySvc {
    name: String,
}    
trait Svc6 {
    fn handle6(&self, subject: Subject);
}
impl Svc6 for MySvc {
    fn handle6(&self, subject: Subject) {
        let task = future::ok((self.name.to_string(), subject))
            .and_then(|(n, s)| Ok(println!("#6. Hi {}! My name is {}.", s.name, n)));
        tokio::spawn(task);
    }
}   

#[test]
fn svc6_works() {
    let svc = MySvc {
        name: "Zorg".into(),
    };
    let subj = Subject {
        name: "Gandalf".into(),
    };
    tokio::run(future::ok(svc).and_then(|s| Ok(s.handle6(subj))));
}

虽然这适用于间接,但我担心我tokio是否正确使用。每个Svc6impl 都必须调用tokio::spawn()而不是仅仅返回一个任务。如果服务器处理生成,我也更喜欢它,因为它可能需要处理优先级和排队。也很难测试不返回任何内容的方法。

这是我一直在尝试的其他事情的游乐场链接。要查看完整的上下文,请转到Samotop 源和接受 fn。

如果 trait 方法实现可以返回 impl Trait,那就太好了!

trait Svc1 {
    fn handle1(&self, subject: Subject) -> Future<Item = (), Error = ()>;
}
impl Svc1 for MySvc {
    // error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
    fn handle1(&self, subject: Subject) -> impl Future<Item = (), Error = ()> {
        future::ok(println!(
            "#1. Hi {}! My name is {}.",
            subject.name, self.name
        ))
    }
}
4

2 回答 2

2

这里的期货或 Tokio 没有什么特别之处,这只是 Rust。在深入复杂的异步编程世界之前,我强烈建议您学习如何使用基本的 Rust 功能。从Rust 编程语言开始,特别是关于trait 对象的部分:

trait Svc {
    fn handle(&self, subject: Subject) -> Box<Future<Item = (), Error = ()> + Send>;
}

impl Svc for MySvc {
    fn handle(&self, subject: Subject) -> Box<Future<Item = (), Error = ()> + Send> {
        Box::new(future::ok(println!(
            "#1. Hi {}! My name is {}.",
            subject.name, self.name
        )))
    }
}

#[test]
fn svc_works() {
    let svc = MySvc {
        name: "Zorg".into(),
    };
    let subj = Subject {
        name: "Gandalf".into(),
    };
    tokio::run(svc.handle(subj))
}

这被明确称为Tokio 文档中关于如何返回Future.

如果 trait 方法实现可以返回 impl Trait!

据我所知,这是不可能的。每个返回 an 的函数都返回impl Trait一个可能不同大小的具体类型。特定的调用者不知道要为任意 trait 实现分配多少堆栈空间。

也可以看看:

于 2018-07-06T14:40:08.530 回答
0

从 trait 实现中返回 impl Trait 是不行的,因为我必须(再次?)知道我们需要一个具体的大小。Box解决问题可能会奏效,但我一直在思考。所以我把事情稍微转了转,而是做了Servicereturn a Sink,这将收到该物品。然后我将流转发到接收器中。似乎这可以用以下方式包裹tokio::spawn()

use futures::StartSend;
use tokio;
use tokio::io;
use tokio::prelude::*;

struct Subject {
    name: String,
}

trait Svc {
    type Receiver;
    type Error;
    fn start(&self) -> Self::Receiver;
}

struct MySvc {
    name: String,
}

impl Svc for MySvc {
    type Receiver = MyReceiver;
    type Error = io::Error;
    fn start(&self) -> Self::Receiver {
        MyReceiver::new(&self.name)
    }
}

struct MyReceiver {
    name: String,
    pending: Box<Future<Item = (), Error = ()> + Send>,
}

impl MyReceiver {
    fn say_hi(&self, subject: Subject) {
        println!("Hi {}! It's {}.", subject.name, self.name)
    }
    fn new(name: impl ToString) -> Self {
        Self {
            name: name.to_string(),
            pending: Box::new(future::ok(())),
        }
    }
}

impl Future for MyReceiver {
    type Item = Self;
    type Error = Self;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        Ok(Async::Ready(MyReceiver::new(&self.name)))
    }
}

impl Sink for MyReceiver {
    type SinkItem = Subject;
    type SinkError = ();
    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        self.say_hi(item);
        Ok(AsyncSink::Ready)
    }
    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        Ok(Async::Ready(()))
    }
}

#[test]
fn try() {
    let svc = MySvc { name: "jOy".into() };

    let task = future::ok(svc)
        .and_then(|s| {
            s.start().and_then(|r| {
                let subject = Subject {
                    name: "Miou".into(),
                };
                let task = stream::once(Ok::<Subject, ()>(subject))
                    .forward(r)
                    .map_err(|_| ())
                    .and_then(|_| Ok(()));
                tokio::spawn(task);
                Ok(())
            })
        })
        .and_then(|_| Ok(()))
        .map_err(|_| ());

    tokio::run(task);
}
于 2018-07-06T17:12:02.693 回答