Skip to content

udbmnm/rust-learn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust 学习笔记

  • println! 会自动推导出具体的类型
  • rust 里面的“赋值”叫变量绑定更能体现所有权的概念
  • 变量在默认不可变,加上 mut 将变量声明为可变
  • 可变变量最大的好处就是使用上的灵活性和性能上的提升
  • 使用下划线开头忽略未使用的变量
fn main() {
    let _x = 5;
    let y = 10; //这里会报错
}
  • let 可以使用变量解构赋值,和 JS 很像
let (a, mut b): (bool,bool) = (true, false);
//在 Rust 1.59 版本后,我们可以在赋值语句的左式中使用元组、切片和结构体模式了
let (a, b, c, d, e);
(a, b) = (1, 2);
// _ 代表匹配一个值,但是我们不关心具体的值是什么,因此没有使用一个变量名而是使用了 _
[c, .., d, _] = [1, 2, 3, 4, 5];
Struct { e, .. } = Struct { e: 5 };
//使用 += 的赋值语句还不支持解构式赋值
  • 常量不允许使用 mut。常量不仅仅默认不可变,而且自始至终不可变,因为常量在编译完成后,已经确定它的值
  • 常量使用 const 关键字而不是 let 关键字来声明,并且值的类型必须标注
  • Rust 常量的命名约定是全部字母都使用大写,并使用下划线分隔单词 const MAX_POINTS: u32 = 100_000;
  • 变量遮蔽,就是普通的同名变量会覆盖前面的变量名,新变量类型不同也没事,相当于生成全新的变量,旧变量不可访问,局部同名变量只能覆盖局部变量

这和 mut 变量的使用是不同的,第二个 let 生成了完全不同的新变量,两个变量只是恰好拥有同样的名称,涉及一次内存对象的再分配 ,而 mut 声明的变量,可以修改同一个内存地址上的值,并不会发生内存对象的再分配,性能要更好。

  • 避免在浮点数上测试相等性,和 JS 类似的精度问题
fn main() {
  // 断言0.1 + 0.2与0.3相等
  assert!(0.1 + 0.2 == 0.3);
}
  • 有返回值就是表达式,表达式不能包含分号。这一点非常重要,一旦你在表达式后加上分号,它就会变成一条语句,再也不会返回一个值。

  • 表达式可以成为语句的一部分,例如 let y = 6 中,6 就是一个表达式,它在求值后返回一个值 6(有些反直觉,但是确实是表达式)。

  • 栈是后进先出,使用堆必须先在堆上分配内存,然后返回指向堆内存地址的指针存入栈中

  • 栈数据往往可以直接存储在 CPU 高速缓存中,而堆数据只能存储在内存中。访问堆上的数据比访问栈上的数据慢,因为必须先访问栈再通过栈上的指针来访问堆内存

所有权原则

  • Rust 中每一个值都被一个变量所拥有,该变量被称为值的所有者
  • 一个值同时只能被一个变量所拥有,或者说一个值只能拥有一个所有者
  • 当所有者(变量)离开作用域范围时,这个值将被丢弃(drop)
  • 任何基本类型的组合可以 Copy ,不需要分配内存或某种形式资源的类型是可以 Copy 的,如果一个类型拥有 Copy 特征,一个旧的变量在被赋值给其他变量后仍然可用
fn main() {
  let x = 5;
  let y = x;
  println!("x = {}, y = {}", x, y);
}
  • 引用使用&x, let y = &x; 解引用使用 *y

  • 可变引用同时只能存在一个

let mut s = String::from("hello");

let r1 = &mut s;
let r2 = &mut s;

println!("{}, {}", r1, r2);
// error[E0499]: cannot borrow `s` as mutable more than once at a time
// 同一时间无法对 `s` 进行两次可变引用借用
  • 可变引用与不可变引用不能同时存在
let mut s = String::from("hello");

let r1 = &s; // 没问题
let r2 = &s; // 没问题
let r3 = &mut s; // 大问题

println!("{}, {}, and {}", r1, r2, r3);

注意,引用的作用域 s 从创建开始,一直持续到它最后一次使用的地方,这个跟变量的作用域有所不同,变量的作用域从创建持续到某一个花括号 } 结束

如果在上面的代码中声明r3之前 使用 println!("{} and {}", r1, r2) ,那么代码是可以编译通过的,因为r1和r2的作用域在r3之前结束了,所以r3的引用不会发生冲突

  • 悬垂引用(Dangling References)
fn main() {
  let reference_to_nothing = dangle();
}
fn dangle() -> &String {
  let s = String::from("hello");
  &s
}
// error[E0106]: missing lifetime specifier
// 因为 s 是在 dangle 函数内创建的,当 dangle 的代码执行完毕后,s 将被释放,但是此时我们又尝试去返回它的引用。这意味着这个引用会指向一个无效的 String,如果修改成直接返回  字符串 s,就不会有问题了
  • 当你只需要匹配一个条件,且忽略其他条件时就用 if let ,否则都用 match。
  if let Some(3) = v {
    println!("three");
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages