rust stable core 参考导读 | u8

59 阅读7分钟

版本:1.90.0

参考文档:u8 - Rust

本文希望实现这样一个效果,就是看完本文后,再看 core 的参考文档,能轻松一些。

本文目前只是一个近似于草稿的版本,积极接收意见建议。

正文内容是 AI 写的。

阅读本文需要有 rust 语言的学习基础。


u8unsigned int 8 的简写,是一个常用的整数类型,范围是 0...127

1 常用方法

1.1 作为一种数字类型

在 Rust 中,u8 提供了多种算术运算方法来处理可能的溢出情况。

你可能听说过,YouTube曾因为某视频的播放量过大, i32 不够用,给显示成了一个负的数字。

方法类型返回值溢出行为使用场景
checked_*Option<u8>返回 None需要处理溢出逻辑
wrapping_*u8回绕循环计数、模运算
saturating_*u8饱和到边界UI、进度条、颜色值
overflowing_*(u8, bool)返回结果+标志需要知道是否溢出
strict_*u8panic确保无溢出的关键计算
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