【问题标题】:Rust: use common trait type for different streams (tcp stream, tls stream)Rust:对不同的流使用通用特征类型(tcp 流、tls 流)
【发布时间】:2021-09-19 18:48:08
【问题描述】:

在我拥有std::net::TcpStreamnative_tls::TlsStream<TcpStream> 的情况下,我面临动态特征的编译器错误。我的算法思路如下:

  1. 在 var "tcp" 中创建 TCP 流
  2. 如果方案是 https => 用新的TlsStream<TcpStream> 替换相同的变量。
  3. 在流​​上写入和接收数据。

我需要的重要特征是std::io::Readstd::io::Write。因此我想,我只是将我的“tcp”变量建模为Box<dyn Read + Write>。但无论我如何尝试,我总是遇到编译错误。您可以在下面看到一个无法编译的最小示例。

use std::net::{IpAddr, Ipv4Addr, TcpStream};
use std::io::{Write as IoWrite, Read as IoRead};
use native_tls::TlsConnector;

fn main() {
    let use_https = true;
    // IP of "example.com".
    let ip_addr = std::net::IpAddr::V4(Ipv4Addr::new(85, 13, 155, 159));
    let port = if use_https { 443 } else { 80 };
    let tcp_stream = TcpStream::connect((ip_addr, port)).unwrap();
    let tcp_stream = maybe_connect_to_tls(tcp_stream, use_https);
}

fn maybe_connect_to_tls(tcp: TcpStream, use_https: bool) -> Box<dyn IoRead + IoWrite> {
    if use_https {
        let tls = TlsConnector::new().unwrap();
        let tcp = tls.connect("example.com", tcp).unwrap();
        Box::new(tcp)
    } else {
        Box::new(tcp)
    }
}

Playground link

这是我尝试编译时遇到的错误:

error[E0225]: only auto traits can be used as additional traits in a trait object
  --> src/main.rs:14:78
   |
14 | fn maybe_connect_to_tls(tcp: TcpStream, use_https: bool) -> Box<dyn IoRead + IoWrite> {
   |                                                                     ------   ^^^^^^^ additional non-auto trait
   |                                                                     |
   |                                                                     first non-auto trait
   |
   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}`
   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>

我也尝试了maybe_connect_to_tls&lt;T&gt;(tcp: TcpStream, use_https: bool) -&gt; Box&lt;T&gt; where T: IoWrite + IoRead + ?Sized,但无论我尝试什么都会导致其他编译失败..

知道如何解决这个问题吗?我想要一个通用的流对象,它应该对应用程序不可见,具体实现是什么。

【问题讨论】:

    标签: rust


    【解决方案1】:

    For Rust internal reasons,你的 trait 对象只能包含一个非auto trait。但是,您可以简单地创建一个依赖于 ReadWrite 特征的特征:

    use std::net::{IpAddr, Ipv4Addr, TcpStream};
    use std::io::{Write as IoWrite, Read as IoRead};
    use native_tls::TlsConnector;
    
    trait ReadAndWrite: IoRead + IoWrite {
    }
    
    impl <T: IoRead + IoWrite> ReadAndWrite for T {
    }
    
    fn main() {
        let use_https = true;
        // IP of "example.com".
        let ip_addr = std::net::IpAddr::V4(Ipv4Addr::new(85, 13, 155, 159));
        let port = if use_https { 443 } else { 80 };
        let tcp_stream = TcpStream::connect((ip_addr, port)).unwrap();
        let tcp_stream = maybe_connect_to_tls(tcp_stream, use_https);
    }
    
    fn maybe_connect_to_tls(tcp: TcpStream, use_https: bool) -> Box<dyn ReadAndWrite> {
        if use_https {
            let tls = TlsConnector::new().unwrap();
            let tcp = tls.connect("example.com", tcp).unwrap();
            Box::new(tcp)
        } else {
            Box::new(tcp)
        }
    }
    

    Playground link

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-10
      • 2020-01-28
      • 1970-01-01
      • 2021-10-13
      • 2021-07-10
      • 2012-04-26
      • 2011-12-20
      相关资源
      最近更新 更多