add
普通加法运算 (
+
):- 不会进行溢出检查,如果发生溢出,会直接导致程序 panic。
let a: usize = 1; let b: usize = 2; let result = a + b;
wrapping_add
方法:- 执行加法运算,如果发生溢出,会返回结果的低位(模运算),不会 panic。
let a: usize = usize::MAX; let b: usize = 1; let result = a.wrapping_add(b); // Result: 0
checked_add
方法:- 执行加法运算,如果发生溢出,会返回
None
,否则返回Some(result)
。
let a: usize = usize::MAX; let b: usize = 1; let result = a.checked_add(b); // Result: None
- 执行加法运算,如果发生溢出,会返回
saturating_add
方法:- 执行加法运算,如果发生溢出,会返回最大值
usize::MAX
,不会 panic。
let a: usize = usize::MAX; let b: usize = 1; let result = a.saturating_add(b); // Result: usize::MAX
- 执行加法运算,如果发生溢出,会返回最大值
overflowing_add
方法:- 执行加法运算,如果发生溢出,会返回一个包含结果和溢出标志的元组
(result, bool)
。
let a: usize = usize::MAX; let b: usize = 1; let (result, overflow) = a.overflowing_add(b); // Result: (0, true)
- 执行加法运算,如果发生溢出,会返回一个包含结果和溢出标志的元组
示例代码
以下是一个示例代码展示了以上方法的使用:
fn main() {
let a: usize = usize::MAX;
let b: usize = 1;
// 普通加法(会 panic)
// let result = a + b;
// wrapping_add
let wrap_result = a.wrapping_add(b);
println!("wrapping_add result: {}", wrap_result);
// checked_add
match a.checked_add(b) {
Some(result) => println!("checked_add result: {}", result),
None => println!("checked_add overflowed"),
}
// saturating_add
let saturating_result = a.saturating_add(b);
println!("saturating_add result: {}", saturating_result);
// overflowing_add
let (overflowing_result, overflowed) = a.overflowing_add(b);
println!("overflowing_add result: {}, overflowed: {}", overflowing_result, overflowed);
}
输出结果
wrapping_add result: 0
checked_add overflowed
saturating_add result: 18446744073709551615
overflowing_add result: 0, overflowed: true
解释
普通加法:
- 未启用,若启用则会导致 panic,因为
usize::MAX + 1
会溢出。
- 未启用,若启用则会导致 panic,因为
wrapping_add
:- 结果为 0,因为
usize::MAX + 1
溢出后的低位结果是 0。
- 结果为 0,因为
checked_add
:- 返回
None
,表示加法溢出。
- 返回
saturating_add
:- 返回
usize::MAX
,表示饱和结果。
- 返回
overflowing_add
:- 返回
(0, true)
,表示结果为 0,并且发生了溢出。
- 返回
Overflowing Explanation
let a: usize = usize::MAX;
let b: usize = 1;
let result = a.wrapping_add(b); // Result: 0
usize::MAX
represents the maximum value that can be stored in ausize
. On a 64-bit system, this value is2^64 - 1
(or18446744073709551615
).- When you add
1
tousize::MAX
usingwrapping_add
, the operation wraps around to0
because the maximum value has been exceeded.
Diagram
Here's a step-by-step illustration of the wrapping addition process:
Step 1: Initial Values
a = 2^64 - 1
(18446744073709551615)b = 1
a: 18446744073709551615 (Binary: 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111)
b: 1 (Binary: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001)
Step 2: Perform Addition
- Add the binary values of
a
andb
.
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
+ 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
----------------------------------------------------------------------------
100000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Step 3: Wrap Around
- Since the result exceeds the maximum value that can be represented by
usize
(which is 64 bits long), the operation wraps around, discarding the carry bit (most significant bit).
100000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
- After discarding the carry bit:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
- The result is
0
.
Final State
result = 0
let a: usize = usize::MAX; // 18446744073709551615
let b: usize = 1; // 1
let result = a.wrapping_add(b); // Result: 0