侧边栏壁纸
  • 累计撰写 218 篇文章
  • 累计创建 59 个标签
  • 累计收到 5 条评论

Rust-N02:数据类型

barwe
2024-10-05 / 0 评论 / 0 点赞 / 171 阅读 / 2,541 字
温馨提示:
本文最后更新于 2024-10-05,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

数据类型

整型 iN/uN

Rust 整型有:i8/u8, i16/u16, i32/u32, i64/u64, i128/u128, isize/usize

其中 iN/uN 表示该类型长度为 N bits (即 N/8 Bytes),有符号类型范围为 [-2(N-1), 2(N-1)-1],无符号类型的范围为 [0, 2^N-1]。

isize/usize 依赖于系统架构(64位还是 32 位)。

在 64 位系统中,isize 是 64 bits 即 8 Bytes,但是它并不等同于 i64

Rust 默认使用 i32 表示整型(let x = 1;),如果需要使用其他类型,需要显示指定类型(let x: i64 = 1; or let x = 1i64;)。

使用类型后缀形式(1i64)时,实际数值不能超过类型允许的范围,例如 128i8 是不合法的,127i8 是合法的。

允许使用下划线作为数字分隔符方便读书,例如 1_2_3_41234 等价,再例如 12_345_678

整型字面值 Literals

除了十进制字面值(例如 123, -123)外,还可以使用其它进制的字面量:

  • 十六进制以 0x 开头,例如 0xff255 等价
  • 八进制以 0o 开头,例如 0o377255 等价
  • 二进制以 0b 开头,例如 0b_1111_1111255 等价

此外 u8 还可以表示 单字节字符 字面量:let x: u8 = b'A';(这里只能用单引号)

整型溢出 Integer Overflow

溢出指的是变量实际接收的值超出了变量类型的范围,如将 256 赋给 i8 类型的变量。

溢出有两种处理方式:

  • 退出程序:这是 debug 模式下的默认行为
  • 进行一定的自动纠正,避免程序退出。具体的纠正方法有:
    • 在变量类型取值范围内从小到大循环取值,即 wrapping
    • 在达到最大或者最小值边界时停止取值,即 saturating

自动纠正机制在大部分情境下可能是没有意义的,因此我们需要在程序中手动检测溢出,必要时指定如何纠正溢出。

release 模式下溢出时会自动执行 wrapping 操作。

Rust 为基本操作提供了对应的变种方法用于手动处理溢出问题:

  • .wrapping_* 方法进行 wrapping 操作
  • .checked_* 方法出现溢出时会返回 None
  • .overflow_* 方法返回一个 wrapping 值和表示是否发生溢出的布尔值
  • saturating_* 方法在发生溢出时取最大或者最小值
fn main() {
    // wrapping_*
    println!("{}", 127i8.wrapping_add(2i8));
    println!("{}", 255u8.wrapping_add(2u8));
    // checked_* 溢出时返回 None
    match 255u8.checked_add(2u8) {
        None => println!("None"),
        Some(v) => println!("{v}"),
    };
    // overflow_* 返回TCW结果值和表示是否溢出的布尔值
    let (v, st) = 255u8.overflowing_add(2u8);
    println!("v={v}, is_overflow={st}");
    // saturating_* 在最大最小值处饱和处理
    println!("{}", 255u8.saturating_add(2u8));
}
-127
1
None
v=1, is_overflow=true
255

浮点数 fN

类型:f32, f64 (默认),有符号。

数值运算

整数除法会向 0 舍入到最近的整数:

  • 99 / 100 returns 0
  • -99 / 100 returns 0

取余运算:43 % 5 returns 3

布尔类型 bool

let st: bool = true;

字符类型 char

char 类型大小为 4 字节(32 bits),用来表示 Unicode 标量值。

前面提到的字面量 b'A' 本质上是整型(u8),它指的应该是 ASCII 表中定义的单字节字符。

let heart_eyed_cat = '😻';

Rust 区分单引号和双引号:单引号用于 Unicode 字符字面量,双引号用于字符串字面量。

单字节字面量中也是用的单引号:b'A'

原生复合类型:元组

let t1 = (500, 64.0, 1);
let t2: (i32, f64, u8) = (500, 64.0, 1);
let (x, y, z) = t2;
  • 元组的每个元素的类型可以不同,元组变量类型可以通过类型注解显式指定,也可以从元组值中自动推断
  • 模式 pattern:上面用来解构元组 t2(x, y, z) 就是一个模式
  • 模式匹配 pattern matching:使用模式来解构元组的这个过程就是模式匹配
  • 解构 destructure:使用模式匹配从元组中提取元素到模式中的变量中的操作就是解构
  • 元组解构时不需要指定模式中各变量的类型,因为元组本身每个元素的类型就是已知的
  • 除了模式解构外,还可以通过索引来访问元组元素,例如访问第一个元素 t2.0
  • 单元元组 unit tuple:值和类型都为 (),表达式或者函数不返回其他值时默认返回这个

原生复合类型:数组

  • 数组的每个元素的类型必须一致,可以手动指定,或者自动从值列表推断
  • 数组的长度在编译时是已知的(这点与 C++ 一致),变长数组请使用 vector 类型
  • 数组是位于栈中的单个内存块
// 从值列表推断数组类型
let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

// 指定数组类型
let a: [i32; 5] = [1, 2, 3, 4, 5];

// 创建值相同的数组
let a = [3; 5]; // 等价于 let a: [i32; 5] = [3, 3, 3, 3, 3];
  • 数组元素通过索引访问(a[0],元组是 t.0
  • 程序运行时访问超出数组索引范围的元素会引发运行时错误
0

评论区