在rust中,引用的意思的一个内存地址上数据用一个变量名来表示,而且只能有一个变量名同时有该内存上数据的所有权。如果直接使用=
,那么不是复制,而是发生了内存所有权的转移,代码实例:
fn main() {
let s1 = String::from("hello world !");
println!("s1 = {}", s1);
let s2 = s1; // s1的所有权转移给s2了,此时不能再用s1了
println!("s2 = {}", s2);
}
这种方式保证了任意时刻,每个内存地址块只有全局唯一一个所有权。这种方式存在一个缺陷,如果我们想在函数中使用一个堆内存上数据作为参数,那么参数会发生所有权转移,当函数结束时,对应的数据会被释放掉了,给出一个代码例子:
fn foo(s: String) {
println!("foo s = {}", s);
}
fn main() {
let s = String::from("hello world !");
foo(s);
// println!("s = {}", s); // 报错,因为所有权已经被转移到函数参数中了
}
上述情况,我们只是想要借用下s
的值,那么“借用”这个概念就是如此,仅仅获取内存上的值,但是不获取对应的所有权,内存模型如下:
在rust中借助符号&
实现,代码实例:
fn foo(s: &String) {
println!("foo s = {}", s);
}
fn main() {
let s = String::from("hello world !");
foo(&s);
println!("s = {}", s); // 这里是正确的,所有权还在
}
注意:借用的变量在第一次使用之后就失效了,除非重新借用! 给出代码实例:
fn main() {
let s = String::from("hello world !");
let s1 = &s;
println!("{}", s1); // 正确,执行完成后不再借用
// println!("{}", s1); // 错误,已经没了借用权了
}
对于可变引用来说,也是同样的道理。不过需要注意的是,可变引用一旦出现在作用域内,就不能其它的引用了。可以通过可变引用修改原来的值。但是,可变引用函数和可变引用可以同时出现,具体看下面的代码:
fn foo(s: &mut String) {
s.push_str(" ---test");
println!("foo s = {}", s);
}
fn main() {
let mut s = String::from("hello world !");
let s1 = &mut s; // 可变引用
s1.push_str(" ---test");
println!("s = {}", s1);
foo(&mut s); // 注意声明方式
}