变量
变量可变性
默认情况下, 默认情况下变量是不可变的
当变量不可变时, 这意味着一旦一个值绑定到一个变量名后, 就不能更改该值了
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
}
静态变量
- 定义静态变量时必须声明类型
- 静态变量是可以修改的(但是需要在 unsafe 块中)
- 静态变量的作用域是整个程序运行期间
- 不能在函数内部定义必须在模块顶部定义
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 位 | i64 | u64 |
128 位 | i128 | u128 |
arch | isize | usize |
isize
和 usize
类型取决于程序运行的计算机体系结构, 在表中表示为 arch
: 若使用 64 位架构系统则为 64 位, 若使用 32 位架构系统则为 32 位
最大值, 最小值计算:
有符号
- 最小值: -(2n - 1)
- 最大值: 2(n - 1) - 1
无符号
- 最小值: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 位 | f32 | u32 |
64 位 | f64 | u64 |
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
- 与元祖不同, 数组必须是相同类型的一组数据
- 与其他编程语言不同, 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);
}