Rust随手记

基本数据类型-原生类型

image-20240410195209385

  • 元组(tuple)

​ 允许各个元素类型不相同
[code]
fn main(){ let tup: (i32,f64,u8) = (500,6.4,1);}
[/code]

  • 字符串

[code]
// quiz2.rs//// This is a quiz for the following sections:// - Strings// - Vecs// - Move semantics// - Modules// - Enums//// Let’s build a little machine in the form of a function. As input, we’re going// to give a list of strings and commands. These commands determine what action// is going to be applied to the string. It can either be:// - Uppercase the string// - Trim the string// - Append “bar” to the string a specified amount of times// The exact form of this will be:// - The input is going to be a Vector of a 2-length tuple,// the first element is the string, the second one is the command.// - The output element is going to be a Vector of strings.//// No hints this time!// I AM NOT DONEpub enum Command { Uppercase, Trim, Append(usize),}mod my_module { use super::Command; // TODO: Complete the function signature! pub fn transformer(input: Vec<(String,Command)>) -> Vec { // TODO: Complete the output declaration! let mut output: Vec = vec![]; for (string, command) in input.iter() { // TODO: Complete the function body. You can do it! match command{ Command::Uppercase => output.push(string.to_uppercase()), Command::Trim => output.push(string.trim().to_string()), Command::Append(n) => { let mut append_stirng = string.clone(); for _ in 0..*n { append_stirng += “bar”; } output.push(append_stirng); } } } output }}#[cfg(test)]mod tests { // TODO: What do we need to import to have transformer in scope? use super::my_module::transformer; use super::Command; #[test] fn it_works() { let output = transformer(vec![ (“hello”.into(), Command::Uppercase), (“ all roads lead to rome! “.into(), Command::Trim), (“foo”.into(), Command::Append(1)), (“bar”.into(), Command::Append(5)), ]); assert_eq!(output[0], “HELLO”); assert_eq!(output[1], “all roads lead to rome!”); assert_eq!(output[2], “foobar”); assert_eq!(output[3], “barbarbarbarbarbar”); }}
[/code]

  • String

image-20240414142656028

  • "rust is fun!".to_owned() 是一个字符串字面量(string literal),.to_owned() 是一个字符串切片(&str)的方法,用于将字符串切片转换为一个拥有所有权的 String 类型的对象。这个方法的作用是创建一个新的 String 对象,其中包含了字符串切片的内容,同时拥有了自己的内存空间,与原始的字符串切片无关。

  • "nice weather".into() 是 Rust 中的一个特殊的语法,它实际上是调用了 From trait 中的实现,将一个类型转换为另一个类型。在这种情况下,"nice weather".into() 将一个字符串字面量(&str 类型)转换为 String 类型。这种转换是通过实现了 From<&str> for String 的 trait 来完成的,它会将给定的字符串切片(&str)复制到一个新的 String 对象中,并返回这个新对象。这种转换通常被称为”类型推导”,因为编译器会根据上下文自动推导出需要转换的目标类型。

  • Option

和match配合

image-20240417114555485

  • 通配符

image-20240417114753525

  • if let 简介控制流

相当于二元控制流

  • 泛型

image-20240417120202658

  • Trait(interface)

image-20240417120533444

(1) trait作为参数

image-20240417230445201

小计:

.fold()

[code]
fn main() { let numbers = vec![1, 2, 3, 4, 5]; let sum = numbers.iter().fold(0, |acc, &x| acc + x); println!(“The sum is: {}”, sum); // 输出:The sum is: 15}
[/code]

.fold()迭代器方法
[code]
fn fold<B, F>(self, init: B, f: F) -> Bwhere F: FnMut(B, Self::Item) -> B,
[/code]

这里的参数含义是:

  • init 是初始值,它是要合并的类型的默认值或起始状态。
  • f 是一个闭包函数,它接受两个参数:累积值(accumulator)和当前迭代的元素,并返回一个新的累积值。

.fold() 方法会迭代迭代器的每个元素,并在每次迭代中调用闭包函数 f,将当前累积值和当前元素作为参数传递给闭包函数,然后将闭包函数的返回值作为新的累积值。最终,.fold() 方法返回的值是所有元素被合并后得到的单个值。

智能指针

通常用结构体来实现,不同之处在于实现了DerefDrop traitDereftrait 允许智能指针结构体示例表现的像引用 一样,Drop trait允许我们自定义当智能指针离开作用域时 运行的代码

  • Box

box允许将值直接放到到堆上

递归类型

cons list

每一项都包含两个元素:当前的值和下一项。其最后一项

  • 计算非递归类型的大小

image-20240421090726614

Rust知道为Message分配多少空间时,他会检查每一个成员,并发现quit并不需要任何空间,Move需要两个i32空间,依此类推

Deref

实现Deref允许我们重载解引用运算符* 我们无法直接使用指针所指向的数据,需要通过解引用运算符

Drop

制定在值离开作用域时应该执行Droptrait。一般是自动进行。

当我们想手动执行,就可以使用公用的drop

image-20240421092345178

Rc< T >智能指针

引用计数

  • Rc< T >来共享数据

image-20240421092803615

  • 可以用来计数

image-20240421092829590

会打印出引用计数,可以调用strong_count函数获得

但是,虽然可以共享数据,其还是没有违反借用和所有权的定义,只是使别的变量具有a变量的可读性

RefCell < T >和内部可变性

  • RefCell 大量使用unsafe代码来模糊rust规则,要手动检查是否符合规则

结合Rc < T >和 RefCell < T > 来拥有多个可变数据所有者
[code]
#[derive(Debug)]enum List { Cons(Rc<RefCell>, Rc), Nil,}use crate::List::{Cons, Nil};use std::cell::RefCell;use std::rc::Rc;fn main() { let value = Rc::new(RefCell::new(5)); let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil))); let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a)); let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a)); *value.borrow_mut() += 10; println!(“a after = {:?}”, a); println!(“b after = {:?}”, b); println!(“c after = {:?}”, c);}
[/code]

可以拥有一个表面上不可变的List,不过可以使用RefCell< T>中提供内部可变性的方法来再需要时修改

多线程

spawn创建多线程

image-20240421094452825

线程间传送数据

提供了信道(channel)来实现。信道分为发送者和接收者

image-20240421103518959

可以允许多个发送者 但是只能有一个接收者
类比java

信道与所有权转移

send函数会获取其参数的所有权并移动这个值归接收者所有。

image-20240421104012845

不想所有权转移 :

互斥器Mutex< T >

image-20240421104351246

同步和异步async和多线程

异步返回的都是future

.await异步机制的实现 更像

Macro )指的是 Rust 中一系列的功能:使用 macro_rules!声明Declarative )宏,和三种 过程Procedural )宏:

  • 自定义 #[derive] 宏在结构体和枚举上指定通过 derive 属性添加的代码
  • 类属性(Attribute-like)宏定义可用于任意项的自定义属性
  • 类函数宏看起来像函数不过作用于作为参数传递的 token

为什么已经有了函数还需要宏呢?

宏是一种代码生成器 ,允许在编译时对代码进行操作和生成,可以在更大的范围内改变代码结构和行为。在某些情况下,使用宏可以提高代码的灵活性和效率,但同时也会增加代码的复杂性和难以理解性。

总结

怀着java的心来学rust,在很多情况下,rust所有权问题总是是一个大坑,rust是对底层深入的语言,相比于java非常多的工具链,rust给我最大的感觉就是如同汽车修理工那样,一个零件一个零件的卸下和装配。说实话,时间太短了,很多概念是第一次接受,并没有特别深入的了解,之后会尽力去做的。