Rust 所有权理解
Understanding OwnerShip
1. What Is Ownership?
Rust’s central feature is ownership.
1.1 Why need it?
Rust uses a third approach: memory is managed through a system of ownership with a set of rules that the compiler checks at compile time.
It’s an approach to manage the way they use a computer’s memory while running.
Managing heap data is why ownership exists can help explain why it works the way it does.
1.2 Concept
Ownership Rules:
- Each value in Rust has a variable that’s called its owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value will be dropped.
2. OwnerShip Explanation
2.1 Stack and Heap
- These types are all stored on the stack and popped off the stack when their scope is over.
- Scalar Types: Integers, floating-point numbers, Booleans, and characters
- Compound Types: Tuples and arrays
-
Complex data types (such as
String
){ let s = String::from("hello"); // s is valid from this point forward // do stuff with s } // this scope is now over, and s is no
When a variable goes out of scope, Rust calls a special function for us. This function is called
drop
, and it’s where the author ofString
can put the code to return the memory.String
Type is mutable, growable. So we need to allocate an amount of memory on the heap.
2.2 Ways Variables and Data Interact: Move
-
Integer (Allocated in Stack)
let x = 5; let y = x;
let y = x
make a copy of the value inx
and bind it toy
, and these two5
values are pushed onto the stack. -
String (Allocated in Heap)
Tips: String type is made up of three parts:
This group of data is stored on the stack, but
ptr
is a pointer to the memory in heap that holds the contents of the string.let s1 = String::from("hello"); let s2 = s1; println!("{}, world!", s1); //error // 'let s2 = s1' means rust considers s1 to no longer be valid // therefore, Rust doesn’t need to free anything when s1 goes out of scope.
When we assign s1 to s2, the String data is copied, meaning we copy the pointer, the length, and the capacity that are on the stack, but we do not copy the data on the heap that the pointer refers to.
In this example, we would say that
s1
was moved intos2
The data representation in memory looks:
2.3 Clone
Here’s an example of the clone
method in action, it’s like Deep Copy in C++.
The heap data does get copied, and s2 will have the memory in heap that holds the contents of the string.
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
2.4 Stack-Only Data: Copy
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y);
After let y=x
, x is still valid and wasn’t moved into y
.
The reason is that types such as integers that have a known size at compile time are stored entirely on the stack,
2.4 Ownership and function
fn main() {
let s1 = gives_ownership(); // gives_ownership moves its return
// value into s1
let s2 = String::from("hello"); // s2 comes into scope
let s3 = takes_and_gives_back(s2); // s2 is moved into
// takes_and_gives_back, which also
// moves its return value into s3
} // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was
// moved, so nothing happens. s1 goes out of scope and is dropped.
fn gives_ownership() -> String { // gives_ownership will move its
// return value into the function
// that calls it
let some_string = String::from("hello"); // some_string comes into scope
some_string // some_string is returned and
// moves out to the calling
// function
}
// takes_and_gives_back will take a String and return one
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
// scope
a_string // a_string is returned and moves out to the calling function
}
When a variable that includes data on the heap goes out of scope, the value will be cleaned up by drop
unless the data has been moved to be owned by another variable.