Вариантразматывать безопасно? - PullRequest
0 голосов
/ 12 сентября 2018

Я реализую оболочку библиотеки C, которая принимает обратные вызовы, и обратные вызовы будут реализованы в Rust. Учитывая, что паника в Rust при вызове из C является неопределенным поведением , я хочу уловить любую потенциальную панику в Rust до того, как она попадет в C.

Я читал о std::panic::catch_unwind. Оболочка чувствительна к производительности, и я бы предпочел избегать использования таких типов, как Mutex. Я хотел бы сохранить свой результат в Option<i32> и установить его на Some(value) в случае, когда нет паники. None будет означать, что функция не была выполнена успешно, и, следовательно, должна была возникнуть паника.

Option<i32> Размотка безопасна? Если нет, то при каких условиях возникнет проблема? Могу ли я обернуть его в std::panic::AssertUnwindSafe?

Вот пример, где я использовал AssertUnwindSafe, чтобы обернуть все замыкание.

use std::panic::{self, AssertUnwindSafe};

fn random_function_that_might_panic(a: i32) -> i32 {
    if a == 42 {
        panic!("did you forget a towel?");
    }
    a * 2
}

fn do_not_panic(a: i32) {
    let mut result = None;
    let unwind_state = panic::catch_unwind(AssertUnwindSafe(|| {
        result = Some(random_function_that_might_panic(a)); // get result, but this could panic
    }));
    match unwind_state {
        Ok(()) => {
            match result {
                Some(value) => {
                    println!("Result: {:?}", value);
                }
                None => {
                    // this should never happen...
                    println!("No result but no panic?");
                }
            }
        }
        Err(e) => {
            println!("caught panic: {:?}", e);
        }
    }
}

fn main() {
    do_not_panic(1);
    do_not_panic(2);
    do_not_panic(3);
    do_not_panic(42);
}

(см. Выше на детской площадке .)

Я не мог понять, как обернуть просто Option<i32> в AssertUnwindSafe, поэтому здесь я завернул всю затвор. Как бы мне обернуть только Option<i32>?

1 Ответ

0 голосов
/ 12 сентября 2018

Безопасно ли разматывать Option<i32>?

Да.Нет смысла задавать человеку этот вопрос, когда вы можете задать компилятору:

fn implements<T: std::panic::UnwindSafe>() {}

fn main() {
    implements::<Option<i32>>();
}

Ваш реальный вопрос должен быть:

Is &mut Option<i32>Развернуть безопасно?

Это не так, но вы, вероятно, уже знали это.Я предполагаю, что вы получили эту ошибку компилятора, прежде чем вы добавили AssertUnwindSafe, который говорит вам, что это небезопасно:

error[E0277]: the trait bound `&mut std::option::Option<i32>: std::panic::UnwindSafe` is not satisfied in `[closure@src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`
  --> src/main.rs:12:24
   |
12 |     let unwind_state = panic::catch_unwind(|| {
   |                        ^^^^^^^^^^^^^^^^^^^ the type &mut std::option::Option<i32> may not be safely transferred across an unwind boundary
   |
   = help: within `[closure@src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`, the trait `std::panic::UnwindSafe` is not implemented for `&mut std::option::Option<i32>`
   = note: required because it appears within the type `[closure@src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`
   = note: required by `std::panic::catch_unwind`

Я бы написал ваш код как этот, для чего он стоит:

fn do_not_panic(a: i32) {
    let result = panic::catch_unwind(|| random_function_that_might_panic(a)).ok();

    match result {
        Some(value) => {
            println!("Result: {:?}", value);
        }
        None => {
            println!("caught panic");
        }
    }
}

Нет изменяемых переменных, нет дополнительной вложенности, нет комментариев "этого никогда не должно быть".

См. Также:

...