2017-08-28 166 views
1

我想返回不同的IMAP連接,具體取決於secure變量,但如果我們使用SSL,則imap::client::Client返回不同的類型。 Client中的所有功能都由impl<T: Read + Write> Client<T>實現。具有相同基本結構的不同返回類型

是否有更好的方式更有效的解決方案?

use error::*; 
use imap::client::Client; 
use openssl::ssl::{SslConnectorBuilder, SslMethod, SslStream}; 
use std::net::TcpStream; 

pub enum ConnectionResult { 
    Normal(Client<TcpStream>), 
    Secure(Client<SslStream<TcpStream>>), 
} 

/// Mail account 
#[derive(Debug, Deserialize)] 
pub struct Account { 
    pub username: String, 
    pub password: String, 
    pub domain: String, 
    pub port: u16, 
    pub secure: bool, 
} 

impl Account { 
    pub fn connect(&self) -> Result<ConnectionResult> { 
     if self.secure { 
      let ssl_connector = SslConnectorBuilder::new(SslMethod::tls()) 
       .chain_err(|| "fail with ssl")? 
       .build(); 
      let mut imap_socket = Client::secure_connect(
       (self.domain.as_str(), self.port), 
       &self.domain, 
       ssl_connector, 
      ); 
      imap_socket 
       .login(&self.username, &self.password) 
       .chain_err(|| "fail when login")?; 
      Ok(ConnectionResult::Secure(imap_socket)) 
     } else { 
      let mut imap_socket = Client::connect((self.domain.as_str(), self.port))?; 
      imap_socket 
       .login(&self.username, &self.password) 
       .chain_err(|| "fail when login")?; 
      Ok(ConnectionResult::Normal(imap_socket)) 
     } 
} 

我只是想返回一個Client結構,而不是持有不同Client個枚舉:

pub fn connect<T: Read + Write>(&self) -> Result<Client<T>> { 
    // But this won't work 
} 
+0

我只是想返回客戶端結構,而不是一個不同的客戶端枚舉 – babariviere

回答

2

你的方法似乎並不壞。我的建議是使用composition:封裝你在structenum,做你想要的東西在每個方法有match

enum ConnectionResult { // not pub because intern implementation 
    Normal(Client<TcpStream>), 
    Secure(Client<SslStream<TcpStream>>), 
} 

pub struct MyClient { 
    connection_result: ConnectionResult, 
    // other fields 
} 

impl MyClient { 
    pub fn do_something(&self) { 
     match connection_result { 
      Normal(client) => // do something with normal client 
      Secure(client) => // do something with secure client 
     } 
    } 
} 

從用戶的角度來看,有兩個客戶端之間沒有什麼區別。

如果你不希望這個解決方案,您可以使用夜間-> impl功能:

#![feature(conservative_impl_trait)] 

trait MyClient { 
    // the methods you need 
} 

struct NormalClient { 
    client: Client<TcpStream>, 
    /*etc.*/ 
} 
struct SecureClient { 
    client: Client<SslStream<TcpStream>>, 
    /*etc.*/ 
} 

impl MyClient for NormalClient { /*etc.*/ } 
impl MyClient for SecureClient { /*etc.*/ } 

fn get_client() -> impl MyClient { /*etc.*/ } 
相關問題