Rust - 02 - Ownership
In other languages, the programmer must explicitly allocate and free the memory. Rust uses a third approach: memory is managed through a system of ownership with a set of rules that the compiler checks. If any of the rules are violated, the program won’t compile.
None of the features of ownership will slow down your program while it’s running.
Rust with the Stack/Heap
When your code calls a function, the values passed into the function (including, potentially, pointers to data on the heap) and the function’s local variables get pushed onto the stack. When the function is over, those values get popped off the stack.
Keeping track of what parts of code are using what data on the heap, minimizing the amount of duplicate data on the heap, and cleaning up unused data on the heap so you don’t run out of space are all problems that ownership addresses.
Ownership Rules
- Each value in Rust has an owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value will be dropped
Ownership Example
For hardcoded string literals
fn main() {
{ // s is not valid here, it’s not yet declared
let s = "hello"; // s is valid from this point forward
// do stuff with s
} // this scope is now over, and s is no longer valid
}
- When
s
comes into scope, it is valid. - It remains valid until it goes out of scope.
For mutable string we may use String
type:
fn main() {
let mut s = String::from("hello");
s.push_str(", world!"); // push_str() appends a literal to a String
println!("{}", s); // This will print `hello, world!`
}
Why can String
be mutated but literals cannot? The difference is in how these two types deal with memory.
Memory and Allocation (Lifetime)
Rust memory allocation strategy: the memory is automatically returned once the variable that owns it goes out of scope.
fn main() {
{
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
// longer valid
}
when s
goes out of scope. 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 of String
can put the code to return the memory. Rust calls drop
automatically at the closing curly bracket.
Another example:
let v1: &Vec<i32>;//-------------------------+
{// |
let v = Vec::new();//-----+ |v1's lifetime
v1 = &v;// | v's lifetime |
}//<-------------------------+ |
v1.len();//<---------------------------------+
Variables and Data Interacting (Move)
Rust will never automatically create “deep” copies of your data.
By default, Rust move
s the data on reassigning.
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 is MOVED to s2, s2 is the NEW OWNER
println!("{}, world!", s1); // Error: borrow of moved value: `s1`
}
// Unlike shallow copy, s1 was **moved** into s2 . And then s1 is invalidated.
Ownership in Functions
fn main() {
let s = String::from("hello"); // s comes into scope
takes_ownership(s); // s's value moves into the function...
// ... and so is no longer valid here
print!("{s}"); // Error: s moved and is NOT valid here
}
fn takes_ownership(s: String) {
println!("{}", s);
}
References and Borrowing
TL’DR
- At any given time, you can have either one mutable reference or any number of immutable references.
- References must always be valid.
Immutable References (Borrow , &)
Unlike an owner, there can be multiple borrowed references at the same time
For a reference, the value it points to will not be dropped when the reference stops being used
A borrower cannot access the resource after the owner has destroyed it
let v: Vec<i32> = Vec::new();
let v1 = &v; //v1 has borrowed from v
let v2 = &v; //v2 has also borrowed from v
v.len(); //allowed
v1.len(); //also allowed
v2.len(); //also allowed
Borrow is immutable by default
let s = String::from("hello");
let s2 = &s;
s2.push_str("world"); // Error: cannot borrow `s2` as mutable
Parameter References
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
} // Here, s goes out of scope. But because it does not have ownership of what
// it refers to, it is not dropped.
Mutable References (&mut)
Changes on mutable ref will reflect on the value it points to
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{s}"); // hello, world (var is mutated by the function 'change')
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
You cannot have mutable ref and immutable ref at same time. But they can be used when scopes are not overlapped.
You can have only 1 mutable ref. Or you can have many immutable refs.
let mut s = String::from("hello");
let r1 = &s; // no problem
let r2 = &s; // no problem
let r3 = &mut s; // BIG PROBLEM, you should not mutable the s
println!("{}, {}, and {}", r1, r2, r3);
Note that a reference’s scope starts from where it is introduced and continues through the last time that reference is used.
fn main() {
let mut s = String::from("hello");
{
let r1 = &s; // no problem
let r2 = &s; // no problem
println!("{} and {}", r1, r2);
// variables r1 and r2 will not be used after this point
} // scope ends
let r3 = &mut s; // no problem,
println!("{}", r3);
}
With ref and mutable ref. Rust can prevent data races at compile time. A data race is similar to a race condition and happens when these three behaviors occur:
- Two or more pointers access the same data at the same time.
- At least one of the pointers is being used to write to the data.
- There’s no mechanism being used to synchronize access to the data.
Rust prevents this problem by refusing to compile code with data races!
Dangling References
In languages with pointers, it’s easy to erroneously create a dangling pointer —a pointer that references a location in memory that may have been given to someone else—by freeing some memory while preserving a pointer to that memory.
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String { // dangle returns a reference to a String
let s = String::from("hello"); // s is a new String
&s // we return a reference to the String, s
} // Here, s goes out of scope, and is dropped. Its memory goes away.
// Here we have a dangling pointer
// To fix this issue, return 's' instead of '&s'
Slices
// String Slices
let s = String::from("hello");
let len = s.len();
// index starts from 0
let slice = &s[0..2];
let slice = &s[..2];
let slice = &s[0..len];
let slice = &s[..];
let slice = &s[3..len];
let slice = &s[3..];
// Array Slices
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
assert_eq!(slice, &[2, 3]);
String Literals are slices
let s = "Hello, world!";
// Actually the type of s is '&str'
// &str is an immutable reference.
Full Example for String Slices
fn first_word(s: &str) -> &str {
...
}
fn main() {
let my_string = String::from("hello world");
// `first_word` works on slices of `String`s, whether partial or whole
let word = first_word(&my_string[0..6]);
let word = first_word(&my_string[..]);
// `first_word` also works on references to `String`s, which are equivalent
// to whole slices of `String`s
let word = first_word(&my_string);
let my_string_literal = "hello world";
// `first_word` works on slices of string literals, whether partial or whole
let word = first_word(&my_string_literal[0..6]);
let word = first_word(&my_string_literal[..]);
// Because string literals **are** string slices already,
// this works too, without the slice syntax!
let word = first_word(my_string_literal);
}
相关文章
- Jgit的使用笔记
- 利用Github Action实现Tornadofx/JavaFx打包
- 叹息!GitHub Trending 即将成为历史!
- 微软软了?开源社区讨论炸锅,GitHub CEO 亲自来答
- GitHub Trending 列表频现重复项,前后端都没去重?
- Photoshop Elements 2021版本软件安装教程(mac+windows全版本都有)
- (ps全版本)Photoshop 2020的安装与破解教程(mac+windows全版本都有)
- (ps全版本)Photoshop cc2018的安装与破解教程(mac+windows全版本,包括2023
- 环境搭建:Oracle GoldenGate 大数据迁移到 Redshift/Flat file/Flume/Kafka测试流程
- 每个开发人员都要掌握的:最小 Linux 基础课
- 来撸羊毛了!Windows 环境下 Hexo 博客搭建,并部署到 GitHub Pages
- 超实用!手把手入门 MongoDB:这些坑点请一定远离
- 【GitHub日报】22-10-09 zustand、neovim、webtorrent、express 等4款App今日上新
- 【GitHub日报】22-10-10 brew、minio、vite、seaweedfs、dbeaver 等8款App今日上新
- 【GitHub日报】22-10-11 cobra、grafana、vue、ToolJet、redwood 等13款App今日上新
- Photoshop 2018 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2017 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2020 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2023 资源免费下载(mac+windows全版本都有,包括最新的2023)
- 最新版本Photoshop CC2018软件安装教程(mac+windows全版本都有,包括2023