目录

开始学习Rust

目录

参考书籍: https://course.rs/about-book.html 书中写的已经非常详细了,无需重复造轮子。仅做为一个学习笔记。记录自己在学习过程中的探索。

书中的一个例子: https://course.rs/first-try/hello-world.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
fn main() {
   let penguin_data = "\
   common name,length (cm)
   Little penguin,33
   Yellow-eyed penguin,65
   Fiordland penguin,60
   Invalid,data
   ";

   let records = penguin_data.lines();

   for (i, record) in records.enumerate() {
     if i == 0 || record.trim().len() == 0 {
       continue;
     }

     // 声明一个 fields 变量,类型是 Vec
     // Vec 是 vector 的缩写,是一个可伸缩的集合类型,可以认为是一个动态数组
     // <_>表示 Vec 中的元素类型由编译器自行推断,在很多场景下,都会帮我们省却不少功夫
     let fields: Vec<_> = record
       .split(',')
       .map(|field| field.trim())
       .collect();
     if cfg!(debug_assertions) {
         // 输出到标准错误输出
       eprintln!("debug: {:?} -> {:?}",
              record, fields);
     }

     let name = fields[0];
     // 1. 尝试把 fields[1] 的值转换为 f32 类型的浮点数,如果成功,则把 f32 值赋给 length 变量
     //
     // 2. if let 是一个匹配表达式,用来从=右边的结果中,匹配出 length 的值:
     //   1)当=右边的表达式执行成功,则会返回一个 Ok(f32) 的类型,若失败,则会返回一个 Err(e) 类型,if let 的作用就是仅匹配 Ok 也就是成功的情况,如果是错误,就直接忽略
     //   2)同时 if let 还会做一次解构匹配,通过 Ok(length) 去匹配右边的 Ok(f32),最终把相应的 f32 值赋给 length
     //
     // 3. 当然你也可以忽略成功的情况,用 if let Err(e) = fields[1].parse::<f32>() {...}匹配出错误,然后打印出来,但是没啥卵用
     if let Ok(length) = fields[1].parse::<f32>() {
         // 输出到标准输出
         println!("{}, {}cm", name, length);
     }
   }
 }

需要多加一些解释

  • lines() 函数的含义:
    • 在 Rust 中,lines 方法是字符串切片(&str)的一个方法,它用于按行切分字符串,并返回一个迭代器(iterator),每次迭代返回字符串中的一行。这个方法的作用是将包含多行的字符串拆分成多个单独的字符串,每个字符串代表原始字符串中的一行。默认情况下,lines 方法以换行字符(\n)为分界来切分字符串。
  • 在rust中let 与golang中的var是等价的吗?
    • 在 Rust 中的 let 和 Go 语言中的 var 都是用来声明变量的关键字,但它们在语言设计和行为上有一些不同之处。
    • 不可变性:Rust 默认情况下使用 let 声明的变量是不可变的。如果你想要一个可变的变量,你需要使用 mut 关键字,例如 let mut x = 5;。Go 默认情况下使用 var 声明的变量是可变的,例如 var x int = 5; 或者简写为 var x = 5。Go 没有一个类似 Rust 中的 mut 关键字来区分可变和不可变。mut:这个关键字是“mutable”的缩写,表示变量是可以变的,即可变变量。在 Rust 中,默认情况下,使用 let 声明的变量是不可变的(immutable)。如果你想要改变这个变量的值,你需要在变量名前添加 mut 关键字,明确地表明此变量是可变的。
    • 类型推断:Rust 的 let 可以进行类型推断,你不必显式地指定变量的类型,例如 let x = 5;,编译器会推断出 x 是 i32 类型。Go 的 var 也可以进行类型推断,你可以选择显式地指定类型,也可以省略类型让编译器推断,例如 var x = 5;。
    • 显式类型声明:Rust 允许你显式地声明变量的类型,例如 let x: i32 = 5;。Go 也允许显式声明类型,例如 var x int = 5;。
    • 作用域:Rust 中 let 绑定的作用域通常由花括号 {} 决定。Go 中 var 声明的作用域也是由花括号 {} 决定的,但 Go 有包级变量的概念,使用 var 在函数外部声明的变量具有包级作用域。
    • 生命周期和内存管理:Rust 中的变量生命周期管理是编译时确定的,Rust 使用所有权和借用规则来保证内存安全。Go 使用垃圾收集(GC)来管理内存,程序员不需要显式管理变量的生命周期。
  • 在rust语言中 定义变量let var3 = "你好";let var3: &str = "你好"; 的区别:
    • let var3 = "你好"; 在这种写法中,我们没有显式指定 var3 的类型。Rust 编译器会自动使用类型推断来确定 var3 的类型。因为 “你好” 是一个字符串字面量,所以编译器会推断 var3 的类型为 &‘static str。‘static 是一个生命周期,意味着这个字符串字面量是硬编码到程序的二进制文件中的,它的生命周期是整个程序的运行期。
    • let var3: &str = "你好"; 在这种写法中,我们显式地指定了 var3 的类型为 &str,这是一个字符串切片类型。这里没有指定生命周期,所以编译器会根据上下文来推断生命周期。由于 “你好” 同样是一个字符串字面量,它的生命周期会被推断为 ‘static。
    • 总的来说,两种写法都会得到同样的结果,即 var3 的类型是 &‘static str。不过第一种写法利用了 Rust 的类型推断系统,而第二种写法则显式指定了类型。在实践中,显式类型通常用于更复杂的情况,比如当类型推断不明确或需要明确指出变量类型以提高代码可读性时。
    • 如果你是初学者,了解和习惯类型推断可以让你写出更简洁的代码,但在团队合作或编写公共API时,显式类型声明可以减少误解和提高代码的清晰度。