diff --git "a/source/_posts/2024/rust\347\232\204\347\211\271\346\200\247\345\244\207\345\277\230.md" "b/source/_posts/2024/rust\347\232\204\347\211\271\346\200\247\345\244\207\345\277\230.md" new file mode 100644 index 0000000..5071b44 --- /dev/null +++ "b/source/_posts/2024/rust\347\232\204\347\211\271\346\200\247\345\244\207\345\277\230.md" @@ -0,0 +1,308 @@ +--- +title: rust的特性备忘 +date: 2024-05-16 21:54:54 +tags: rust +index_img: /2024/05/16/rust的特性备忘/title.jpeg +--- + +## 前言 + +由于个人学习的知识学一门忘一门,因此在这里总结一些比较容易忘记的细节内容,以备复习。 + +> 参考 :杨旭<> ,《Rust for Rustaceans》 + +## 引用 + +rust 提供的引用是指针的一种高级抽象。引用就是指针。 + +- 引用始终引用的是有效数据 +- 引用与 usize 的倍数对齐 +- 引用可以动态大小的类型提供上述保障 + +引用会保证在内存中对齐,没有对齐的部分会填充字节,从而不会影响代码的运行速度。 + +例如:i32 类型在内存中占用的空间为 4 字节。 + +> rust 会把不没有固定长度的类型存储在内部指针的附近,这样可以让程序永远不会超出程序在内存中运行的空间,产生溢出漏洞, + +## Raw Pointers(原始指针) + +原始指针是没有 Rust 标准保障的内存地址,即本质上都是需要 unsafe 块包裹的。 +它的速度极快,但是不安全。 + +- 不可变 Raw Pointer: `*const T` +- 可变的 Raw Pointer:`*mutT` + +> 注意: `*constT`,这三个标记放在一起表示的是一个类型 +> +> 例子: `*const String` + +`*const T` 和 `*mutT` 之间差异很小,可以互相转换。 + +Rust 的引用(&mutT 和 &T )会编译为原始指针。这意味着无需冒险进入 unsafe 块,就可以获得原始指针的性能。 + +### 例子:把引用转为原始指针 + +```rust +fn main() { + let a:i64 = 42; + let a_ptr: *const i64 = &a as *const i64; + println!("a: {} ({:p})",a,a_ptr); +} +// ouput=> a: 42 (0x7ff7bd530670) +``` + +> {:p} 可以打印指针地址 + +解引用 (dereference):通过指针从 RAM 内存提取数据的过程 叫做对指针进行解引用 + +```rust +fn main() { + let a: i64 = 42; + let a_ptr: *const i64 = &a as *const i64; + let a_addr: usize = unsafe { std::mem::transmute(a_ptr) }; + println!("a: {} ({:p}... 0x{:x})", a, a_ptr, a_addr + 7); +} +// output=> a: 42 (0x7ff7bacca370... 0x7ff7bacca377) +``` + +> std::mem::transmute :将一种类型的值的位重新解释为另一种类型。两种类型必须具有相同的大小。如果不能保证这一点,编译将失败。 + +### 重要的提示 🔥 + +- 在底层,引用(&T 和 &mutT)被实现为原始指针。但引用带有额外的保障,应该始终作为首选使用 +- 访问 原始指针 的值总是 unsafe 的 +- 原始指针 不拥有值的所有权 +- 在访问时编译器不会检查数据的合法性 +- 允许多个 原始指针 指向同一数据 +- Rust 无法保证共享数据的合法性 + +#### 什么时候可以使用原始指针 + +- 某些 OS 或第三方库需要使用,例如与 C 交互。 +- 共享对某些内容的访问至关重要,运行时性能要求高。 + +## Smart Pointer(智能指针) + +智能指针倾向于包装原始指针,附加更多的能力,不仅仅是对内存地址解引用。 + +### `Box` + +可以把任何东西都放在 Box 里。可接受几乎任何类型的长期存储。新的安全编程时代的主力军。 + +- 优点:将值集中存储在 Heap。 +- 缺点:大小增加。 + +### `Rc` + +`Rc`是 Rust 的能干而吝啬的簿记员。它知道谁借了什么,何时借了什么。 + +- 优点:对值的共享访问。 +- 缺点:大小增加。运行时成本增加,线程不安全。 + +### `Arc` + +`Arc`是 Rust 的大使。它可以跨线程共享值,保证这些值不会相互干扰。 + +- 优点:对值的共享访问,线程安全。 +- 缺点:大小增加,运行时成本增加。 + +### `Cell` + +变态专家,具有改变不可变值的能力。 + +- 优点:内部可变性。 +- 缺点:大小增加,性能降低。 + +### `RefCell` + +对不可变引用执行改变的能力,但有代价。 + +- 优点:内部可变性,可与仅接受不可变引用的 `Rc`、`Arc` 嵌套使用。 +- 缺点:大小增加,运行时成本增加,缺乏编译时保障。 + +### `Cow` + +封闭并提供对借用数据的不可变访问,并在需要修改所有权时延迟克隆数据。 + +- 优点:当只是只读访问时可以避免写入。 +- 缺点:大小可能会增加. + +### `String` + +可处理可变长度的文本,展示了如何构建安全的抽象。 + +- 优点:动态按需增长,在运行时保证正确编码。 +- 缺点:过度分配内存大小。 + +### `Vec` + +程序最常用的存储系统;它在创建和销毁值时保持数据有序。 + +- 优点:动态按需增长。 +- 缺点:过度分配内存大小。 + +### `RawVec` + +是`Vec`和其它动态大小类型的基石,知道如何按需给你的数据提供一个家。 + +- 优点:动态按需增长。与内存分配器一起配合寻找空间。 +- 缺点:代码上一般用不到。 + +### `Unique` + +作为值的唯一所有者,可保证拥有完全控制权。 + +- 优点:需要独占值的类型(如 String)的基础. +- 缺点:代码上一般用不到。 + +### `Shared` + +分享所有权。 + +- 优点:共享所有权,可以将内存与 T 的宽度对齐,即使是空的时候。 +- 缺点:代码上一般用不到。 + +# 内存 + +有 3 个比较重要的内存区域`stack`,`heap`,`static`。 + +- stack 比较快,在内存中比较整齐。 +- heap 比较慢,在内存中比较混乱。 + +## stack 栈内存 + +Stack 是一段内存. 其调用顺序是 LIFO(后进先出)的。 +程序把它作为一个暂存空间,用于函数调用,main 函数就接近 Stack 底部。 + +想把数据放在 Stack,编译器必须知道类型的大小。 + +> 首选使用 Stack,也就是实现了 Sized 的类型。 + +### Stack Frame + +Stack Frame 与 rust 的声明周期相关。 + +每个函数都拥有自己的 Frame 当函数返回时,它的 Frame 就被回收了,构成函数本地变量值的那些字节不会立即擦除, 但访问它们也是不安全的。 + +因为它们可能被后续的函数调用所重写(如果后续函数调用的 Frame 与回收的这个有重合的话)。 + +但即使没有被重写,它们也可能包含无法合法使用的值。例如函数返回后被移动的值。 + +### 小技巧 + +当一个函数即需要兼容 `&str`和 `String`的参数。 + +> $str 存在 Stack 上,String 存储在 Heap 上。 + +`AsRef` 要求参数实现到 T 这个类型的引用,即使参数不是这样的类型。 + +```rust +fn is_strong>(password:T) -> bool { + password.as_ref().len() > 6 +} +``` + +`Into` 要求参数转化为 String 这个类型。但是会涉及比较多的步骤。 + +```rust +fn is_strong>(password:T) -> bool { + password.as_ref().len() > 6 +} +``` + +## Heap 堆内存 + +Heap 在内存中是混乱的,它是一个内存池,并没有绑定到当前程序的调用栈,是为在编译时没有已知大小的类型准备的。 + +例如: + +- 切片类型 [T] +- 随着程序运行动态改变的 String,Vec +- trait 对象,它允许程序员来模拟一些动态语言的特性:通过允许将多个类型放进一个容器 +- 一些类型的大小不会改变,但是无法告诉编译器需要分配多少内存 + +Heap 允许你显式的分配连续的内存块。当这么做时,你会得到一个指针,它指向内存块开始的地方。 + +Heap 内存中的值会一直有效,直到你对它显式的释放。如果你想让值活得比当前函数 frame 的生命周期还长,就很有用。 + +### Heap 线程安全 + +如果想把值送到另一个线程,当前线程可能根本无法与那个线程共享 stack frames,你就可以把它存放在 heap 上。 + +因为函数返回时 heap 上的分配并不会消失,所以你在一个地方为值分配内存,把指向它的指针传给另一个线程,就可以让那个线程继续安全的操作于这个值。 + +换一种说法:当你分配 heap 内存时,结果指针会有一个无约束的生命周期,你的程序让它活多久都行。 + +### Heap 机制 + +Heap 上面的变量必须通过指针访问。Rust 里与 Heap 交互的首要机制就是 Box 类型。 + +```rust +fn main() { + let a:i32 = 40; // Stack + let b:Box = Box::new(60); // Heap + let result:i32 = a + *b; // 用指针访问。 +} +``` + +当`Box:new(value)`时,值就会放在 heap 上,返回的`Box`就是指向 heap 上该值的指针。当 box 被丢弃时,内存就被释放。 + +如果忘记释放 heap 内存,就会导致内存泄漏 +有时你就想让内存泄露。 + +例子:在生命周期没有结束的时候手动释放。 + +```rust +fn main() { + let a: Box = Box::new(1); + let b: Box = Box::new(1); + let result = *a + *b; + drop(a); + println!("{}", result); +} +``` + +#### 如何让内存泄露 🔥 + +例如有一个只读的配置,整个程序都需要访间它。就可以把它分配在 heap 上。 + +通过 Box:leak 得到一个'static 引用,从而显式的让其进行泄露。 + +### Static 静态内存 + +- static 内存实际是一个统称,它指的是程序编译后的文件中几个密切相关的区域。 + - 当程序执行时,这些区域会自动加载到你程序的内存里。 +- static 内存里的值在你的程序的整个执行期间会一直存活。 +- 程序的 static 内存是包含程序二进制代码的(通常映射为只读的)。 + - 随着程序的执行,它会在本文段的二进制代码中挨个指令进行遍历,而当函数被调用时就进行跳跃。 +- static 内存会持有使用 static 声明的变量的内存,也包括某些常量值, 例如字符串。 + +### ‘static + +'static 是特殊的生命周期,它的名字就是来自于 static 内存区,它将引用标记为只要 static 内存还存在(程序关闭前),那么引用就合法。 + +static 变量的内存在程序开始运行时就分配了,到 static 内存中变量的引用,按定义来说,就是'static 的,因为在程序关闭前它不会被释放。 + +一旦你创建了一个'static 生命周期的引用,就程序的其余部分而言,它所指向的内容都可能在 static 内存中,因为程序想要使用它多久就可以使用多久。 + +#### `T:'static` + +其表示类型 T 可以存活我们想要的任何时长(直到程序关闭),同时这也要求 T 是拥有所有权的和自给自足的。 + +要求这个类型不借用其他的值,要么借用的值也都是`‘static`的。 + +### const 与 static 的区别 + +```rust +const x:i32 = 123; +``` + +- const 关键字会把紧随它的东西声明为常量 +- 常量可在编译时完全计算出来。 +- 在编译期间,任何引用常量的代码会被替换为常量的计算结果值 +- 常量没有内存或关联其它存储(因为它不是一个地方) +- 可以把常量理解为某个特殊值的方便的名称 + + +### 动态内存分配 \ No newline at end of file diff --git "a/source/_posts/2024/rust\347\232\204\347\211\271\346\200\247\345\244\207\345\277\230/title.jpeg" "b/source/_posts/2024/rust\347\232\204\347\211\271\346\200\247\345\244\207\345\277\230/title.jpeg" new file mode 100644 index 0000000..0d431c1 Binary files /dev/null and "b/source/_posts/2024/rust\347\232\204\347\211\271\346\200\247\345\244\207\345\277\230/title.jpeg" differ