Rust使用ownership系统来管理内存,编译器会检查这些ownership系统的规则,一旦违反这些规则,则编译不通过
0. 堆和栈
编译期大小可知的数据,放在栈上
编译器大小不定,数据放在堆上,对应的指针放在栈上
1. Ownership的规则
-
Rust中每个值都有一个owner
-
任何时间有且仅有一个owner
-
当owner离开作用域之后,对应的值将会被删掉
2. 作用域
Rust中变量离开作用域之后,会被调用drop
方法
2.1 变量作用域
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
}
上面的代码注释详细给出了对应的变量作用域
2.2 heap对象的赋值操作
图片.png下面的赋值操作有个问题是,当s1,s2都离开作用域的时候,其对应的同一块内存会被释放两次,造成错误
let s1 = String::from("hello");
let s2 = s1; // s1赋值完之后,就不再有用了
println!("{}, world!", s1); // 到这一行没法编译
2.2.1 move != 浅拷贝
由于在Rust中,赋值完之后,并且失效了前一个变量,则不能称其为浅拷贝,而称其为move
2.2.2 clone=深拷贝
由于以上的原因,Rust不会主动去深拷贝数据,则需要我们显式的声明,见下面的代码:
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
}
2.3 stack对象的赋值操作
fn main() {
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y);
}
由于上述变量在编译器大小可知,则都是存储在栈上,没有深拷贝和浅拷贝的区别,可以看作是深拷贝
2.4 Ownership与函数
在Rust中,将一个值传递给函数,类似于将其赋值给一个变量
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
let x = 5; // x comes into scope
makes_copy(x); // x would move into the function,
// but i32 is Copy, so it's okay to still
// use x afterward
} // Here, x goes out of scope, then s. But because s's value was moved, nothing
// special happens.
fn takes_ownership(some_string: String) { // some_string comes into scope
println!("{}", some_string);
} // Here, some_string goes out of scope and `drop` is called. The backing
// memory is freed.
fn makes_copy(some_integer: i32) { // some_integer comes into scope
println!("{}", some_integer);
} // Here, some_integer goes out of scope. Nothing special happens.
明白了上面heap对象和stack对象的赋值操作,上述代码可以看出:
-
s
在之后就无法再用了,因为当其被传入函数的时候,就已经不是它自己了,除非是把自己clone一份 -
x
还可以再用,因为是一个深拷贝
2.5 函数返回值
赋值情况也是类似的道理
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 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("yours"); // some_string comes into scope
some_string // some_string is returned and
// moves out to the calling
// function
}
// This function takes a String and returns 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
}
如果我们想再拿回之前传入的值,在没有references的情况下,只能再返回出来
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)
}
Ref:
网友评论