Refining Ch04.

This commit is contained in:
rust-lang.xfoss.com 2023-12-12 17:58:19 +08:00
parent 584cf03a38
commit 60bd1a1a61
2 changed files with 24 additions and 18 deletions

View File

@ -1,11 +1,7 @@
fn main() {
let s = "नमस्ते";
let mut s = String::from("hello");
for c in s.chars() {
println!("{}", c);
}
s.push_str(", world!"); // push_str() 方法会追加一个字面值,到某个 String
for b in s.bytes() {
println!("{}", b);
}
println! ("{}", s); // 这将打印出 `hello, world!`
}

View File

@ -106,28 +106,38 @@ let s = String::from("hello");
这种字符串,*可* 被改变:
```rust
let mut s = String::from("hello");
s.push_str(", world!"); // push_str() 方法会追加一个字面值,到某个 String
println! ("{}", s); // 这将打印出 `hello, world!`
let mut s = String::from("hello");
s.push_str(", world!"); // push_str() 方法会追加一个字面值,到某个 String
println! ("{}", s); // 这将打印出 `hello, world!`
```
那么,到底字面值, `&str``String` 类型有何不同?为何 `String` 可以被改变,而字面值却不能?区别就在于,这两种类型处理内存的方式,是不同的。
那么,这里有什么区别呢?为什么 `String` 可被改变,而字面值却不能呢?区别在于,这两种类型如何处理内存。
## 内存与内存分配
对于字符串字面值这种情况在编译时咱们就知道其内容因此该文本就被直接硬编码到了最终的可执行文件。这就是为何字符串字面值快速高效的原因。然而这些属性只是来源于字符串字面值的不可变性。不幸的是对于那些在编译时大小未知的且在运行期间大小可能改变的各个文本是无法为他们而将某块内存放入到二进制程序中的unfortunately, we can't put a blob of memory into the binary for each piece of text whose size is unknown at compile time and whose size might change while running the program
**Memeory and Allocation**
`String` 类型下,为了支持可变、可增长的一段文本,就需要在内存堆上分配某个数量的内存,用来保存文本的那些内容,而这个数量在编译时则是未知的。这就意味着:
- 该内存必须在运行时向内存分配器请求;
- 在使用完那个 `String` 值之后,需要把这片内存交回给内存分配器的某种途径。
对于字符串字面值,我们在编译时就知道其内容,因此该文本会被直接硬编码到,最终的可执行文件中。这就是字符串字面值快速高效的原因。但这些属性,只是来自于字符串字面值的不变性。遗憾的是,我们无法为每段编译时大小未知,且在运行程序时大小可能改变的文本,添加一块内存到二进制程序中。
其中第一部分是由代码编写者完成的:在调用 `String::from` 时,这个 `from` 方法的实现,就请求了他所需的内存。在各种编程语言中,这是相当通行的做法。
而在 `String` 类型下,为了支持某段可变、可增长的文本,我们需要在堆上,分配编译时未知的某个数量的内存,来保存内容。这意味着:
然而,这第二部分就有所不同了。在带有 *垃圾收集器garbage collector, GC* 的那些语言中,对那些不再是正被使用中的内存的追踪和清理,是由垃圾收集器完成的,对此这里无需去考虑。而在大多数不带垃圾收集器的语言,就要靠代码编写者自己,去识别内存在何时不再被使用,并像请求内存时一样,要调用代码来显式地释放他。要正确完成这样的内存释放,早已成为一个历史悠久的编程难题。若忘记了,咱们就将浪费内存。而过早地释放内存,则将造成变量失效。若执行两次,那也同样是程序错误。咱们需要严格地一个 `allocate` 对应一个 `free`
Rust 采取了不同的路线:一旦某个变量超出了作用域,那么该变量所持有的内存空间,就被自动退回。下面是对清单 4-1 那个作用域示例,使用 `String` 而非字符串字面值的一个版本:
- 必须在运行时,向内存分配器申请该内存;
- 我们需要某种,当咱们是使用完咱们的 `String` 后,将此内存返回给分配器的方法。
第一部分是由我们完成的:当我们调用 `String::from` 时,其实现会请求所需的内存。这在编程语言中非常普遍。
不过,第二部分有所不同。在有 *垃圾回收器garbage collectorGC* 的语言中GC 会跟踪并清理不再使用的内存,我们不需要考虑这个问题。在大多数没有 GC 的语言中,我们有责任识别内存何时不再被使用,并调用代码显式释放内存,就像我们请求内存时一样。正确做到这一点,历来是编程中的难题。如果我们忘记了,就会浪费内存。如果过早释放,就会产生无效变量。如果我们做了两次,那也是一个错误。我们需要在 `allocate` 一次内存的同时,严格 `free` 一次内存。
Rust 采用了不同的路径:一旦拥有内存的变量超出作用域,该内存就会自动返回。下面是清单 4-1 中,咱们作用域示例的一个使用了 `String`,而非字符串字面值的版本:
```rust
{