Skip to main content

所有权

Stack and Heap

The stack is last-in, first-out, fast, and its size is known at compile time. The heap,

Ownership

  1. Every value in Rust has an owner. Every piece of data, or "value," in a Rust program is owned by a variable. That variable is its owner.

  2. There can only be one owner at a time. As soon as a value is assigned to another variable, the original variable no longer owns that value.

    let s1 = String::from("hello");
let s2 = s1; // ownership of s1 is moved to s2

println!("s1: {s1}"); // this line errors, because s1 no longer owns the value
println!("s2: {s2}"); // this line prints fine, because s2 now owns the value
  1. When the owner goes out of scope, the value is dropped. When ownership of a piece of data is moved to a local variable, that data is invalid outside the scope of that local variable.
    {
let s = String::from("hello");
// s is valid here
}
// s is invalid here and cannot be accessed

Copy

Types that implement the Copy trait are usually simple scalar types whose data lives entirely on the stack. Common examples include:

All integer types (e.g. i32, u64) The boolean type (bool) Floating-point types (e.g. f64) The character type (char) Tuples, if they only contain types that also implement Copy. The key point is that String does not implement Copy, because it manages heap-allocated data.

Borrowing

Borrowing is achieved by creating a reference to a value.

What is borrowing? Fundamentally, borrowing means temporarily using a value without taking ownership of it. How do you borrow? You borrow a value by creating a reference to it. The effect of references: when you create a reference to data and pass it to a function, ownership of the original data is not transferred. The original owner still retains control.

Immutable references &T

An immutable reference lets you read the data but not modify it. The key rule for immutable references is: You can have any number of immutable references to the same data at the same time.

    let s = String::from("hello");
let r1 = &s; // immutable borrow
let r2 = &s; // another immutable borrow
println!("r1: {}, r2: {}", r1, r2); // you can use multiple immutable references at once

Mutable references &mut T

A mutable reference lets you both read and write (modify) the data it points to. To create a mutable reference, the original data must be declared mutable using the mut keyword.

The key rule for mutable references is:

Within a given scope, you can have only one mutable reference to a particular piece of data at any time. This rule prevents data races at compile time.

    let mut s = String::from("hello");
let r1 = &mut s; // mutable borrow
// let r2 = &mut s; // this line errors, because you cannot have multiple mutable references at once
r1.push_str(", world!"); // modify the data
println!("r1: {}", r1); // you can use the mutable reference

Non-Lexical Lifetimes (NLL): note that the scope of a borrow does not necessarily last until the end of the entire lexical block in which it is defined. Instead, a borrow lasts until its last use. This feature, called Non-Lexical Lifetimes (NLL), makes code more flexible. For example, after a mutable reference is used for the last time, you can create another mutable reference to the same data within the same lexical scope:

    let mut s = String::from("hello");
let r1 = &mut s; // mutable borrow
r1.push_str(", world!"); // modify the data
println!("r1: {}", r1); // use the mutable reference

// r1 is no longer used here, so we can create another mutable reference
let r2 = &mut s; // another mutable borrow
r2.push_str(" Welcome to Rust!"); // modify the data
println!("r2: {}", r2); // use the new mutable reference

That is, after r2 is created, r1 is no longer used.

The rule for mutable vs. immutable references: the two cannot coexist

Any number of immutable references (&T), or

Only one mutable reference (&mut T). The two kinds of reference cannot be active at the same time. This avoids situations where data is modified through a mutable reference while other parts of the code expect the data to remain unchanged through an immutable reference.

Summary

To sum up the core rules and benefits of Rust's borrowing mechanism:

  1. Borrowing lets you temporarily access a value through a reference without taking ownership.
  2. Creating a reference does not transfer ownership of the data.
  3. References can be immutable (&T), allowing read-only access; or mutable (&mut T), allowing read-write access.

For any given piece of data within a particular scope, you can have either:

  1. any number of immutable references, or
  2. only one mutable reference. You cannot use both kinds of reference to the same data at the same time.

A reference's lifetime must never outlive the data it points to. The Rust compiler enforces this rule to prevent dangling references.

📢 Share this article