当前位置: 首页 > Web前端 > HTML

Rust入门系列的参考和借鉴

时间:2023-03-29 12:12:29 HTML

1。引用在很多场景下,我们可能只想读取一个变量指向的值,而不想获得它的所有权。这时候,我们就可以使用引用了。其实在很多其他的编程语言中,也有引用的概念。简单来说,引用就是创建一个变量指向另一个指针的地址,而不是直接指向该指针指向的堆内存地址。通过&地址运算符获取对指针变量的引用。例如,在Rust中,我们创建这样一个引用:lets1=String::from("hello");//获取s1的引用lets=&s1;下图很好的说明了关系变量s1是栈内存中的一个指针地址,ptr记录了堆内存中存储的String("hello")的地址变量s也存储在栈内存中,指针通过ptr记录s1的地址,实现对String("hello")的引用2.借用引用作为函数参数的行为称为借用,如何使用借用避免移动一个变量的所有权,我们可以看下面的例子:fnmain(){lets=String::from("hello!");//使用sReference作为入参,s的所有权不会移动letlen=get_length(&s);println!("{}的长度为{}",s,len);//hello!的长度is6}fnget_length(string:&String)->usize{//引用和变量一样,默认是不可变的//string.push_str("world");//`string`是一个`&`引用,所以它引用的数据不能被借用为可变的string.len()}3.变量引用从上面的例子我们可以知道,引用和变量一样,也是不可变的默认情况下,我们不能修改引用指向的值。但是如果你想这样做,你可以使用mut关键字将引用变成一个变量:fnmain(){letmuts=String::from("hello!");/**使用mut关键字,将s的变量引用作为入参,*这样s的所有权就不会被移动,并且s的值也可以通过函数中的变量引用来修改*/letlen=get_length(&muts);//在get_length函数中,我们实现了对s的修改println!("{}的长度为{}",s,len);//hello!world的长度为11}fnget_length(string:&mutString)->usize{//通过变量引用修改值string.push_str("world");string.len()}3.1变量引用的重要限制对应一个指针变量。在一个特定的范围内,只能有一个变量引用。道理也很容易理解。如果一个作用域中有两个对一个变量的可变引用,意味着可能有两个变量同时控制同一个内存空间,会发生数据竞争,容易运行3.1.1只能有一个同一范围内的可变引用。从例子中可以看出,当我们对变量origin进行两个可变引用时,编译时会直接报错fnmain(){letmutorigin=String::from("hello");让ref1=&mut原点;让ref2=&mut原点;//error:cannotborrow`origin`asmutableinthetimemorethanatimeprintln!("{},{}",ref1,ref2);}3.1.2可以有多个不可变引用如果多个不可变引用被用在同时,不会有这样的限制,因为immutableReferences实际上是只读的,不存在可能的内存安全风险。通过这个例子我们可以看到Rust允许这样使用:fnmain(){letorigin=String::from("hello");让ref1=&origin;让ref2=&origin;println!("{},{}",ref1,ref2);}3.1.3在某些场景下,可以存在多个可变引用从上面两个例子我们已经知道,如果一个作用域中有两个以上的可变引用,那么可能会出现Datarace,那么有没有一些场景会出现多个变量引用呢?我们看下面的例子:其实在程序执行过程中,只要作用域out了,作用域中的变量就会被释放。在这个例子中,当声明ref2时,ref1已经被销毁,所以仍然可以保证变量引用fnmain(){letmutorigin=String::from("hello");{letref1=&mut原点;println!("{}",ref1);}//当ref2被声明时,ref1已经被销毁letref2=&mutorigin;println!("{}",ref2);}3.1.4不能同时有可变引用和不可变引用对于指针变量,它的可变引用和不可变引用实际上是互斥的,不能同时存在时间。原因很简单。可变引用可以修改指向内存空间的值。当值被修改时,不可变引用的意义就不存在了。所以Rust在编译的时候会检查,如果发现这种情况,会直接报错:fnmain(){letmutorigin=String::from("hello");让ref1=&origin;letref2=&mutorigin;//不能借用`origin`作为可变的,因为它也被借用为不可变的println!("{}{}",ref1,ref2);}4.悬挂引用这是出现在C/C++等语言,描述的最重要的是一个变量指向的内存空间已经被释放或者分配给其他程序使用,但是这个变量仍然有效的场景。在Rust中,编译器会检查这种情况以避免悬挂引用。假设它可以编译,下面是生成悬挂引用的场景:fnmain(){lets=String::from("haha");//s的所有权被移动到helper的作用域leta=helper(s);/**假设编译成功:*调用helper时,释放了s指向的内存空间,但是helper中返回了s的引用,*其实这个引用是无效的,变量a变成一个悬空引用*/}fnhelper(s:String)->&String{println!("{}",s);&s//error:missinglifetimespecifier}但事实上,在编译时,Rust不允许helper返回对s的引用