Rust中溢出时带边界的整数运算

Rust中溢出时带边界的整数运算,rust,integer-overflow,panic,Rust,Integer Overflow,Panic,我最近遇到的问题需要基于整数类型的位对边界进行整数运算 例如,使用i32integer来执行add操作,下面是一段伪代码来展示这个想法: sum = a + b max(min(sum, 2147483647), -2147483648) // if the sum is larger than 2147483647, then return 2147483647. // if the sum is smaller than -2147483648, then return -21474836

我最近遇到的问题需要基于整数类型的位对边界进行整数运算

例如,使用
i32
integer来执行
add
操作,下面是一段伪代码来展示这个想法:

sum = a + b
max(min(sum, 2147483647), -2147483648)

// if the sum is larger than 2147483647, then return 2147483647.
// if the sum is smaller than -2147483648, then return -2147483648.
为了实现这一点,我天真地编写了以下丑陋的代码:

fn i32\u通过铸造添加处理(a:i32,b:i32)->i32{
设和:i32;
如果(a as i64+b as i64)>2147483647 as i64{
总和=2147483647;
}否则如果(a为i64+b为i64)<-2147483648为i64{
总和=-2147483648;
}否则{
总和=a+b;
}
总和
}
fn main(){
println!(“{:?}”,i32_添加_处理_通过_铸造(2147483647,1));
println!(“{:?}”,i32_添加_处理_通过_铸造(-2147483648,-1));
}
代码运行良好;但是我的六感告诉我使用类型转换是有问题的。因此,我尝试使用传统的紧急(异常)处理来处理此问题……但我坚持使用以下代码(紧急结果无法检测下溢或溢出):

使用std::panic;
fn i32 \u添加\u处理\u通过\u panic(a:i32,b:i32)->i32{
设和:i32;
让result=panic::catch|u unwind(|{a+b}).ok();
比赛结果{
Some(result)=>{sum=result},
无=>{sum=?}
}
总和
}
fn main(){
println!(“{:?}”,i32_添加_处理_由_panic(2147483647,1));
println!(“{:?}”,i32_添加_处理_由_panic(-2147483648,-1));
} 
总而言之,我有3个问题:

  • 我的类型转换解决方案对强类型语言有效吗?(如果可能,我需要解释它为什么有效或无效。)
  • 有没有其他更好的方法来处理这个问题
  • 恐慌是否可以单独处理不同的异常

  • 在这种情况下,Rust标准库有一个名为的方法,该方法支持您的用例:

    assert_eq!(10_i32.saturating_add(20), 30);
    assert_eq!(i32::MIN.saturating_add(-1), i32::MIN);
    assert_eq!(i32::MAX.saturating_add(1), i32::MAX);
    
    在内部,它作为一个组件实现


    一般来说,这些问题不打算通过恐慌和退市来解决,而只是在例外情况下进行清理。手写版本可能涉及类型转换,但只计算一次
    A作为i64+b作为i64
    。或者,这里有一个使用的版本,它在溢出时返回
    None
    ,而不是panics:

    fn saturating_add(a: i32, b: i32) -> i32 {
        if let Some(sum) = a.checked_add(b) {
            sum
        } else if a < 0 {
            i32::MIN
        } else {
            i32::MAX
        }
    }
    
    fn饱和添加(a:i32,b:i32)->i32{
    如果让一些(和)=a.检查_添加(b){
    总和
    }否则,如果a<0{
    i32::MIN
    }否则{
    i32::MAX
    }
    }
    
    您知道吗?出于性能原因,捕捉恐慌可能是个坏主意。锈菌恐慌不是设计用来作为商业例外的,应该很少被发现,如果有的话。而且,这里的铸造仅仅是一种转换,既安全又定义明确,使用它没有什么错。不同类型的指针之间的强制转换是危险的,而这些类型甚至不可能在安全锈迹中取消引用。@L.F.使用
    as
    进行类型强制转换可能会有问题,因为它会更改值。解决方法是使用不改变值的转换:
    From
    。例如,如果i64::from(a)+i64::from(b)>i64::from(i32::MAX),则将第一个条件写为
    。(也就是说,如果仅仅使用饱和算法显然不容易的话。)任何时候该值都不适合被强制转换到的类型。例如,
    -10_i32 as u32
    4294967286
    1_000_000 as i16
    -13824
    。如果您碰巧得到了错误的宽度或符号,您可能只是默默地得到了错误的值
    From
    没有这个问题,因为当转换是无损的时,整数只执行From
    。(对于容易出错的转换,您可能希望使用
    TryFrom
    ,它返回一个
    结果,您可以以任何适当的方式处理该结果。)