本文属于我的 Rust 学习笔记 系列。来源:原子之音。
视频
代码
变量与不可变性
变量基础
- Rust 使用
let
关键字声明变量。
- Rust 支持类型推导,如果推导不出来会在编译时报错。也可显式指定。
let x: i32 = 5;
- 变量一般使用蛇形命名法(即下划线),枚举和结构体使用帕斯卡命名法(全大写)。
- 如果变量声明了但是没有用,可以在变量名前面添加一个下划线,这样就不会报错。
- 支持强制类型转换。
let a = 3.1; let b = a as i32;
- 打印变量,基础类型默认都支持了,其他类型需要实现特质。
println!("val: {}", x);
println!("val: {x}");
不可变变量
rust 的变量默认是不可变的!
不可变性是 rust 实现可靠性和安全性的关键,有效防止数据竞争和并发问题。
如果希望可变,需要使用mut
关键字。
Shawowing
Rust 允许隐藏变量。意思是可以声明一个与前一个变量同名的新变量(值、类型、可变性均可改变)。
这个变量是隐藏了,而不是消失了,具体可以看下面的例子。
例子
fn main() {
let _nice_count = 100; let _nice_number: i64 = 54;
let mut _count = 3;
_count = 4;
let x = 5;
{
let x = 10;
println!("inner x : {}", x); } println!("Outer x: {x}"); let x = "hello"; println!("New x : {x}"); let mut x = "this";
println!("x: {x}"); x = "that";
println!("Mut x: {x}"); }
const 与 static
常量和静态变量的名称通常应全部大写,且在单词间加下划线。他们的区别如下:
常量 const
常量的值必须是编译时已知的常量表达式,必须制定类型和值。
常量被直接作用于底层编译结果,而不是简单的字符替换。
作用域是块级,只在声明的作用域内可见。
静态变量 static
静态变量是在运行时分配内存的。
静态变量是变量,并非不可变的,可在unsafe
代码段中修改。
应尽量避免使用unsafe
。
生命周期是整个程序的运行时间。
例子
static MY_STATIC: i32 = 42;
static mut MY_MUT_STATIC: i32 = 42;
fn main() {
const SECOND_HOUR: usize = 3_600;
const SECOND_DAY: usize = 24 * SECOND_HOUR;
{
const SE: usize = 1_000;
println!("{SE}");
}
println!("{}", SECOND_DAY);
println!("{MY_STATIC}");
unsafe {
MY_MUT_STATIC = 32;
println!("{MY_MUT_STATIC}");
}
}
基础数据类型
类型 | 描述 | 子类型 |
整型 | 有符号整型 | i8,i16,i32(默认推断),i64,i128 |
| 无符号整型 | u8,u16,u32,u64,u128 |
| 平台决定大小整型 | usize,isize |
浮点型 | 浮点数 | f32,f64(强烈建议使用) |
布尔型 | true/false | bool |
字符型 | 使用单引号表示,可以表示Unicode表情 | char |
例子
fn main() {
let a1 = -125;
let a2 = 0xFF;
let a3 = 0o13;
let a4 = 0b10;
println!("{a1} {a2} {a3} {a4}"); println!("u32 max: {}", u32::MAX); println!("u32 min: {}", u32::MIN); println!("i32 max: {}", i32::MAX); println!("i32 min: {}", i32::MIN); println!("usize max: {}", usize::MAX); println!("isize is {} bytes", std::mem::size_of::<isize>()); println!("usize is {} bytes", std::mem::size_of::<usize>()); println!("u64 is {} bytes", std::mem::size_of::<u64>()); println!("i64 is {} bytes", std::mem::size_of::<i64>()); println!("i32 is {} bytes", std::mem::size_of::<i32>());
let f1: f32 = 1.23234;
let f2: f64 = 9.88888;
println!("Float are {:.2} {:.2}", f1, f2);
let is_ok = true;
let can_ok: bool = false;
println!("is ok? {is_ok} can ok? {can_ok}"); println!(
"is ok or can ok ?{}, can ok and is ok? {}",
is_ok || can_ok,
is_ok && can_ok
); let char_c = 'C';
let emo_char = '😀';
println!("You Get {char_c} feel {emo_char}");
println!("{}", emo_char as usize); println!("{}", emo_char as i32); }
元组和数组
相同点:
- 都是复合类型(Compound Types,Vec Map这些是集合类型 Collection Types)
- 长度固定
- 都可以设置成可变的(mut)
不同点:
- 元组(Tuples)是不同数据类型的复合数据
- 数组(Arrays)是同一类型的复合数据
数组
数组是固定长度的同构集合。
创建方式:
- [a, b, c]
- [value: size] 长度为 size 初始化值为 value 的数组
获取元素: arr[index]
获取长度: arr.len()
可以放在 for 循环中遍历。
元组
元组是固定长度的异构集合。
空元组是函数的默认返回值。
获取元素: tup.index
没有 length。
例子
fn main() {
let tup = (0, "hi", 3.4);
println!("tup elements {} {} {}", tup.0, tup.1, tup.2);
let mut tup2 = (0, "hi", 3.4);
println!("tup2 elements {} {} {}", tup2.0, tup2.1, tup2.2);
tup2.1 = "f"; println!("tup2 elements {} {} {}", tup2.0, tup2.1, tup2.2);
let tup3 = ();
println!("tup3 {:?}", tup3);
println!("Array");
let mut arr = [11, 12, 34];
arr[0] = 999;
println!("arr len {} first element is {}", arr.len(), arr[0]);
for elem in arr {
println!(" {}", elem);
}
let ar = [2; 3];
for i in ar {
println!("{}", i); }
let arr_item = [1, 2, 3];
let tup_item = (2, "ff");
println!("arr: {:?}", arr_item);
println!("tup: {:?}", tup_item); let arr_ownership = arr_item;
let tup_ownership = tup_item;
println!("arr: {:?}", arr_item);
println!("tup: {:?}", tup_item);
let a = 3;
let _a = a;
println!("{a}");
let string_item = String::from("aa");
let _string_item = string_item; }