首先,要搞清楚栈内存和堆内存对应了那些类型。rust的整型、浮点型、boo
l型、字面字符串型和tuple
型都是栈内存上的;如果使用=
,那么这些数据会拷贝一份新的内容。
然后,要了解rust的变量作用域,这点直接参考C++的即可。
最后给出Owership的规则:
String
在rust中是堆内存的内容,堆内存中的内容如果使用=
,那么默认是使用移动语义的,移动语义直接参考C++的std::move
即可。给出代码实例说明:
fn main() {
let str = "hello";
let s1 = String::from(str);
println!("s1 = {}", s1);
let s2 = s1;
println!("s2 = {}", s2);
// println!("s1 = {}", s1); // 直接调用是错误的,此时s1堆内存的owner已经是s2了
}
实际在内存中发生的情景
和C++的移动语义一样,内存中实际的控制权被转换到了s2中了,s1此时已经是空的了。
如果我们想要s1任然有效,那么可以通过克隆的方式,比如:
let s1 = String::from("hello");
let s2 = s1.clone();
在函数使用的时候,尤其要注意这个问题,给出代码实例:
fn main() {
let str = String::from("hello world !");
takes_ownership(str);
// println!("str = {}", str); // 直接调用会报错,因为已经被移动了
let str1 = String::from("hello world !");
takes_ownership(str1.clone()); // 可以安全调用,因为使用了clone了
println!("str1 = {}", str1);
}
fn takes_ownership(some_string: String) { // 一旦调用,外界的String所有权会被移动到这里
println!("takes_ownership(): {}", some_string);
}
上述代码中,takes_ownership
函数在调用后,原来的String
内容会被销毁,如果不想销毁,可以使用一个trick:
fn main() {
let str = String::from("hello world !");
let str1 = takes_ownership(str);
println!("str1 = {}", str1);
}
fn takes_ownership(some_string: String) -> String { // 一旦调用,外界的String所有权会被移动到这里
println!("takes_ownership(): {}", some_string);
some_string
}
函数内部使用expression
的方式返回即可