8、溢出
溢出
rust中的整型有范围,这从一开始就清楚的
比如u8类型的范围就是0~255,那么如果运算时超出了这个范围,就会发生溢出
溢出在rust中是一个error,如果在C/C++等语言当中往往会被直接忽略掉,但是rust很安全,他不允许溢出随便发生
如果运算的结果 > 类型::MAX,则称为上溢,如果 < 类型::MIN,则称为下溢
无自动类型转换
在其它语言中,如果发生了溢出,可能存在自动类型转换以防止溢出的发生,python支持大整数,无限精度,其他也没有什么语言可以非常好的处理溢出了
rust的理念就是,不能完全解决这个问题,那就避免这个问题的发生
所以rust自然不支持这种东西
解决方案
我们有两种方案可以实现较好的处理溢出
- 拒绝操作
- 提出一个更好的方案处理预期外的整数类型
拒绝操作
最保守的方式就是rust默认的方式,一旦发生溢出,那么直接终止程序的执行,这个过程通过panic来实现,前面也接触到了这个panic
提出一个“明智”的结果
当算术操作的结果发生溢出时,可以选择环绕(warp around)
这其实就相当于C/C++里面默认的溢出处理方式,比如u8类型,255+1=0,MAX+1=MIN,这样子
溢出检查
rust允许选择整数溢出发生时使用的方法,该行为由 overflow-checks 配置文件设置
如果将 overflow-checks 的值被置为 true
,那么整数溢出时,rust将在运行时发生panic,如果将 overflow-checks 的值被置为 false
,那么整数溢出时,rust将 (环绕)warp around
然后就是,详细了解一下配置文件(Profiles)
Profiles(配置文件)
配置文件时一组配置选项,可以自定义Rust代码编译方式
Cargo提供了四种配置:dev,release,test和bench
dev: 运行cargo build
,cargo run
或cargo test
等命令时,都是以dev配置模式运行
release: 发布release版本时,要通过添加—release以构建release发布版,即cargo build --release
dev模式,编译起来很快,但是性能不佳,是专门用来开发与调试的。release模式在编译时,会进行漫长的优化,以确保代码的执行效率,所以编译过程会比较漫长
test: test配置是在执行cargo test
时默认选择的配置,test配置继承于dev配置
bench: bench配置是在执行cargo bench
时默认选择的配置,bench配置继承于release配置
总结:
dev | 适用于迭代开发与调试 |
---|---|
release | 优化的生产版本 |
test | 单元测试与集成测试 |
bench | 性能基准测试 |
overflow-checks
一般情况下,overflow-checks的配置是,对于dev模式是true,对于release模式是false
如果不是极端的要求性能的场景,官方还是建议我们把溢出检查都打开
不过有个问题,如果我想在某些地方启用溢出检查,某些地方不想启用溢出检查的话,这个全局配置就很不适用了
所以Rust提供了一种方法来实现自定义是否对某个细微的地方启用溢出检查
warpping_methods
比如使用warpping_add
就可以实现主动关闭溢出检查的加法了
let x = 255u8;
let y = 1u8;
let sum = x.wrapping_add(y);
assert_eq!(sum, 0);
练习
题目很简单,就是实现阶乘的无溢出检测
RustRover的代码提示挺好的,直接提示除了warpping方法有warpping_mul
pub fn factorial(n: u32) -> u32 {
let mut result: u32 = 1;
for i in 1..=n {
result = result.wrapping_mul(i);
}
result
}
这一节的学习就先到这里了