Rust借贷指针(翻译)_第1页
Rust借贷指针(翻译)_第2页
Rust借贷指针(翻译)_第3页
Rust借贷指针(翻译)_第4页
Rust借贷指针(翻译)_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、.Rust Borrowed Pointers Tutorial(翻译)1. Introduction(介绍)2. By example(使用示例)3. Other uses for the & operator(对&操作符的其它使用方式)4. Taking the address of fields(取成员地址)5. Borrowing managed boxes and rooting(从托管盒子借来指针和根植)6. Borrowing unique boxes(从自有盒子借指针)7. Borrowing and enums(借贷和枚举)8. Returning borro

2、wed pointers(返回借贷指针)9. Named lifetimes(对生存期命名)10. Conclusion()1. Introduction(介绍)Borrowed pointers are one of the more flexible and powerful tools available in Rust.(借贷指针是Rust最为灵活强大的工具之一。) A borrowed pointer can point anywhere: into the managed or exchange heap, into the stack, and even into the int

3、erior of another data structure.(借贷指针可以指向任何地方:托管堆、交换堆或者栈,甚至是另一个数据结构的内部。) A borrowed pointer is as flexible as a C pointer or C+ reference.(借贷指针和C指针或者C+的引用一样灵活。) However, unlike C and C+ compilers, the Rust compiler includes special static checks that ensure that programs use borrowed pointers safely

4、.(然而,和C/C+编译器不同,Rust编译器包含了特别的静态检查以确保程序安全的使用借贷指针。) Another advantage of borrowed pointers is that they are invisible to the garbage collector, so working with borrowed pointers helps reduce the overhead of automatic memory management.(借贷指针的另一上特点是,它们对垃圾回收器不可见,因此使用借贷指针有助于降低自动内存管理的开销。)Despite their comp

5、lete safety, a borrowed pointer's representation at runtime is the same as that of an ordinary pointer in a C program.(尽管它们完全安全,借贷指针的运行时表示和普通C指针是一样的。) They introduce zero overhead.(它们不引入任何开销。) The compiler does all safety checks at compile time.(编译器所有安全检查发生在编译期。)Although borrowed pointers have r

6、ather elaborate theoretical underpinnings (region pointers), the core concepts will be familiar to anyone who has worked with C or C+.(尽管借贷指针拥有相当详细的理论基础(区域指针),其核心概念对任何使用C/C+的人熟悉。) Therefore, the best way to explain how they are usedand their limitationsis probably just to work through several exampl

7、es.(因此,解释它们使用方式和限制的最好方法就是,通过几个例子。)2. By example(示例)Borrowed pointers are called borrowed because they are only valid for a limited duration.(借贷指针之所以叫借贷,是因为它们只在有限时间内有效。) Borrowed pointers never claim any kind of ownership over the data that they point to: instead, they are used for cases where you wo

8、uld like to use data for a short time.(借贷指针不拥有它所指向数据任何形式的所有权:取而代之的是,它们适用于你想要在短时间内使用数据的情况。)As an example, consider a simple struct type Point:(作为例子,思考一个简单的结构体类型Point:)struct Point x: float, y: floatWe can use this simple definition to allocate points in many different ways.(我们可以使用这个定义通过不同的方式分配指针。) Fo

9、r example, in this code, each of these three local variables contains a point, but allocated in a different place:(例如,在下面代码里,三个局部变量都包含指针,但在不同地方分配。)let on_the_stack : Point = Point x: 3.0, y: 4.0;let shared_box : Point = Point x: 5.0, y: 1.0;let unique_box : Point = Point x: 7.0, y: 9.0;Suppose we wa

