rust 是否有替代版本可以使用std::panic::catch_unwind进行可变引用?

92vpleto  于 2023-02-23  发布在  其他
关注(0)|答案(2)|浏览(125)

为了解释我的问题,我附上了一个示例代码,而不是我的真实的项目来显示错误。

fn divide(x: &mut i32, y: &mut i32) -> i32 {
    assert!(*y != 0, "Attempted to divide by zero");
    *x / *y
}

#[test]
fn test_divide() {
    let mut x = 10;
    let mut y = 2;
    assert_eq!(divide(&mut x, &mut y), 5);
    let mut x = 10;
    let mut y = -2;
    assert_eq!(divide(&mut x, &mut y), -5);

    let result = std::panic::catch_unwind(|| divide(&mut x, &mut 0));
    assert!(result.is_err());
    let err = result.unwrap_err();
    let msg = err.downcast_ref::<&'static str>().unwrap();
    let mssss = "Attempted to divide by zero";
    assert_eq!(msg, &mssss);
}

在最后一个例子中,因为x和0是test_divide中的可变引用,所以我不能使用这个catch_unwind。
是否有其他方法可以捕获此错误?谢谢
我尝试更改项目中的可变引用,以便可以使用此catch_unwind,但它破坏了许多其他代码

xzv2uavs

xzv2uavs1#

对于传递给catch_unwind的闭包,可以使用move语义,或者使用#[should_panic]

pub fn divide(x: &mut i32, y: &mut i32) -> i32 {
    assert!(*y != 0, "Attempted to divide by zero");
    *x / *y
}

#[cfg(test)]
mod tests {
    use super::divide;

    #[test]
    fn test_divide() {
        let mut x = 10;
        let mut y = 2;
        assert_eq!(divide(&mut x, &mut y), 5);
        let mut x = 10;
        let mut y = -2;
        assert_eq!(divide(&mut x, &mut y), -5);

        let result = std::panic::catch_unwind(move || divide(&mut x, &mut 0));
        assert!(result.is_err());
        let err = result.unwrap_err();
        let msg = err.downcast_ref::<&'static str>().unwrap();
        let mssss = "Attempted to divide by zero";
        assert_eq!(msg, &mssss);
    }
    
    #[test]
    #[should_panic(expected = "Attempted to divide by zero")]
    fn test_divide2() {
        let mut x = 10;
        divide(&mut x, &mut 0);
    }   
}

Playground.

wgeznvg7

wgeznvg72#

可变引用的问题在于它们不是UnwindSafe,这是因为数据可能有不变量,这些不变量会在函数执行过程中暂时中断,然后恢复。如果我们在它们中断时感到恐慌,那么一切都很好--除非我们稍后发现恐慌,在这种情况下,我们可以观察到中断的不变量。
如果你确定你没有任何不变量可以被违反,你可以用AssertUnwindSafe Package 你的闭包:

#[test]
fn test_divide() {
    let mut x = 10;
    let mut y = 2;
    assert_eq!(divide(&mut x, &mut y), 5);
    let mut x = 10;
    let mut y = -2;
    assert_eq!(divide(&mut x, &mut y), -5);

    let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| divide(&mut x, &mut 0)));
    assert!(result.is_err());
    let err = result.unwrap_err();
    let msg = err.downcast_ref::<&'static str>().unwrap();
    let mssss = "Attempted to divide by zero";
    assert_eq!(msg, &mssss);
}

相关问题