2016-02-17 1 views
0

У меня есть два затворов, которые захватывают ту же Vec, и я не знаю, как написать это в идиоматических Руст:Захватив ту же переменную в одном из нескольких закрытий

use std::error; 

fn get_token -> Box<Vec<u8>>() {...} 
fn do_stuff(file: &str) -> std::io::Result<i32> {...} 
fn do_other_stuff(a: &str, a: &str) -> std::io::Result<i32> {...} 

enum MyError { 
    IoError { token: Vec<u8>, reason: String), 
} 

fn consumer() -> Result<MyError,()> { 
    let token = get_token(); 

    try!(do_stuff("a") 
     .map_err(|e| MyError::IoError { token: token, reason: "foo".to_str() })); 
    try!(do_other_stuff("b", "c") 
     .map_err(|e| MyError::IoError { token: token, reason: "bar".to_str() })); 
} 

Я мог бы заменить map_err звонки с match но я действительно в шоке от этого: как я могу пройти Vec для нескольких закрытий?

+2

Возможно, я спрошу, почему вывод 'get_token',' Box > 'а не просто' Vec ' –

ответ

3

Прежде всего: Пожалуйста, убедитесь, чтобы обеспечить в будущем в MCVE, это не забава, чтобы исправить ошибки синтаксиса, прежде чем быть в состоянии воспроизвести проблему: http://is.gd/tXr7WK

Ржавчина не знает, что единственный способ второе закрытие может выполняться, если первое закрытие не запускалось и никогда не будет работать. Вы можете либо дождаться принятия, внедрения и стабилизации RFC let/else, либо вы можете создать свою ошибку в шагах, сначала создайте внутреннее закрытие, которое выполняет все операции для этой одной ошибки, не используя token, а затем запустите закрытие , затем сопоставьте ошибку с вашим пользовательским типом ошибки.

|| -> _ { 
    try!(do_stuff("a").map_err(|e| ("foo".to_owned(), e))); 
    try!(do_other_stuff("b","c").map_err(|e| ("bar".to_owned(), e))); 
    Ok(()) 
}().map_err(|(reason, e)| MyError::IoError{ token: token, reason: reason }) 

Там что-то странное происходит, когда закрытие требует, чтобы указать, что она возвращает что-то с -> _, но я не уверен, что это такое.

+0

Спасибо, я буду использовать детскую площадку в следующий раз, когда я отправлю что-нибудь. Извиняюсь. –

+0

Хорошее решение ... но о, это '|| -> _ {...}() 'pattern perl like! –

2

Вы можете использовать and_then() комбинатор, чтобы избежать дополнительного закрытия:

try!(do_stuff("a").map_err(|_| "foo") 
     .and_then(|_| 
      do_other_stuff("b","c").map_err(|_| "bar") 
     ) 
     .map_err(|e| MyError::IoError{token:token,reason:e.into()}) 
); 
3

Гораздо более простым, чтобы просто не использовать try! или закрытия:

if let Err(e) = do_stuff("a") { 
    return Err(MyError::IoError{token: token, reason: "foo".to_owned()}); 
} 
if let Err(e) = do_other_stuff("b", "c") { 
    return Err(MyError::IoError{token: token, reason: "bar".to_owned()}); 
} 

Это позволяет Rust выполнять простой анализ, как вы хотите и намного читабельнее, чем танцы через обручи.

+0

проблема заключается в том, что вы теряете значение «Ok», но так как это не требуется в этом вопросе, ваш ответ будет самым красивым. –

+1

@ker Вы можете «совместить», если хотите значение «Ok». – Veedrac

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