logoProsperBao

Rust 类型

2022-09-12 05 · 10min

Rust 中的变量声明

和 js/ts 类似不可变的数据都是用 const 修饰,但是 Rust 中的 const 修饰的变量必须是常量,不能是变量。

也不能通过添加 mut 来让 const 变量变成可变变量。

const a = 1;
const b = a + 1;

Rust 中的变量(let)默认是不可变的,如果需要声明可变变量,需要使用 mut 关键字。

fn main() {
  let a = 1;
  let mut b = 2;
  b = 3;
  println!("a: {}, b: {}", a, b);
}

隐藏

当一个 let 没有用 mut 修饰,但是又想让值改变,可以重新用 let 声明一次。

这样相当于重新创建了一个变量,拿到之前的数据计算之后赋值给这个变量。

也可以用 {} 创建一个临时作用域,等作用域结束之后,这个变量就会恢复原来的值。

fn main() {
  let a = 1; // 1
  let a = a + 1;// 2
  println!("a: {}", a); // 2
  {
    let a = 4; // 这里发生了隐藏,并且这个变量只在这个作用域内有效
    println!("a: {}", a); // 4
  }
  println!("a: {}", a); // 2
}

Rust 中的数据类型

Rust 中的数据类型分为两种,一种是标量类型,一种是复合类型。

标量类型

整数

数据类型范围:

  • 有符号: -(2n - 1) 到 2n - 1 - 1
  • 无符号: 0 到 2n - 1
长度有符号无符号
8-biti8u8
16-biti16u16
32-biti32u32
64-biti64u64
128-biti128u128
archisizeusize

arch 长度的范围是根据当前计算机系统的架构来决定的,如果是 64 位系统,那么 isizeusize 的长度就是 64 位。

数值之间允许使用 _ 分隔,方便阅读。

fn main() {
  let a = 1_000_000;
  println!("a: {}", a);
}

允许在数字后面显示的指定类型

fn main() {
  let a = 1u32;
  println!("a: {}", a);
}

允许直接使用十六进制、八进制、二进制、单字节字符

fn main() {
  let a = 0xff;
  let b = 0o77;
  let c = 0b1111_0000;
  let d = b'A';
  println!("a: {}, b: {}, c: {}, d: {}", a, b, c, d);
}

数字字面值例子
Decimal (十进制)98_222
Hex (十六进制)0xff
Octal (八进制)0o77
Binary (二进制)0b1111_0000
Byte (单字节字符)(仅限于u8)b’A’

浮点数

原生的浮点数类型有两种,f32f64,默认是 f64。遵从 IEEE-754 标准表示。

fn main() {
  let a = 2.0; // f64
  let b: f32 = 3.0; // f32
  println!("a: {}, b: {}", a, b);
}

布尔类型

布尔类型只有两个值,truefalse。类型定义字符串是 bool

fn main() {
  let a = true;
  let b: bool = false;
  println!("a: {}, b: {}", a, b);
}

字符类型

Rust的 char 类型是语言中最原生的字母类型。

char 类型的大小是 4 个字节,也就是 32 位,并代表了一个 Unicode 标量值。

拼音字母,中文、日文、韩文等字符,emoji 以及零长度的空白字符都是有效的 char 值。Unicode 标量值包含从 U+0000U+D7FFU+E000U+10FFFF 在内的值。

fn main() {
  let a = 'a';
  let b = 'A';
  let c = '中';
  let d = '😀';
  println!("a: {}, b: {}, c: {}, d: {}", a, b, c, d);
}

复合类型

在 Rust 中数据的属性访问是有限制的,每个类型的访问方式都不一样,不能混用。

元组类型

元组是一个将多个其他类型的值组合进一个复合类型的主要方式。元组长度固定:一旦声明,它们的长度不能增长或缩小。

元组中的每一个位置都有一个类型,而且这些不同值的类型也不必是相同的。

可是使用类似的声明方式解构元组,将元组中的值绑定到变量上。

fn main() {
  let a: (i32, f64, u8) = (500, 6.4, 1);
  println!("a: {:?}", a); // {:?} 可以打印结构体
  let (x, y, z) = a; // 类似于 JS 的解构
  println!("x: {}, y: {}, z: {}", x, y, z);
}

也可以通过类似数组下标的方式访问元组中的值,但是不能使用 [] 去索引。

fn main() {
  let a: (i32, f64, u8) = (500, 6.4, 1);
  let x = a.0;
  let y = a.1;
  let z = a.2;
  println!("x: {}, y: {}, z: {}", x, y, z);
}

不带任何值的元组有个特殊的名称,叫做 单元(unit) 元组。这种值以及对应的类型都写作 (),表示空值或空的返回类型。如果表达式不返回任何其他值,则会隐式返回单元值。

数组

数组和元组类似,不过数组中的每个元素的类型必须相同。数组是固定长度的:一旦声明,它们的长度不能增长或缩小。

建议在不确定数组是否会改变的情况下使用 vector 来替代数组类型。vector 比数组类型更加灵活。

如果确定数组长度不会变更,可以使用数组类型,这样可以提升性能。

fn main() {
  let a = [1, 2, 3, 4, 5];
  println!("a: {:?}", a);
  let b: [i32; 5] = [1, 2, 3, 4, 5]; 
  println!("b: {:?}", b);
  let c = [3; 5]; // 可以通过在方括号中指定初始值加分号再加元素个数的方式来创建一个每个元素都为相同值的数组
  println!("c: {:?}", c); // [3, 3, 3, 3, 3] 
}

可以通过 [] 运算符来访问数组中的元素,但是不能使用 . 运算符。

fn main() {
  let a = [1, 2, 3, 4, 5];
  let first = a[0];
  let second = a[1];
  println!("first: {}, second: {}", first, second);
}