简体   繁体   English

澄清 Rust 的所有权规则

[英]Clarifying Rust's ownership rules

I'm reading Rust Programming Language book and would like to clarify following Listing 4.5 in Return Values and Scope section:我正在阅读 Rust 编程语言书籍,并想在返回值和范围部分澄清以下清单 4.5:

fn main() {
   let s1 = String::from("hello");
   let (s2, len) = calculate_length(s1);
   println!("The length of '{}' is {}.", s2, len);
}
fn calculate_length(s: String) -> (String, usize) {
   let length = s.len(); // len() returns the length of a String
   (s, length)
}

If I use:如果我使用:

fn calculate_length(s: String) -> (String, usize) {
   (s, s.len())
}

then I'm getting:然后我得到:

error[E0382]: borrow of moved value: `s`
  --> guessing_game/src/main.rs:46:9
   |
43 | fn calculate_length(s: String) -> (String, usize) {
   |                     - move occurs because `s` has type `String`, which does not  implement the `Copy` trait
...
46 |     (s, s.len())
   |      -  ^ value borrowed here after move
   |      |
   |      value moved here

At the same time if I swap values in returning tuple to (s.len(), s) (in calculate_length function) and rewrite main caller accordingly, it compiles without errors.同时,如果我将返回元组中的值交换到(s.len(), s) (在calculate_length函数中)并相应地重写main调用者,它编译时不会出错。

Intuitively I understand this borrowing error (and how to fix it), but could somebody clarify/explain this behavior "more formally"?直觉上我理解这个借用错误(以及如何解决它),但有人可以“更正式地”澄清/解释这种行为吗?

since this construction seems to be an "atomic" operation因为这个构造似乎是一个“原子”操作

Constructing a tuple is “atomic”, but evaluating an expression is not.构造元组是“原子的”,但对表达式求值不是。 In general, expressions can contain arbitrary side effects in any part of them, so the order of evaluation of sub-expressions can affect the semantics of the program.一般来说,表达式的任何部分都可以包含任意的副作用,因此子表达式的计算顺序会影响程序的语义。 Some languages leave it partly unspecified, but in Rust, the evaluation order is always left-to-right.有些语言部分未指定,但在 Rust 中,评估顺序总是从左到右。

So, evaluating (s, s.len()) consists of the following steps:因此,评估(s, s.len())包括以下步骤:

  1. Evaluate the first subexpression, s .计算第一个子表达式s Since s is a type that is not Copy , this moves the value out of the variable s .由于s是不是Copy的类型,因此这会将值移出变量s
  2. Evaluate the second subexpression, s.len() .计算第二s.len()表达式s.len() (This is an error since s is already moved.) (这是一个错误,因为s已经被移动了。)
  3. Construct the tuple from the value of the first subexpression and the value of the second subexpression.根据第一个子表达式的值和第二个子表达式的值构造元组。

In this case, looking at the program we can see that it would not have any undesirable consequences to reorder the two subexpression evaluations, but Rust's evaluation order does not have any special cases for different types of expressions.在这种情况下,查看程序我们可以看到,将两个子表达式的计算重新排序不会产生任何不良后果,但是 Rust 的计算顺序对于不同类型的表达式没有任何特殊情况。

(The optimizer will perform lots of transformations on this code, in particular making nearly all “moves” not involve any memory copying or other actual CPU operations, but it would be very hard to program Rust if the validity of a program depended on the optimizer's choices.) 优化器将对这段代码执行大量转换,特别是使几乎所有“移动”不涉及任何内存复制或其他实际 CPU 操作,但是如果程序的有效性取决于优化器的选择。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM