From 6c5893a38a347df8d672ea48aea66fe1783979b5 Mon Sep 17 00:00:00 2001 From: Xuzheng77s Date: Thu, 18 Aug 2022 18:47:32 +0800 Subject: [PATCH] Update src/ch04-01-what-is-ownership.md.md ch04-01-what-is-ownership.md --- src/ch04-01-what-is-ownership.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ch04-01-what-is-ownership.md b/src/ch04-01-what-is-ownership.md index cc07e28..92beaa5 100644 --- a/src/ch04-01-what-is-ownership.md +++ b/src/ch04-01-what-is-ownership.md @@ -2,11 +2,11 @@ > [ch04-01-what-is-ownership.md](https://github.com/rust-lang/book/blob/main/src/ch04-01-what-is-ownership.md) >
-> commit a5e0c5b2c5f9054be3b961aea2c7edfeea591de8 +> commit 9c9a522555c05cae6717adfbb419af58ebd1cea0 Rust 的核心功能(之一)是 **所有权**(*ownership*)。虽然该功能很容易解释,但它对语言的其他部分有着深刻的影响。 -所有程序都必须管理其运行时使用计算机内存的方式。一些语言中具有垃圾回收机制,在程序运行时不断地寻找不再使用的内存;在另一些语言中,程序员必须亲自分配和释放内存。Rust 则选择了第三种方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。如果违反了任何这些规则,程序都不能编译。在运行时,所有权系统的任何功能都不会减慢程序。 +所有程序都必须管理其运行时使用计算机内存的方式。一些语言中具有垃圾回收机制,在程序运行时有规律地寻找不再使用的内存;在另一些语言中,程序员必须亲自分配和释放内存。Rust 则选择了第三种方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。如果违反了任何这些规则,程序都不能编译。在运行时,所有权系统的任何功能都不会减慢程序。 因为所有权对很多程序员来说都是一个新概念,需要一些时间来适应。好消息是随着你对 Rust 和所有权系统的规则越来越有经验,你就越能自然地编写出安全和高效的代码。持之以恒! @@ -17,11 +17,11 @@ Rust 的核心功能(之一)是 **所有权**(*ownership*)。虽然该 > 在很多语言中,你并不需要经常考虑到栈与堆。不过在像 Rust 这样的系统编程语言中,值是位于栈上还是堆上在更大程度上影响了语言的行为以及为何必须做出这样的抉择。我们会在本章的稍后部分描述所有权与栈和堆相关的内容,所以这里只是一个用来预热的简要解释。 > > 栈和堆都是代码在运行时可供使用的内存,但是它们的结构不同。栈以放入值的顺序存储值并以相反顺序取出值。这也被称作 **后进先出**(*last in, first out*)。想象一下一叠盘子:当增加更多盘子时,把它们放在盘子堆的顶部,当需要盘子时,也从顶部拿走。不能从中间也不能从底部增加或拿走盘子!增加数据叫做 **进栈**(*pushing onto the stack*),而移出数据叫做 **出栈**(*popping off the stack*)。栈中的所有数据都必须占用已知且固定的大小。在编译时大小未知或大小可能变化的数据,要改为存储在堆上。 -> 堆是缺乏组织的:当向堆放入数据时,你要请求一定大小的空间。内存分配器(memory allocator)在堆的某处找到一块足够大的空位,把它标记为已使用,并返回一个表示该位置地址的 **指针**(*pointer*)。这个过程称作 **在堆上分配内存**(*allocating on the heap*),有时简称为 “分配”(allocating)。将数据推入栈中并不被认为是分配。因为指向放入堆中数据的指针是已知的并且大小是固定的,你可以将该指针存储在栈上,不过当需要实际数据时,必须访问指针。想象一下去餐馆就座吃饭。当进入时,你说明有几个人,餐馆员工会找到一个够大的空桌子并领你们过去。如果有人来迟了,他们也可以通过询问来找到你们坐在哪。 +> 堆是缺乏组织的:当向堆放入数据时,你要请求一定大小的空间。内存分配器(memory allocator)在堆的某处找到一块足够大的空位,把它标记为已使用,并返回一个表示该位置地址的 **指针**(*pointer*)。这个过程称作 **在堆上分配内存**(*allocating on the heap*),有时简称为 “分配”(allocating)。(将数据推入栈中并不被认为是分配)。因为指向放入堆中数据的指针是已知的并且大小是固定的,你可以将该指针存储在栈上,不过当需要实际数据时,必须访问指针。想象一下去餐馆就座吃饭。当进入时,你说明有几个人,餐馆员工会找到一个够大的空桌子并领你们过去。如果有人来迟了,他们也可以通过询问来找到你们坐在哪。 > > 入栈比在堆上分配内存要快,因为(入栈时)分配器无需为存储新数据去搜索内存空间;其位置总是在栈顶。相比之下,在堆上分配内存则需要更多的工作,这是因为分配器必须首先找到一块足够存放数据的内存空间,并接着做一些记录为下一次分配做准备。 > -> 访问堆上的数据比访问栈上的数据慢,因为必须通过指针来访问。现代处理器在内存中跳转越少就越快(缓存)。继续类比,假设有一个服务员在餐厅里处理多个桌子的点菜。在一个桌子报完所有菜后再移动到下一个桌子是最有效率的。从桌子 A 听一个菜,接着桌子 B 听一个菜,然后再桌子 A,然后再桌子 B 这样的流程会更加缓慢。出于同样原因,处理器在处理的数据彼此较近的时候(比如在栈上)比较远的时候(比如可能在堆上)能更好的工作。在堆上分配大量的空间也可能消耗时间。 +> 访问堆上的数据比访问栈上的数据慢,因为必须通过指针来访问。现代处理器在内存中跳转越少就越快(缓存)。继续类比,假设有一个服务员在餐厅里处理多个桌子的点菜。在一个桌子报完所有菜后再移动到下一个桌子是最有效率的。从桌子 A 听一个菜,接着桌子 B 听一个菜,然后再桌子 A,然后再桌子 B 这样的流程会更加缓慢。出于同样原因,处理器在处理的数据彼此较近的时候(比如在栈上)比较远的时候(比如可能在堆上)能更好的工作。 > > 当你的代码调用一个函数时,传递给函数的值(包括可能指向堆上数据的指针)和函数的局部变量被压入栈中。当函数结束时,这些值被移出栈。 > @@ -31,7 +31,7 @@ Rust 的核心功能(之一)是 **所有权**(*ownership*)。虽然该 首先,让我们看一下所有权的规则。当我们通过举例说明时,请谨记这些规则: -> 1. Rust 中的每一个值都有一个被称为其 **所有者**(*owner*)的变量。 +> 1. Rust 中的每一个值都有一个 **所有者**(*owner*)。 > 2. 值在任一时刻有且只有一个所有者。 > 3. 当所有者(变量)离开作用域,这个值将被丢弃。 @@ -197,7 +197,9 @@ Rust 采取了一个不同的策略:内存在拥有它的变量离开作用域 原因是像整型这样的在编译时已知大小的类型被整个存储在栈上,所以拷贝其实际的值是快速的。这意味着没有理由在创建变量 `y` 后使 `x` 无效。换句话说,这里没有深浅拷贝的区别,所以这里调用 `clone` 并不会与通常的浅拷贝有什么不同,我们可以不用管它。 -Rust 有一个叫做 `Copy` trait 的特殊注解,可以用在类似整型这样的存储在栈上的类型上(第十章详细讲解 trait)。如果一个类型实现了 `Copy` trait,那么一个旧的变量在将其赋值给其他变量后仍然可用。Rust 不允许自身或其任何部分实现了 `Drop` trait 的类型使用 `Copy` trait。如果我们对其值离开作用域时需要特殊处理的类型使用 `Copy` 注解,将会出现一个编译时错误。要学习如何为你的类型添加 `Copy` 注解以实现该 trait,请阅读附录 C 中的 [“可派生的 trait”][derivable-traits]。 +Rust 有一个叫做 `Copy` trait 的特殊注解,可以用在类似整型这样的存储在栈上的类型上([第十章][ch10]将会详细讲解 trait)。如果一个类型实现了 `Copy` trait,那么一个旧的变量在将其赋值给其他变量后仍然可用。 + +Rust 不允许自身或其任何部分实现了 `Drop` trait 的类型使用 `Copy` trait。如果我们对其值离开作用域时需要特殊处理的类型使用 `Copy` 注解,将会出现一个编译时错误。要学习如何为你的类型添加 `Copy` 注解以实现该 trait,请阅读附录 C 中的 [“可派生的 trait”][derivable-traits]。 那么哪些类型实现了 `Copy` trait 呢?你可以查看给定类型的文档来确认,不过作为一个通用的规则,任何一组简单标量值的组合都可以实现 `Copy`,任何不需要分配内存或某种形式资源的类型都可以实现 `Copy` 。如下是一些 `Copy` 的类型: @@ -209,7 +211,7 @@ Rust 有一个叫做 `Copy` trait 的特殊注解,可以用在类似整型这 ### 所有权与函数 -将值传递给函数在语义上与给变量赋值相似。向函数传递值可能会移动或者复制,就像赋值语句一样。示例 4-3 使用注释展示变量何时进入和离开作用域: +将值传递给函数与给变量赋值的原理相似。向函数传递值可能会移动或者复制,就像赋值语句一样。示例 4-3 使用注释展示变量何时进入和离开作用域: 文件名: src/main.rs @@ -251,6 +253,7 @@ Rust 有一个叫做 `Copy` trait 的特殊注解,可以用在类似整型这 [data-types]: ch03-02-data-types.html#数据类型 [ch8]: ch08-02-strings.html +[ch10]: ch10-00-generics.md [derivable-traits]: appendix-03-derivable-traits.html [method-syntax]: ch05-03-method-syntax.html#方法语法 [paths-module-tree]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html