首页 > 解决方案 > 如何为 UnixStream 和 TcpStream 创建多态类型

问题描述

我有一个名为 Connection 的结构,它接收 atokio::net::TcpStream或 atokio::net::UnixStream以与远程服务器对话。鉴于 Rust 没有构造函数,我在我的结构中添加了一个静态 new() 方法并在那里执行身份验证握手,然后将流的实例传递给 Connection 的新实例并将其从 new() 返回给我的最终用户。

我的问题是如何创建一个可以设置为 UnixStream 或 TcpStream 的临时文件,以便我可以在进行握手的消息交换期间对其进行操作。由于 UnixStream 和 TcpStream 没有共同的父级,我不知道如何实现这一点:

pub struct Configuration {
  tcp_socket: Option<SocketAddr>,
  unix_socket: Option<PathBuf>,
}

pub(crate) struct Connection {
  tcp: Option<TcpStream>,
  unix: Option<UnixStream>,
}

impl Connection {

  pub(crate) async fn new(configuration: &Configuration) -> Result<Connection, Box<dyn std::error::Error>> {
    let mut stream;
    if configuration.unix_socket().is_some() {
      stream = UnixStream::connect(configuration.unix_socket().unwrap()).await?;
    } else {
      stream = TcpStream::connect(configuration.tcp_socket().unwrap()).await?;
    }
    // Handshake code goes here...

    let conn = Connection {
      tcp: Some(stream),
      unix: None,
    };

    Ok(conn)
}

标签: rustrust-tokio

解决方案


您可以使用这样的枚举:

pub(crate) enum Connection{
  Tcp(TcpStream),
  Unix(UnixStream),
}

并且match无论您在哪里访问它或为具有通用功能的两个流实现一个特征。这个特征可以被视为一个泛型,它将在编译时评估它是哪个版本。

最小的例子:

pub(crate) trait ExampleStream{
  fn connect<A>(address: A) -> Result<Self, Error>;
}

enum 选项最接近您到目前为止所写的内容,因此我建议您这样做。


推荐阅读