Skip to content

变量

变量可变性

默认情况下, 默认情况下变量是不可变的

当变量不可变时, 这意味着一旦一个值绑定到一个变量名后, 就不能更改该值了

rust
fn main() {
  let x = 10;
  x = 20;
  println!("x is {}", x);
}
// 这个代码是无法通过编译的, 报错信息如下:
// cannot assign twice to immutable variable `x`
rust
fn main() {
  let mut x = 10;
  x = 20;
  println!("x is {}", x);
}
// 加上 mut 关键字后, 可以通过编译
// 那就证明, 现在变量是可以重新赋值的
sh
warning: value assigned to `x` is never read
 --> main.rs:2:9
  |
2 |     let x = 10;
  |         ^
  |
  = help: maybe it is overwritten before being read?
  = note: `#[warn(unused_assignments)]` on by default

error[E0384]: cannot assign twice to immutable variable `x`
 --> main.rs:3:5
  |
2 |     let x = 10;
  |         -
  |         |
  |         first assignment to `x`
  |         help: consider making this binding mutable: `mut x`
3 |     x = 20;
  |     ^^^^^^ cannot assign twice to immutable variable

error: aborting due to 1 previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0384`.
x is 10

变量的遮蔽

所谓 遮蔽(shadow) 就是说: 可以声明和前面变量具有相同名称的新变量

rust
fn main() {
    let x = 10;
    println!("x is {}", x); // 10

    let x = x + 10;
    println!("x is {}", x); // 20
}

静态变量

  1. 定义静态变量时必须声明类型
  2. 静态变量是可以修改的(但是需要在 unsafe 块中)
  3. 静态变量的作用域是整个程序运行期间
  4. 不能在函数内部定义必须在模块顶部定义
rust
static APP_SLOGAN: &str = "Rust is best language";

fn main() {
  println!("{}", APP_SLOGAN);
}

常量

  • 定义常量时必须声明类型
  • 与其他编程语言类似, 常量声明后无法修改
  • 命名规范为: 字母全部大写, 以 _ 分割单词, 如: SECONDS_IN_HOUR SECONDS_IN_DAY SECONDS_IN_WEEK
rust
// 常量可以是一个值
const SECONDS_IN_MINUTES:u32 = 60;

// 也可以是一个表达式计算的值
const SECONDS_IN_HOUR:u32 = 60 * 60;

// 也可以是一个有其他常量表的达式计算的值
const SECONDS_IN_DAY:u32 = SECONDS_IN_HOUR * 24;

fn main() {
    println!("{}, {}, {}", SECONDS_IN_MINUTES, SECONDS_IN_HOUR, SECONDS_IN_DAY);
}

数据类型

查看参考手册

标量类型(scalar)

标量(scalar)类型表示单个值

整数类型 integer

长度有符号类型无符号类型
8 位i8(-128,127)u8(0,255)
16 位i16(-32768, 32768)u16(0,65535)
32 位i32(-2147483648,2147483648)u32(0, 4294967295)
64 位i64u64
128 位i128u128
archisizeusize

isizeusize 类型取决于程序运行的计算机体系结构, 在表中表示为 arch: 若使用 64 位架构系统则为 64 位, 若使用 32 位架构系统则为 32 位

最大值, 最小值计算:

  1. 有符号

    • 最小值: -(2n - 1)
    • 最大值: 2(n - 1) - 1
  2. 无符号

    • 最小值:0
    • 最大值: 2n - 1

n 代表类型后的数字, 比如 i8 最大值就是: 2(8-1)-1 => 27 - 1 => 128 - 1 => 127

rust
fn main() {
    let i8n: i8 = -10; // -128 - 127
    let u8n: u8 = 255; // 0 - 255
    println!("{i8n}, {u8n}");

    // 如果硬要将一个超过类型最大值的数字
    // 赋值给对应类型的变量, 那么就会报错
    let out_of_range_number: i8 = 200;
}
sh
error: literal out of range for `i8`
 --> main.rs:8:35
  |
8 |     let out_of_range_number: i8 = 200;
  |                                   ^^^
  |
  = note: the literal `200` does not fit into the type `i8` whose range is `-128..=127`
  = help: consider using the type `u8` instead
  = note: `#[deny(overflowing_literals)]` on by default

error: aborting due to 1 previous error; 1 warning emitted
数字字面量示例
十进制98_222
十六进制0xff
八进制0o77
二进制0b1111_0000
字节 (仅限于 u8)b'A'
rust
fn main() {
    let n = 11; // 10 进制, 没什么好说的
    println!("n is: {}", n);

    let n = 0x10; // 16 进制的 16, 0x开头
    println!("n is: {}", n);

    let n = 0o10; // 8 进制的 8, 0o开头
    println!("n is: {}", n);

    let n = 0b10; // 2 进制的 2, 0b开头
    println!("n is: {}", n);
}

浮点型 float

比 js 设计更合理的浮点数, js 单精度的浮点数设计太变态了

长度有符号类型无符号类型
32 位f32u32
64 位f64u64
rust
fn main() {
    let f1 = 1.1;
    let f2 = 1.2;
    let f3 = f1 + f2;
    println!("f3 is: {f3}"); // 2.3
}

