ToB企服应用市场:ToB评测及商务社交产业平台

标题: 29. 干货系列从零用Rust编写正反向代理,异步回调(async trait)的使用 [打印本页]

作者: 飞不高    时间: 2024-1-3 06:55
标题: 29. 干货系列从零用Rust编写正反向代理,异步回调(async trait)的使用
wmproxy

wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透,后续将实现websocket代理等,会将实现过程分享出来,感兴趣的可以一起造个轮子
项目地址

国内: https://gitee.com/tickbh/wmproxy
github: https://github.com/tickbh/wmproxy
关于 ++trait++

  trait是Rust中的概念,类似于其他语言中的接口(interface)。
  在Rust中不存在继承的概念,所有关于结构体的拓展功能全部均由trait来代替。比如std::io::Read这是一个关于io的trait,在TcpStream中和在File中均实现了该功能,这样子如果上层只关心读操作的,我们就可以将其转化成std::io::Read的一个对象,比如io: std::io::Read,后面我们也可以把他包裹成BufferReader等实现功能的转化。
为什么不在Rust中使用继承

下面举下例子,设计关于车的通用基类,能跑能停等
  1. public class BaseCar {
  2.   //... 省略其他属性和方法...
  3.   public void run() { //... }
  4.   public void stop() { //... }
  5. }
复制代码
一开始自行车都很完美,接下来设计摩托车,摩托车需要加油,那么基类被改成
  1. public class BaseCar {
  2.   //... 省略其他属性和方法...
  3.   public void run() { //... }
  4.   public void stop() { //... }
  5.   public void refuel() { //... }
  6. }
复制代码
但是自行车又没有加油的需求
  1. // 自行车
  2. public class Bicycle extends BaseCar {
  3. //... 省略其他属性和方法...
  4. public void refuel() {
  5.      throw new UnSupportedMethodException("我不需要加油!");
  6. }
  7. }
复制代码
如果接下来又有修理引擎的接口,那基类又得加repairEngine的接口。自行车继承这个基类将会产生严重的负担,不继承又得重新写一些关于基础能力的函数,又会增加重复代码。
那么接下来是以trait方案的实现
  1. pub trait Base {
  2.    fn run(&self);
  3.    fn stop(&self);
  4. }
  5. pub trait Refuel {
  6.    fn refuel(&mut self);
  7. }
  8. pub trait RepairEngine {
  9.    fn repair_engine(&mut self);
  10. }
复制代码
那么自行车只需要实现Base能力,然后摩托车在自行车的基础上实现Refuel及RepairEngine即可实现解耦。
异步的trait

在程序中均使用的是异步(async)编程,那么我们可能需要将trait实现成:
  1. pub trait Base {
  2.    async fn run(&self);
  3.    async fn stop(&self);
  4. }
复制代码
当我们如此写的时候编译器就会提示我们:
  1. functions in traits cannot be declared `async`
  2. `async` trait functions are not currently supported
  3. consider using the `async-trait` crate: https://crates.io/crates/async-trait
  4. see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more informationrustcClick for full compiler diagnostic
复制代码
原来异步的trait实现还没有进入到stable阶段,暂时只能有预览版即nightly版本进行使用。
那么本文将探讨该功能在未stable前如何实现异步的trait。
假如返回一个异步的Future
  1. trait Base {
  2.     type FetchData<'a>: std::future::Future<Output = String> + 'a where Self: 'a;
  3.     fn run<'a>(&'a self) -> Self::FetchData<'a>;
  4. }
复制代码
当然控制Poll的方式相当的麻烦,只要在对性能要求极高的情况下在进行此操作。
预期的官方实现

在最新的Beta或者nightly版本中可以用#![feature(async_fn_in_trait)]来启用该能力,那么我们就可以如下编程:
  1. trait Base {
  2.     type FetchData<'a>: /* 将要何种类型呢?? */;
  3.     fn run<'a>(&'a self) -> Self::FetchData<'a>;
  4. }
复制代码
这样子就和普通的实现没有什么差别了。
实现该功能的难点

理论上来说,一个异步只有你在调用await的时候他才会真正的被调用,如果在此前有引用对话的存在,那么他的生命周期管理才是比较麻烦的存在。
小结

当前的Rust版本为1.74.0,好消息的是当前async trait已经Beta Channel了,如果不出意外的话下一次发布版本的稳定版将会拥有该能力了。该功能的官方实现将会给异步编程的带来极大的方便。让async/await能力越来越强。预期2023年末就可以直接使用了。下一章节我们将讲async trait在项目中的应用。
点击 [关注][在看][点赞] 是对作者最大的支持

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4