引用
- &符号表示共享引用:允许你在引用某些值而不取得其所有权。
fn main()
{
let s1 = "rust".to_string();
let len = str_len(&s1);//传入的是s1的引用
print!("{} {}", s1.len(),len);
}
fn str_len(str : & String) -> usize
{
str.len()
}
- 如果要在共享引用的状态要改变数据的值,则会引起恐慌。通俗的理解是,你借用了别人的东西,正常情况下,你是不可以对你借用的东西做任何改动。把引用做为参数的行为,在rust里面也称为借用。
fn str_len(str : & String) -> usize
{
str.pop();//想要改变引用的数据的值
str.len()
}
这里编译时不通过的,会报以下错误:
3. 如果想在引用的时候能改变数据里面的值,则需要在数据前面加上mut指明传入的数据是可变的。
fn main()
{
let mut s1 = "rust".to_string();
let len = str_len(&mut s1);
print!("{} {}", s1.len(),len);
}
fn str_len(str : &mut String) -> usize
{
str.push_str(",hello");
str.len()
}
4.Rust的设计原则是,同⼀作⽤域内,对于某⼀个对象的引⽤,只允许存在两种情况:要么只有⼀个可变引⽤,要么同时存在多个共享引⽤,共享引⽤不允许修改内容,可变引⽤才有修改权限。
let mut s1 = "rust".to_string();
let s2 = &mut s1;
let s3 = &mut s1;
print!("{} {}",s2,s3);
会报以下错误:
error[E0499]: cannot borrow `s1` as mutable more than once at a time
--> src/main.rs:7:14
|
6 | let s2 = &mut s1;
| ------- first mutable borrow occurs here
7 | let s3 = &mut s1;
| ^^^^^^^ second mutable borrow occurs here
8 |
9 | print!("{} {}",s2,s3);
| -- first borrow later used here
这样做的原因是为防止数据竞争,数据竞争在编译时很难被发现,只有在运行时才出现,rust的单个可变引用在根本上解决了这种问题,可能会发生数据竞争的几种情况:
- 两个或多个指针同时访问同一个数据时;
- 到少有一个指针用于写入数据;
- 没有使用任何机制来同步对数据的访问;
5.但可以通过创建新的作用域,非同时创建多个可变引用。
let mut s1 = "rust".to_string();
{
let s2 = &mut s1;
}
let s3 = &mut s1;
6.不可以同时拥有一个可变的引用和一个不可变的引用。
let mut s1 = "rust".to_string();
let s2 = &s1;
let s3 = &mut s1;
print!("{} {}", s2.len(),s3.len());
报错:
error[E0502]: cannot borrow `s1` as mutable because it is also borrowed as immutable
--> src/main.rs:9:14
|
7 | let s2 = &s1;
| --- immutable borrow occurs here
8 |
9 | let s3 = &mut s1;
| ^^^^^^^ mutable borrow occurs here
...
16 | print!("{} {}", s2.len(),s3.len());
| -------- immutable borrow later used here
- 在Rust中,编译器可以保证引用永远都不是悬空引用。
悬空引用是指一个指针引用了内存中的某个地址,而这块内存可能已经释放并分配给其它数据使用,在rust里,如果引用了某些数据,编译器将保证在引用离开作用域之前数据不会离开作用域。
fn main()
{
let s = dangle_ref();
}
fn dangle_ref() -> &String
{
let str = "rust".to_string();
&str
}
报错:
error[E0106]: missing lifetime specifier
--> src/main.rs:8:20
|
8 | fn dangle_ref() -> &String
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
8 | fn dangle_ref() -> &'static String
| ~~~~~~~~
这里的str的生命周期出了函数作用域后就不起作用了。
8.rust 与C++的区别在于,C++中有一种引用,并且是可变的,但rust中的类型,如果没有实现Copy trait,那么在此类型的变量赋值、函数入参、函数返回值都是move语义。C++ 11 之后也有move语法。