10、nted to write a procedure that computed the distance between any two points, no matter where they were stored.(假设我们想要写一个程序,用于计算任意两点间的距离,而不在乎它们存储在哪。) For example, we might like to compute the distance between on_the_stack and shared_box, or between shared_box and unique_box.(例如,我们想要计算on_the_stack和sha

11、red_box之间或者shared_box和unique_box之间的距离。) One option is to define a function that takes two arguments of type Pointthat is, it takes the points by value.(一种方式,定义两个以类型Point为参数的函数就是说,以点的值作为参数。) But if we define it this way, calling the function will cause the points to be copied.(但是如果我们以这种方式定义,调用函数将导致点被

12、复制。) For points, this is probably not so bad, but often copies are expensive.(对于点来说,这可能并不那么坏,但复制通常是昂贵的。) Worse, if the data type contains mutable fields, copying can change the semantics of your program in unexpected ways.(更糟糕的是,如果数据包含可变成员,复制可能改变程序语义,偏离你的期望。) So we'd like to define a function th

13、at takes the points by pointer.(因此,我们更愿意定义以指向点的指针为参数的函数。) We can use borrowed pointers to do this:(我们可以使用借贷指针来实现它:)fn compute_distance(p1: &Point, p2: &Point) -> float let x_d = p1.x - p2.x; let y_d = p1.y - p2.y; sqrt(x_d * x_d + y_d * y_d)Now we can call compute_distance() in various wa

14、ys:(现在我们可以多种方式调用compute_distance()函数:)compute_distance(&on_the_stack, shared_box);compute_distance(shared_box, unique_box);Here, the & operator takes the address of the variable on_the_stack;(这里的&操作符用于取出变量on_the_stack的地址;) this is because on_the_stack has the type Point (that is, a struc

15、t value) and we have to take its address to get a value.(这是因为on_the_stack的类型为Point(也就是,结构体值)而我们又不得不通过地址来获得它的值的缘故。) We also call this borrowing the local variable on_the_stack, because we have created an alias: that is, another name for the same data.(我们也把这称为从局部变量on_the_stack借来指针,因为我们已经创造了一个别名:那是,相同数

16、据的另一个名字。)In contrast, we can pass the boxes shared_box and unique_box to compute_distance directly.(相对的,盒子shared_box和unique_box可以直接传给compute_distance。) The compiler automatically converts a box like Point or Point to a borrowed pointer like &Point.(编译器自动将盒子Point或者Point转换成借贷指针&Point。) This is

17、 another form of borrowing: in this case, the caller lends the contents of the shared or unique box to the callee.(这是另一种形式的借贷:在这种情况下,调用者将共享或独有盒子的内容借给被调用者。)Whenever a caller lends data to a callee, there are some limitations on what the caller can do with the original.(当调用者将数据借出时,调用者对原始数据的处理会受到限制。) F

