如何用期货引入特征间接?
How to introduce trait indirection with futures?
我有一个 tokio tcp 服务器,它应该将单独的传入连接交给服务。我如何正确处理间接寻址以便服务器可以使用不同的服务实现?我已求助于在服务内部调用 tokio::spawn()
,因为我找不到 return 间接访问未来的方法。
这是我正在做的一个最简单的例子:
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
。每个 Svc6
impl 都必须调用 tokio::spawn()
而不仅仅是 return 执行任务。我也更喜欢服务器是否处理生成,因为它可能需要处理优先级和排队。也很难测试不 return 任何东西的方法。
这里是 the other things I've been trying 的游乐场 link。
要查看完整上下文,请转到 Samotop source 并接受 fn。
如果 trait 方法实现可以 return 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
))
}
}
futures 或 Tokio 没有什么特别之处,这只是 Rust。我强烈建议您在深入异步编程的复杂世界之前学习如何使用基本的 Rust 功能。从 The Rust Programming Language, specicially the section on trait objects:
开始
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))
}
这被明确称为 the Tokio documentation on how to return a Future
的第一个建议。
if trait method implementation could return impl Trait!
据我所知,这是不可能的。 returns 和 impl Trait
returns 可能不同大小的具体类型的每个函数。特定的调用者不知道要为任意特征实现分配多少堆栈 space。
另请参阅:
- What is the correct way to return an Iterator (or any other trait)?
- Sending trait objects between threads in Rust
从 trait 实现中返回 impl Trait 是不行的,因为我必须(再次?)学习我们需要一个具体的大小。 Box
整理一下可能会奏效,但我一直在思考。所以我稍微扭转了局面,将 Service
return 改为 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);
}
我有一个 tokio tcp 服务器,它应该将单独的传入连接交给服务。我如何正确处理间接寻址以便服务器可以使用不同的服务实现?我已求助于在服务内部调用 tokio::spawn()
,因为我找不到 return 间接访问未来的方法。
这是我正在做的一个最简单的例子:
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
。每个 Svc6
impl 都必须调用 tokio::spawn()
而不仅仅是 return 执行任务。我也更喜欢服务器是否处理生成,因为它可能需要处理优先级和排队。也很难测试不 return 任何东西的方法。
这里是 the other things I've been trying 的游乐场 link。 要查看完整上下文,请转到 Samotop source 并接受 fn。
如果 trait 方法实现可以 return 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
))
}
}
futures 或 Tokio 没有什么特别之处,这只是 Rust。我强烈建议您在深入异步编程的复杂世界之前学习如何使用基本的 Rust 功能。从 The Rust Programming Language, specicially the section on trait objects:
开始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))
}
这被明确称为 the Tokio documentation on how to return a Future
的第一个建议。
if trait method implementation could return impl Trait!
据我所知,这是不可能的。 returns 和 impl Trait
returns 可能不同大小的具体类型的每个函数。特定的调用者不知道要为任意特征实现分配多少堆栈 space。
另请参阅:
- What is the correct way to return an Iterator (or any other trait)?
- Sending trait objects between threads in Rust
从 trait 实现中返回 impl Trait 是不行的,因为我必须(再次?)学习我们需要一个具体的大小。 Box
整理一下可能会奏效,但我一直在思考。所以我稍微扭转了局面,将 Service
return 改为 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);
}