# 引用和借用

如上所示，Owership让我们改变一个变量的值变得“复杂”，那能否像其他编程语言那样随意改变变量的值呢？答案是有的。

所有权系统允许我们通过“Borrowing”的方式达到这个目的。这个机制非常像其他编程语言中的“读写锁”，即同一时刻，只能拥有一个“写锁”，或只能拥有多个“读锁”，不允许“写锁”和“读锁”在同一时刻同时出现。当然这也是数据读写过程中保障一致性的典型做法。只不过Rust是在编译中完成这个(Borrowing)检查的，而不是在运行时，这也就是为什么其他语言程序在运行过程中，容易出现死锁或者野指针的问题。

通&#x8FC7;**&**&#x7B26;号完成Borrowing：

```rust
fn main() {
    let x: Vec<i32> = vec!(1i32, 2, 3);
    let y = &x;
    println!("x={:?}, y={:?}", x, y);
}
```

Borrowing(**\&x**)并不会发生所有权moved，所以println可以同时访问x和y。 通过引用，就可以对普通类型完成修改。

```rust
fn main() {
    let mut x: i32 = 100;
    {
        let y: &mut i32 = &mut x;
        *y += 2;
    }
    println!("{}", x);
}
```

## 借用与引用的区别

借用与引用是一种相辅相成的关系，若B是对A的引用，也可称之为B借用了A。

很相近对吧，但是借用一词本意为要归还。所以在Rust用引用时，一定要注意应该在何处何时正确的“归回”借用/引用。 最后面的“高级”小节会详细举例。

## 规则

1. 同一时刻，最多只有一个可变借用（\&mut T），或者2。
2. 同一时刻，可有0个或多个不可变借用（\&T）但不能有任何可变借用。
3. 借用在离开作用域后释放。
4. 在可变借用释放前不可访问源变量。

## 可变性

Borrowing也分“不可变借用”（默认，**\&T**）和“可变借用”（**\&mut T**）。

顾名思义，“不可变借用”是只读的，不可更新被引用的内容。

```rust
fn main() {
    let x: Vec<i32> = vec!(1i32, 2, 3);

    //可同时有多个不可变借用
    let y = &x;
    let z = &x;
    let m = &x;

    //ok
    println!("{:?}, {:?}, {:?}, {:?}", x, y, z, m);
}
```

再次强调下，同一时刻只能有一个可变借用(\&mut T)，且被借用的变量本身必须有可变性 :

```rust
fn main() {
    //源变量x可变性
    let mut x: Vec<i32> = vec!(1i32, 2, 3);

    //只能有一个可变借用
    let y = &mut x;
    // let z = &mut x; //错误
    y.push(100);

    //ok
    println!("{:?}", y);

    //错误，可变借用未释放，源变量不可访问
    // println!("{:?}", x);
}  //y在此处销毁
```

## 高级例子

下面的复杂例子，进行了详细的注释，即使看不懂也没关系，可以在完成Lifetimes（生命周期）的学习后再仔细思考本例子。

```rust
fn main() {
    let mut x: Vec<i32> = vec!(1i32, 2, 3);

    //更新数组
    //push中对数组进行了可变借用，并在push函数退出时销毁这个借用
    x.push(10);

    {
        //可变借用1
        let mut y = &mut x;
        y.push(100);

        //可变借用2，注意：此处是对y的借用，不可再对x进行借用，
        //因为y在此时依然存活。
        let z = &mut y;
        z.push(1000);

        println!("{:?}", z); //打印: [1, 2, 3, 10, 100, 1000]
    } //y和z在此处被销毁，并释放借用。


    //访问x正常
    println!("{:?}", x); //打印: [1, 2, 3, 10, 100, 1000]
}
```

### 总结

1. 借用不改变内存的所有者（Owner），借用只是对源内存的临时引用。
2. 在借用周期内，借用方可以读写这块内存，所有者被禁止读写内存；且所有者保证在有“借用”存在的情况下，不会释放或转移内存。
3. 失去所有权的变量不可以被借用（访问）。
4. 在租借期内，内存所有者保证不会释放/转移/可变租借这块内存，但如果是在**非可变租借**的情况下，所有者是允许继续**非可变租借**出去的。
5. 借用周期满后，所有者收回读写权限
6. 借用周期小于被借用者（所有者）的生命周期。

> 备注： 借用周期，指的是借用的有效时间段。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yar999.gitbook.io/rustprimer/ownership_system/borrowing_reference.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