18、or example, if the contents of a variable have been lent out, you cannot send that variable to another task.(例如,如果变量内容被借出,不能再将变量借给另一个任务。) In addition, the compiler will reject any code that might cause the borrowed value to be freed or overwrite its component fields with values of different types (I

19、'll get into what kinds of actions those are shortly).(还有编译器拒绝任何可能导致借来的值被释放或才它的组成成员被不同类型的值覆写的代码。) This rule should make intuitive sense: you must wait for a borrower to return the value that you lent it (that is, wait for the borrowed pointer to go out of scope) before you can make full use of i

20、t again.(这条规则很直观:在你可以重新使用借出的值前,必须等待它从借用者处返回(也就是说,等待借贷指针超出作用域)。)3. Other uses for the & operator(对&操作符的其它使用方式)In the previous example, the value on_the_stack was defined like so:(前例中,值变量on_the_stack像这样定义:)let on_the_stack: Point = Point x: 3.0, y: 4.0;This declaration means that code can only

21、 pass Point by value to other functions.(这意味着代码只能以点的值传递给其它函数。) As a consequence, we had to explicitly take the address of on_the_stack to get a borrowed pointer.(结果,我们必须提出on_the_stack的地址来获得借贷指针。) Sometimes however it is more convenient to move the & operator into the definition of on_the_stack:(

22、然而,有时候,将&操作符放入on_the_stack的定义会更方便:)let on_the_stack2: &Point = &Point x: 3.0, y: 4.0;Applying & to an rvalue (non-assignable location) is just a convenient shorthand for creating a temporary and taking its address.(将&用于右值(不可赋值的位置)是方便的创造临时变量并取出它的地址的简写形式。) A more verbose way to wri

23、te the same code is:(写出同样代码的更详细方式是:)let tmp = Point x: 3.0, y: 4.0;let on_the_stack2 : &Point = &tmp;4. Taking the address of fields(取出成员地址)As in C, the & operator is not limited to taking the address of local variables.(和C一样,&操作符不局限于取出局部变量的地址。) It can also take the address of fields

24、 or individual array elements.(它也可以取出成员地址或独立阵列元素。) For example, consider this type definition for rectangle:(例如,思考矩形的类型定义:)struct Point x: float, y: float / as beforestruct Size w: float, h: float / as beforestruct Rectangle origin: Point, size: SizeNow, as before, we can define rectangles in a few

25、different ways:(现在,和之前一样,我们可以用不同方式定义矩形:)let rect_stack = &Rectangle origin: Point x: 1f, y: 2f, size: Size w: 3f, h: 4f;let rect_managed = Rectangle origin: Point x: 3f, y: 4f, size: Size w: 3f, h: 4f;let rect_unique = Rectangle origin: Point x: 5f, y: 6f, size: Size w: 3f, h: 4f;In each case, w

26、e can extract out individual subcomponents with the & operator.(对于每种情况,可以使用 &操作符抽取出独立的子组件。) For example, I could write:(例如,可以写成:)compute_distance(&rect_stack.origin, &rect_managed.origin);which would borrow the field origin from the rectangle on the stack as well as from the managed

27、box, and then compute the distance between them.(从栈和托管盒子上的矩形借来origin成员,然后计算他们的距离。)5. Borrowing managed boxes and rooting(从托管盒子借来指针和根植)Weve seen a few examples so far of borrowing heap boxes, both managed and unique.(我们至今已经看到几个从堆盒子,托管和独立,借来指针的例子了。) Up till this point, weve glossed over issues of safe

28、ty.(到此为此,我们都忽略了安全问题。) As stated in the introduction, at runtime a borrowed pointer is simply a pointer, nothing more.(就像介绍中说的那样,在运行时借贷指针只是简单的指针(和C一样),没别的。) Therefore, avoiding C's problems with dangling pointers requires a compile-time safety check.(因此,需要编译期安全检查来避免C里危险的指针的问题。)The basis for the c

29、heck is the notion of lifetimes.(检查的基础是生存期概念。) A lifetime is a static approximation of the span of execution during which the pointer is valid: it always corresponds to some expression or block within the program.(生存期是执行期指针有效范围的静态近似。) Code inside that expression can use the pointer without restricti

30、ons.(在表达式里的代码可以没有限制的使用指针。) But if the pointer escapes from that expression (for example, if the expression contains an assignment expression that assigns the pointer to a mutable field of a data structure with a broader scope than the pointer itself), the compiler reports an error.(但是如果指针离开了那个表达式(例如

31、,如果表达式包含包含赋值表达式,它将指针赋给一个作用域比指针本身更广的数据结构的可变成员),编译器会报错。) We'll be discussing lifetimes more in the examples to come, and a more thorough introduction is also available.(我们将在接下来的例子更多的讨论生存期,并且也存在更全面的介绍。)When the & operator creates a borrowed pointer, the compiler must ensure that the pointer rem

32、ains valid for its entire lifetime.(当用 &操作符创建一个借贷指针,编译器必须确保在指针其余整个生存期有效。) Sometimes this is relatively easy, such as when taking the address of a local variable or a field that is stored on the stack:(有时,这相对容易,例如,获得存储在栈上的局部变量或其成员的地址:)struct X f: int fn example1() let mut x = X f: 3 ; let y = &am

33、p;mut x.f; / -+ L . / | / -+Here, the lifetime of the borrowed pointer y is simply L, the remainder of the function body.(在这里,借贷指针y的生存期是L,函数主体的其余部分。) The compiler need not do any other work to prove that code will not free x.f.(编译器不需要做其它的工作来证明代码不会释放x.f。) This is true even if the code mutates x.(就算代码

34、改变x也没问题。)The situation gets more complex when borrowing data inside heap boxes:(从堆盒子借来数据让情况变得复杂:)fn example2() let mut x = X f: 3 ; let y = &x.f; / -+ L . / | / -+In this example, the value x is a heap box, and y is therefore a pointer into that heap box.(在这个例子里,x的值是堆盒子,因此y是指向堆盒子内部的指针。) Again th

35、e lifetime of y is L, the remainder of the function body.(同样,y的生存期是L,函数主体的余下部分。) But there is a crucial difference: suppose x were to be reassigned during the lifetime L?(但是,有一个关键不同:假设x在生存期L被重新赋值?) If the compiler isn't careful, the managed box could become unrooted, and would therefore be subje

36、ct to garbage collection.(如果编译器不小心,托管盒子可能变得没有根,因而受垃圾回收支配。) A heap box that is unrooted is one such that no pointer values in the heap point to it.(没有根的堆盒子是那些在堆里的没有指针指向的值。) It would violate memory safety for the box that was originally assigned to x to be garbage-collected, since a non-heap pointer-y

37、-still points into it.(这将违返内存安全,原本赋值给x的盒子被垃圾回收了,而非堆指针y仍然指向它。) Note: Our current implementation implements the garbage collector using reference counting and cycle detection.(注意:我们当前实现的垃圾回收器使用引用计数和周期检查。)For this reason, whenever an & expression borrows the interior of a managed box stored in a mu

38、table location, the compiler inserts a temporary that ensures that the managed box remains live for the entire lifetime.(因为这个原因,无论何时 &表达式从存在可变位置上的托管盒子内部借来指针,编译器将插入一个临时变量以确保托管盒子在指针的整个生存期仍然存在。) So, the above example would be compiled as if it were written(因此,上面的盒子可以像所写的那样被编译)fn example2() let mut

39、x = X f: 3; let x1 = x; let y = &x1.f; / -+ L . / | / -+Now if x is reassigned, the pointer y will still remain valid.(现在,如果x被重新赋值,指针y将仍然有效。) This process is called rooting.(这个过程叫做根植。)6. Borrowing unique boxes(借来独立盒子)The previous example demonstrated rooting, the process by which the compiler en

40、sures that managed boxes remain live for the duration of a borrow.(前例示范了根植,编译器依靠根植来确保托管盒子在借出期间仍然存在。) Unfortunately, rooting does not work for borrows of unique boxes, because it is not possible to have two references to a unique box.(不幸的是,根植对从独立指针借出无效,因为不可能有对独立盒子的两个引用。)For unique boxes, therefore, t

41、he compiler will only allow a borrow if the compiler can guarantee that the unique box will not be reassigned or moved for the lifetime of the pointer.(因此,对于独立盒子,只有当独立盒子在指针生存期不被重新赋值或转移,编译器才允许其被指针借出。) This does not necessarily mean that the unique box is stored in immutable memory.(这不一定意味着独立盒子存储在不可变内

42、存里。) For example, the following function is legal:(例如,下面函数是合法的:)fn example3() -> int let mut x = Foo f: 3; if some_condition() let y = &x.f; / -+ L return *y; / | / -+ x = Foo f: 4; .Here, as before, the interior of the variable x is being borrowed and x is declared as mutable.(这里,像之前一样,变量x的内

43、部被借出并且x被申明为可变的。) However, the compiler can prove that x is not assigned anywhere in the lifetime L of the variable y.(然而,编译器会检查在变量y的生存期L里,x不能被赋值。) Therefore, it accepts the function, even though x is mutable and in fact is mutated later in the function.(因此,尽管x是可变的并且事实上在函数的后面被改变,这个函数可以编译。)It may not

44、be clear why we are so concerned about mutating a borrowed variable.(为什么我们如此关注对借来变量的改变呢?) The reason is that the runtime system frees any unique box as soon as its owning reference changes or goes out of scope.(原因在于,只要独立盒子引用改变或者超出作用域,运行时系统就会释放它。) Therefore, a program like this is illegal (and would

45、be rejected by the compiler):(因此,下面程序是非法的(并且会被编译器拒绝):)fn example3() -> int let mut x = X f: 3; let y = &x.f; x = X f: 4; / Error reported here.(这里报错) *yTo make this clearer, consider this diagram showing the state of memory immediately before the re-assignment of x:(为了弄得更清楚,思考下图,它显示了x被重赋值这前的状

46、态:) Stack Exchange Heap x +-+ | f:int | -+ y +-+ | | &int | -+ +-+ | +-+ +-> | f: 3 | +-+Once the reassignment occurs, the memory will look like this:(一旦出现重新赋值,内存就变成这样:) Stack Exchange Heap x +-+ +-+ | f:int | -> | f: 4 | y +-+ +-+ | &int | -+ +-+ | +-+ +-> | (freed) | +-+Here you c

47、an see that the variable y still points at the old box, which has been freed.(你可以看到,变量y仍然指着旧盒子,而它已经被释放。)In fact, the compiler can apply the same kind of reasoning to any memory that is (uniquely) owned by the stack frame.(事实上,编译器将同样的理由应用于任何被栈桢(独立)占有的内存。) So we could modify the previous example to in

48、troduce additional unique pointers and structs, and the compiler will still be able to detect possible mutations:(因此,我们可以修改上例来引入独立指针和结构体,并且编译器将能够检查出可能的改变:)fn example3() -> int struct R g: int struct S f: R let mut x = S f: R g: 3; let y = &x.f.g;x = S f: R g: 4; / Error reported here./ 这里报错。x

49、.f = R g: 5; / Error reported here./ 这里报错。 *yIn this case, two errors are reported, one when the variable x is modified and another when x.f is modified.(在这种情况下,报了两个错,一个是x改变,另一个是x.f改变。) Either modification would invalidate the pointer y.(这两个修改都会使指针y无效。)7. Borrowing and enums(借贷和枚举)The previous examp

50、le showed that the type system forbids any borrowing of unique boxes found in aliasable, mutable memory.(前例显示,类型系统禁止可变内存上拥有别名的独立盒子的借出。(可能是这个意思吧) This restriction prevents pointers from pointing into freed memory.(这个限制避免指针指向已释放内存。) There is one other case where the compiler must be very careful to en

51、sure that pointers remain valid: pointers into the interior of an enum.(编译器必须非常小心的另一个情形是:确保指向枚举数据内部的指针仍然有效。)As an example, lets look at the following shape type that can represent both rectangles and circles:(作为例子,下面的形状类型既可以表示矩形又可以表示圆形:)struct Point x: float, y: float; / as beforestruct Size w: floa

52、t, h: float; / as beforeenum Shape Circle(Point, float), / origin, radius Rectangle(Point, Size) / upper-left, dimensionsNow we might write a function to compute the area of a shape.(现在,我们想写一个函数来计算图形面积。) This function takes a borrowed pointer to a shape, to avoid the need for copying.(这个函数这个函数使用指向图形

53、的指针,以避免复制的必要。)fn compute_area(shape: &Shape) -> float match *shape Circle(_, radius) => 0.5 * tau * radius * radius, Rectangle(_, ref size) => size.w * size.h The first case matches against circles.(第一个分支匹配圆。) Here, the pattern extracts the radius from the shape variant and the action u

54、ses it to compute the area of the circle.(在这里,模式从图形变量抽取半径,然后动作使用它来计算圆的面积。) (Like any up-to-date engineer, we use the tau circle constant and not that dreadfully outdated notion of pi).(就像最新的工程师一样,我们使用tau圆常量而不是可怕的过时的pi符号(为什么啊?Pi可怕?!)。)The second match is more interesting.(第二个分支更有趣。) Here we match aga

55、inst a rectangle and extract its size: but rather than copy the size struct, we use a by-reference binding to create a pointer to it.(这里我们匹配矩形并抽取它的尺寸:但是,比起复制size结构体,我们使用引用绑定来创造指向它的指针。) In other words, a pattern binding like ref size binds the name size to a pointer of type &size into the interior of the enum.(换句话说,向ref size这样的模式绑定将名字size绑定到一个指向枚举类型内部的&Size类型指针)To make this more clear, le

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论