布尔型 bool

与其他变成语言一样, 两个取值 true false

rust
fn main() {
    let is_ok = true;
    println!("is ok {is_ok}");

    let can_i_use = false;
    println!("can i use:{can_i_use}");
}

字符类型 char

  • 存储任意一个字符

注意: 表示字符类型, 只能用 '', 不能使用""

rust
fn main() {
    let char_c: char = 'C';
    println!("char_c is {}", char_c);
}

// 如果使用双赢号就报错: 类型不匹配 mismatched types
// let char_c: char = "C";
sh
error[E0308]: mismatched types
 --> main.rs:2:24
  |
2 |     let char_c: char = "C";
  |                 ----   ^^^ expected `char`, found `&str`
  |                 |
  |                 expected due to this
  |
help: if you meant to write a `char` literal, use single quotes
  |
2 |     let char_c: char = 'C';
  |                        ~~~

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.

复合类型(compound type)

元组 tuple

rust
fn main() {
    let mut tup = (false, 11, 3.14);

    // 会自动进行类型推导,多数情况不需要手动指定
    // let tup: (bool, i32, f32) = (false, 11, 3.14);

    // 与其他编程语言的元组不同的是, rust 元组的元素是可修改的
    tup.1 = 22;

    // 通过 元组.索引 获取元素
    println!("tup 0 is:{}", tup.0);
    println!("tup 1 is:{}", tup.1); // 22
    println!("tup 2 is:{}", tup.2);

    // 通过类似 js 解构的方式来获取元素
    let (x, y, z) = tup;
    println!("x is:{}", x);
    println!("y is:{}", y);
    println!("z is:{}", z);

    // 如果访问不存在的值, 就会报错
    // println!("tup 3 is:{}", tup.3);
}
sh
error[E0609]: no field `3` on type `(bool, {integer}, {float})`
 --> main.rs:9:33
  |
9 |     println!("tup 3 is:{}", tup.3);
  |                                 ^ unknown field

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0609`.

数组 array

  1. 与元祖不同, 数组必须是相同类型的一组数据
  2. 与其他编程语言不同, rust 中的数组 具有固定长度
rust
fn main() {
    let arr = [1, 3, 5];
    // 多数情况下, 不需要手动指定类型, 会自动推导出类型
    // 手动指定格式: [数组类型; 数组长度]
    // let arr: [i32; 3] = [1, 3, 5];

    // 获取数组长度
    let len = arr.len();
    println!("arr len is:{}", len);

    // 通过索引访问元素
    println!("arr 0 is: {}", arr[0]);
    println!("arr 1 is: {}", arr[1]);
    println!("arr 2 is: {}", arr[2]);

    // 获取一个不存在的索引,就会报错: 索引越界
    // println!("arr 3 is: {}", arr[3]);

    // 解构取值
    let [x, y, z] = arr;
    println!("x is :{x}");
    println!("y is :{y}");
    println!("z is :{z}");
}
sh
error: this operation will panic at runtime
  --> main.rs:13:30
   |
13 |     println!("arr 3 is: {}", arr[3]);
   |                              ^^^^^^ index out of bounds: the length is 3 but the index is 3
   |
   = note: `#[deny(unconditional_panic)]` on by default

error: aborting due to 1 previous error
遍历数组
rust
fn main() {
    let arr = [1, 3, 5];

    // 最简单, 最直观的遍历
    let mut i = 0;
    while i < arr.len() {
        println!("arr[{}] is {}", i, arr[i]);
        i += 1;
    }
}
rust
fn main() {
    let arr = [1, 3, 5];

    // for in + ..操作符 遍历数组
    // 1. 0 表示范围的起始值, 即索引从 0 开始
    // 2. ..表示范围操作符, 用于创建一个范围, 不包括结尾(0..10 表示 0-9)
    // 3. arr.len() 表示数组的长度
    // 这个语法有点类似 python 的: for in range(0, len(arr))
    for i in 0..arr.len() {
        println!("arr[{}] is {}", i, arr[i]);
    }
}
rust
fn main() {
    let arr = [1, 3, 5];

    for item in arr.iter() {
        println!("item value is {}", item);
    }
}
rust
fn main() {
    let arr = [1, 3, 5];

    for item in arr.iter().enumerate() {
        let (i, x): (usize, &i32) = item;
        println!("array[{i}] = {x}");
    }
}

强制类型转换

基础类型只能小类型转大类型, 比如: u8 -> u32

rust
let a: u8 = 11;
println!("a: {}", a as u32); // 11

// 因为 bool 类型就2个值 0 和 1, 所以可以转 u8
let b: bool = false;
println!("b: {}", b as u8); // 0

数据类型解析

rust
fn main() {
    let x = 11;
    println!("x:{}", x);
    let s = x.to_string();             // 数字 -> 字符串

    println!("s:{}", s);
    let n = s.parse::<i32>().unwrap(); // 字符串 -> 数字
    println!("n:{}", n);
}

Released under the MIT License.