2016-07-22 4 views
4

У меня есть функция get_url_content и не заботятся об ошибках (это всего лишь тест). Он возвращает Option<String>.Являются ли вложенные спички плохой практикой в ​​идиоматической ржавчине?

extern crate hyper; 

use std::io::Read; 
use hyper::client::Client; 

fn get_url_content(url: &str) -> Option<String> { 
    let client = Client::new(); 
    let mut s = String::new(); 

    match client.get(url).send() { 
     Ok(mut res) => { 
      match res.read_to_string(&mut s) { 
       Ok(_) => { 
        Some(s) 
       }, 
       Err(_) => { 
        None 
       } 
      } 
     }, 
     Err(_) => { 
      None 
     } 
    } 
} 

Эта функция работает нормально, но я считаю ее непростой для чтения. Я думаю, что есть несколько лучших практик в этом случае, чтобы сделать его более читаемым. Являются ли вложенные совпадения плохой практикой (например, callback hell в JS), и если да, то как этого избежать?

ответ

5

Самый простой способ сделать вещи немного чище, это отбросить некоторые фигурные скобки:

match client.get(url).send() { 
    Ok(mut res) => 
     match res.read_to_string(&mut s) { 
      Ok(_) => Some(s), 
      Err(_) => None, 
     }, 
    Err(_) => None, 
} 

Внутренний матч может быть выражена немного очистителя возможно как

match client.get(url).send() { 
    Ok(mut res) => 
     res.read_to_string(&mut s).ok().map(|_| s), 

    Err(_) => None, 
} 

Это наводит на мысль, используя map на внешнем типа (чтобы получить Result<Option<_>, _>), а затем падает результат с .unwrap_or(None)

client.get(url).send() 
     .map(|mut res| res.read_to_string(&mut s).ok().map(|_| s)) 
     .unwrap_or(None) 
+0

Безразлично» t '.map (| mut res | res.read_to_string (& mut s) .ok(). map (| _ | s)) 'fail, потому что' s' заимствовано с изменением и возвращается в том же выражении? –

+0

Это работает. Thx для этого пошагового ответа, это помогает мне лучше понять Rust. –

+0

@ChrisEmerson Нет, так как время жизни выхода не зависит от заимствования. – Veedrac

4

Result и Option есть отличные методы для упрощения создания кода.

fn get_url_content(url: &str) -> Option<String> { 
    let client = Client::new(); 

    let res = client.get(url) 
        .send() 
        .ok() // Convert to Option, discarding error 
        .and_then(|mut res| { 
         let mut s = String::new(); 
         let result = res.read_to_string(&mut s); 
         result.ok().map(|_| s) 
        } 
      }) 
} 

Я рекомендую смотреть через документацию для Result и Option; существуют методы для большинства комбинаций преобразований между ними и действуют как на успех, так и на половину ошибки.

Если вы можете изменить get_url_content вернуть Result, я рекомендовал бы, что (см the error handling documentation. С вашим собственным типом ошибки и некоторых реализациях From функция становится (

fn get_url_content(url: &str) -> Result<String, MyError> { 
    let client = Client::new(); 
    let mut s = String::new(); 

    let got = try!(client.get(url)); 
    let sent = try!(got.send()); 
    try!(sent.read_to_string(s)); 
    Ok(s) 
} 

и, возможно, даже проще с . новый ? оператор

Смежные вопросы