版本:1.90.0
参考文档:u8 - Rust
本文希望实现这样一个效果,就是看完本文后,再看 core 的参考文档,能轻松一些。
本文目前只是一个近似于草稿的版本,积极接收意见建议。
正文内容是 AI 写的。
阅读本文需要有 rust 语言的学习基础。
u8 是 unsigned int 8 的简写,是一个常用的整数类型,范围是 0...127。
1 常用方法
1.1 作为一种数字类型
在 Rust 中,u8 提供了多种算术运算方法来处理可能的溢出情况。
你可能听说过,YouTube曾因为某视频的播放量过大, i32 不够用,给显示成了一个负的数字。
| 方法类型 | 返回值 | 溢出行为 | 使用场景 |
|---|---|---|---|
checked_* | Option<u8> | 返回 None | 需要处理溢出逻辑 |
wrapping_* | u8 | 回绕 | 循环计数、模运算 |
saturating_* | u8 | 饱和到边界 | UI、进度条、颜色值 |
overflowing_* | (u8, bool) | 返回结果+标志 | 需要知道是否溢出 |
strict_* | u8 | panic | 确保无溢出的关键计算 |
unchecked_* | u8 | 未定义行为 | 性能关键且确定无溢出 |
1.1.1 Checked 运算 (checked_*)
返回 Option<u8>,如果溢出则返回 None
let a: u8 = 200;
let b: u8 = 100;
// checked_add - 安全加法
assert_eq!(a.checked_add(b), None); // 溢出,返回 None
assert_eq!(100u8.checked_add(50), Some(150)); // 未溢出
// checked_sub - 安全减法
assert_eq!(5u8.checked_sub(10), None); // 下溢
assert_eq!(10u8.checked_sub(5), Some(5));
// checked_mul, checked_div, checked_rem 等
1.1.2 Wrapping 运算 (wrapping_*)
发生溢出时回绕(wrap around)
let a: u8 = 200;
let b: u8 = 100;
// wrapping_add - 回绕加法
assert_eq!(a.wrapping_add(b), 44); // 200 + 100 = 300, 300 % 256 = 44
assert_eq!(255u8.wrapping_add(1), 0); // 回绕到 0
// wrapping_sub - 回绕减法
assert_eq!(0u8.wrapping_sub(1), 255); // 下溢回绕到 255
1.1.3 Saturating 运算 (saturating_*)
发生溢出时饱和到边界值
let a: u8 = 200;
let b: u8 = 100;
// saturating_add - 饱和加法
assert_eq!(a.saturating_add(b), 255); // 达到最大值
assert_eq!(100u8.saturating_add(50), 150); // 正常计算
// saturating_sub - 饱和减法
assert_eq!(5u8.saturating_sub(10), 0); // 达到最小值
assert_eq!(10u8.saturating_sub(5), 5); // 正常计算
1.1.4 Overflowing 运算 (overflowing_*)
返回 (u8, bool) 元组,包含结果和是否溢出的标志,默认回绕
let a: u8 = 200;
let b: u8 = 100;
// overflowing_add - 带溢出标志的加法
assert_eq!(a.overflowing_add(b), (44, true)); // 结果和溢出标志
assert_eq!(100u8.overflowing_add(50), (150, false)); // 无溢出
// 可以解构结果
let (result, overflowed) = 255u8.overflowing_add(1);
assert_eq!(result, 0);
assert_eq!(overflowed, true);
1.1.5 Strict 运算
这是较新的特性,在 debug 和 release 模式下都对溢出 panic
// 要确保安全性
#![feature(strict_overflow_ops)]
assert_eq!((u8::MAX - 2).strict_add(1), u8::MAX - 1);
/*
// 若溢出则 panic
#![feature(strict_overflow_ops)]
let _ = (u8::MAX - 2).strict_add(3);
*/
1.1.6 Unchecked 运算 (unchecked_*)
不安全操作,假设不会溢出,由程序员保证安全
// unsafe 代码块中可用
unsafe {
let a: u8 = 100;
let b: u8 = 50;
// unchecked_add - 不检查的加法
let result = a.unchecked_add(b); // 假设不会溢出
assert_eq!(result, 150);
}
1.2 与 ascii 码的交互
C 语言是喜欢把 char 当作数字的。在 rust 也可以这么搞。
参考 ASCII - MDN Web 文档术语表:Web 相关术语的定义 | MDN
graph LR
A[u8 字节] --> C[ASCII 字符]
C --> C
C --> A
1.2.1 u8 作为 ASCII 码进行字符转换
1.2.1.1 基本转换方法
// u8 转 char (ASCII 字符)
let ascii_a: u8 = 65;
let char_a: char = ascii_a as char;
println!("{}", char_a); // 输出 'A'
// char 转 u8 (仅限于 ASCII 字符)
let char_b: char = 'B';
let ascii_b: u8 = char_b as u8;
println!("{}", ascii_b); // 输出 66
1.2.1.2 安全的字符转换
// 使用 TryFrom trait 进行安全转换
use std::convert::TryFrom;
let value: u8 = 65;
if let Ok(character) = char::try_from(value) {
println!("安全转换: {}", character); // 'A'
}
// 对于非 ASCII 值会失败
let non_ascii: u8 = 200; // 扩展 ASCII,但不是有效 Unicode
match char::try_from(non_ascii) {
Ok(c) => println!("有效字符: {}", c),
Err(_) => println!("不是有效 Unicode 字符"),
}
1.2.2 从 ASCII 到数字
1.2.2.1 单个数字字符转数值
// 方法1: 使用 char 的方法
let digit_char: u8 = b'5';
let number1 = (digit_char as char).to_digit(10).unwrap();
println!("{}", number1); // 5
// 方法2: 直接算术运算
let digit_char: u8 = b'7';
let number2 = digit_char - b'0';
println!("{}", number2); // 7
// 方法3: 使用 checked 运算避免错误
fn safe_ascii_to_digit(byte: u8) -> Option<u8> {
if byte.is_ascii_digit() {
Some(byte - b'0')
} else {
None
}
}
assert_eq!(safe_ascii_to_digit(b'9'), Some(9));
assert_eq!(safe_ascii_to_digit(b'a'), None);
1.2.2.2 字符串转数字
// ASCII 数字字符串转整数
fn ascii_string_to_number(s: &[u8]) -> Option<u32> {
let mut result = 0u32;
for &byte in s {
if !byte.is_ascii_digit() {
return None;
}
// 使用 checked 运算防止溢出
result = result.checked_mul(10)?;
result = result.checked_add((byte - b'0') as u32)?;
}
Some(result)
}
assert_eq!(ascii_string_to_number(b"123"), Some(123));
assert_eq!(ascii_string_to_number(b"12a"), None);
assert_eq!(ascii_string_to_number(b"9999999999"), None); // 溢出
1.2.2.3 十六进制 ASCII 转数字
fn ascii_hex_to_value(byte: u8) -> Option<u8> {
match byte {
b'0'..=b'9' => Some(byte - b'0'),
b'a'..=b'f' => Some(byte - b'a' + 10),
b'A'..=b'F' => Some(byte - b'A' + 10),
_ => None,
}
}
assert_eq!(ascii_hex_to_value(b'C'), Some(12));
assert_eq!(ascii_hex_to_value(b'9'), Some(9));
assert_eq!(ascii_hex_to_value(b'x'), None);
1.2.3 从数字到 ASCII
1.2.3.1 数字转 ASCII 数字字符
// 单个数字转 ASCII
fn digit_to_ascii(digit: u8) -> Option<u8> {
if digit < 10 {
Some(b'0' + digit)
} else {
None
}
}
assert_eq!(digit_to_ascii(5), Some(b'5'));
assert_eq!(digit_to_ascii(10), None);
// 使用 saturating_add 确保安全
fn safe_digit_to_ascii(digit: u8) -> u8 {
b'0' + digit.min(9) // 限制在 0-9 范围内
}
1.2.3.2 数字转 ASCII 字符串
// 整数转 ASCII 字符串
fn number_to_ascii_string(mut num: u32) -> Vec<u8> {
if num == 0 {
return vec![b'0'];
}
let mut digits = Vec::new();
while num > 0 {
let digit = (num % 10) as u8;
digits.push(b'0' + digit);
num /= 10;
}
digits.reverse();
digits
}
assert_eq!(number_to_ascii_string(123), b"123");
assert_eq!(number_to_ascii_string(0), b"0");
1.2.3.3 数字转十六进制 ASCII
fn value_to_ascii_hex(value: u8) -> [u8; 2] {
let nibble1 = value >> 4; // 高4位
let nibble2 = value & 0x0F; // 低4位
let hex1 = if nibble1 < 10 {
b'0' + nibble1
} else {
b'A' + (nibble1 - 10)
};
let hex2 = if nibble2 < 10 {
b'0' + nibble2
} else {
b'A' + (nibble2 - 10)
};
[hex1, hex2]
}
assert_eq!(value_to_ascii_hex(255), [b'F', b'F']);
assert_eq!(value_to_ascii_hex(10), [b'0', b'A']);
3 作为数据
介绍 u8 作为 1 字节数据的位操作方法。
3.1 字节序转换
3.1.1 大端序和小端序转换
let number: u8 = 0xAB; // 10101011
// 对于 u8,这些方法实际上没有效果(因为只有1字节)
// 但在代码中保持一致性很重要
let big_endian = number.to_be(); // 0xAB - 大端序
let little_endian = number.to_le(); // 0xAB - 小端序
let native = number.to_ne(); // 0xAB - 本机字节序
assert_eq!(big_endian, 0xAB);
assert_eq!(little_endian, 0xAB);
assert_eq!(native, 0xAB);
// 从字节数组转换(实际应用)
let bytes = [0xABu8];
let from_be = u8::from_be_bytes(bytes); // 0xAB
let from_le = u8::from_le_bytes(bytes); // 0xAB
3.2 位计数方法
3.2.1 统计 1 的个数
let value: u8 = 0b1011_0101; // 181
// count_ones - 统计二进制中 1 的数量
let ones = value.count_ones();
println!("1的个数: {}", ones); // 5
// count_zeros - 统计二进制中 0 的数量
let zeros = value.count_zeros();
println!("0的个数: {}", zeros); // 3
3.2.2 前导和尾随的 0/1
let value1: u8 = 0b1110_0000; // 224
let value2: u8 = 0b0000_0111; // 7
let value3: u8 = 0b1111_1111; // 255
// trailing_ones - 从最低位开始连续的 1 的数量
println!("trailing_ones: {}", value2.trailing_ones()); // 3
println!("trailing_ones: {}", value1.trailing_ones()); // 0
// trailing_zeros - 从最低位开始连续的 0 的数量
println!("trailing_zeros: {}", value1.trailing_zeros()); // 5
println!("trailing_zeros: {}", value2.trailing_zeros()); // 0
// leading_ones - 从最高位开始连续的 1 的数量
println!("leading_ones: {}", value1.leading_ones()); // 3
println!("leading_ones: {}", value3.leading_ones()); // 8
// leading_zeros - 从最高位开始连续的 0 的数量
let value4: u8 = 0b0001_1010; // 26
println!("leading_zeros: {}", value4.leading_zeros()); // 3
3.3 位操作和反转
3.3.1 位反转
let original: u8 = 0b1011_0010; // 178
let reversed = original.reverse_bits();
println!("原始: {:08b}", original); // 10110010
println!("反转: {:08b}", reversed); // 01001101
// 验证反转操作
assert_eq!(reversed, 0b0100_1101); // 77
3.3.2 字节旋转
let value: u8 = 0b1110_0001; // 225
// rotate_left - 向左旋转指定位数
let rotated_left = value.rotate_left(2);
println!("左旋2位: {:08b}", rotated_left); // 10000111
// rotate_right - 向右旋转指定位数
let rotated_right = value.rotate_right(3);
println!("右旋3位: {:08b}", rotated_right); // 00111100
3.4 位检查和设置
3.4.1 检查特定位
let flags: u8 = 0b1010_1100; // 172
// 检查第 n 位是否为 1(从低位开始,0-based)
println!("第2位: {}", flags & (1 << 2) != 0); // true
println!("第3位: {}", flags & (1 << 3) != 0); // false
// 使用位掩码检查多个位
let mask = 0b0000_1111; // 低4位掩码
let low_bits = flags & mask;
println!("低4位: {:04b}", low_bits); // 1100