首页 > 其他分享 >借用和引用

借用和引用

时间:2023-08-03 23:11:21浏览次数:29  
标签:String 作用域 some let 引用 借用 string

所有权

Rust通过所有权来管理内存,最妙的是,这种检查只发生在编译期,因此对于程序运行期,不会有任何性能上的损失。

使用堆和栈的性能区别:

写入方面:入栈比在堆上分配内存要快。 因为入栈时操作系统无需分配新的空间,只需要将新数据放入栈顶即可。相比之下,在堆上分配内存则需要更多的工作,这是因为操作系统必须首先找到一块足够存放数据的内存空间,接着做一些记录为下一次分配做准备。

读取方面:出栈比读取堆上的数据快。 栈数据往往可以直接存储在 CPU 高速缓存中,而堆数据只能存储在内存中。访问堆上的数据比访问栈上的数据慢,因为必须先访问栈再通过栈上的指针来访问内存。

因此,处理器处理分配在栈上数据会比在堆上的数据更加高效。

 

Rust的所有权原则:

  1. Rust 中每一个值都被一个变量所拥有,该变量被称为值的所有者

  2. 一个值同时只能被一个变量所拥有,或者说一个值只能拥有一个所有者

  3. 当所有者(变量)离开作用域范围时,这个值将被丢弃(drop)

简单说就是每一个值(堆上的值)有且只有一个所有者(变量),当这个变量出了作用域,那么这个值也被丢弃(在堆上也会丢弃)。

 

看一段代码:

fn main(){
   let x: &str = "hello world";
   let y = x;
   println!("{},{}",x,y);
}

这段代码并不会报错,这是因为 x 在这里只是引用了字符串,没有所有权,所以 let y = x; 是对引用的拷贝,不会有所有权的转移(具体看下一节 “引用与借用” )

 

函数的传参和返回:

传参:

fn main() {
   let s = String::from("hello");  // s 进入作用域
   takes_ownership(s);             // s 的值移动到函数里
   // s 所以到这里不再有效

   let x = 5;                      // x 进入作用域
   makes_copy(x);                  // x 应该移动函数里,
   // 但 i32 是 Copy 的,所以在后面可继续使用 x

} // 这里, x 先移出了作用域,然后是 s。但因为 s 的值已被移走,
 // 所以不会有特殊操作

fn takes_ownership(some_string: String) { // some_string 进入作用域
   println!("{}", some_string);
} // 这里,some_string 移出作用域并调用 `drop` 方法。占用的内存被释放

fn makes_copy(some_integer: i32) { // some_integer 进入作用域
   println!("{}", some_integer);
} // 这里,some_integer 移出作用域。不会有特殊操作

返回:

fn main() {
   let s1 = gives_ownership();         // gives_ownership 将返回值移给 s1

   let s2 = String::from("hello");     // s2 进入作用域

   let s3 = takes_and_gives_back(s2);  // s2 被移动到takes_and_gives_back 中,它也将返回值移给 s3
}
// 这里,
// s3 移出作用域并被丢弃。
// s2 也移出作用域,但已被移走,所以什么也不会发生。
// s1 移出作用域并被丢弃

fn gives_ownership() -> String {  
   let some_string = String::from("hello"); // some_string 进入作用域.
   some_string                              // 返回 some_string 并移出给调用的函数
}

// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(a_string: String) -> String { // a_string 进入作用域
   a_string  // 返回 a_string 并移出给调用的函数
}

引用和借用

在 Rust 中,获取变量的引用叫做借用

引用:&x,解引用:*x;

 

用在函数参数和函数返回值:

fn main() {
   let s1 = String::from("hello");
   let len = calculate_length(&s1);
   println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
   s.len()
}

 

可变引用

引用默认是不能修改值的,想要修改值需要使用可变引用:

fn main() {
   let mut s = String::from("hello");
   change(&mut s);
}

fn change(some_string: &mut String) {
   some_string.push_str(", world");
}

要注意的是,特定数据的可变引用在同一个作用域只能存在一个,并且,可变引用和不可变引用不能同时存在。

新旧编译器的引用作用域不同,旧编译器(1.31之前)的引用作用域结束于最近的花括号处,而新编译器的引用作用域改变为 最后一次使用的位置。

这种优化行为叫做 Non-Lexical LifeTimes(NLL).

 

悬垂引用

指引用指向某个值后,值被释放掉,指针仍然存在的情况。

在 Rust 中编译器可以确保引用永远也不会变成悬垂状态:当你获取数据的引用后,编译器可以确保数据不会在引用结束前被释放,要想释放数据,必须先停止其引用的使用。

释放引用:

fn dangle() -> &String { // dangle 返回一个字符串的引用
   let s = String::from("hello"); // s 是一个新字符串
  &s // 返回字符串 s 的引用
} // 这里 s 离开作用域并被丢弃。其内存被释放。
 // 危险!

// 应该更改为
fn no_dangle() -> String {
   let s = String::from("hello");
   s
}
 

标签:String,作用域,some,let,引用,借用,string
From: https://www.cnblogs.com/heymeteor/p/17604735.html

相关文章

  • 10.智能指针出现循环引用怎么解决
    10.智能指针出现循环引用怎么解决?弱指针用于专门解决shared_ptr循环引用的问题,weak_ptr不会修改引用计数,即其存在与否并不影响对象的引用计数器。循环引用就是:两个对象互相使用一个shared_ptr成员变量指向对方。弱引用并不对对象的内存进行管理,在功能上类似于普通指针,然而一个比......
  • 8.智能指针的循环引用
    8.智能指针的循环引用循环引用是指使用多个智能指针share_ptr时,出现了指针之间相互指向,从而形成环的情况,有点类似于死锁的情况,这种情况下,智能指针往往不能正常调用对象的析构函数,从而造成内存泄漏。举个例子:#include<iostream>usingnamespacestd;template<typenameT>cl......
  • C++逆向分析——引用
    voidmain(){intx=1;int&ref=x;ref=2;printf("%d\n",ref);return;}反汇编代码:intx=1;00724A5FC745F401000000movdwordptr[x],1int&ref=x;00724A668D45F4lea......
  • 白日梦的Elasticsearch实战笔记,ES账号免费借用、32个查询案例、15个聚合案例、7个查询
    目录一、导读二、福利:账号借用三、_searchapi搜索api3.1、什么是querystringsearch?3.2、什么是querydsl?3.3、干货!32个查询案例!四、聚合分析4.1、什么是聚合分析?4.2、干货!15个聚合分析案例五、7个查询优化技巧欢迎关注一、导读Hi!大家久等了!时隔10天,白日梦的Elasticsearch笔记......
  • VS2022 PCL库引用配置
    嫌麻烦的可以直接下载PCL1.13.1安装在D盘然后复制我的配置就行.VC++目录包含目录D:\PCL1.13.1\3rdParty\OpenNI2\Include;D:\PCL1.13.1\3rdParty\VTK\include\vtk-9.2;D:\PCL1.13.1\3rdParty\Qhull\include;D:\PCL1.13.1\3rdParty\FLANN\include;D:\PCL1.13.1\3rdParty\Ei......
  • 引用与借用
    引用(reference)像一个指针,因为它是一个地址,我们可以由此访问储存于该地址的属于其他变量的数据。与指针不同,引用确保指向某个特定类型的有效值。点击查看代码fnmain(){lets1=String::from("hello");letlen=calculate_length(&s1);println!("Theleng......
  • C++ | 引用
    引用&使用引用intb=33,&a=b;b=17;cout<<a;//打印a为17使用引用声明变量类似于指针,声明的变量会同被引用的变量绑定,修改任何一方的数据都会使另一方的数据也改变。使用上的区别在于使用引用不需要*,引用可以理解为一个别名。在函数中使用引用传递参数将参......
  • 怎么还有函数参数不支持引用的?(Excel函数集团)
    函数公式中的参数绝大部分情况下是可以用以下四种:常量引用公式运算(包括函数、四则运算等)自定义名称有少部分函数的参数只支持引用,比如Sumif的第一、第三参数,Subtotal除第一参数以外的其他所有参数等等。但是,有一个函数的参数的特殊用法,只要是引用就会甩脸子,这个函数就是XL......
  • C# 使用SIMD向量类型加速浮点数组求和运算(4):用引用代替指针, 摆脱unsafe关键字,兼谈Unsa
    作者:zyl910目录一、引言二、办法说明2.1历史2.2局部引用变量与引用所指的值(类似指针的地址运算符&、间接运算符*)2.3重新分配局部引用变量(类似指针直接赋值)2.4引用地址调整(类似指针加减法)2.5引用地址比较(类似指针比较)2.6重新解释(类似C++的reinterpret_cast)2.7引用取消只......
  • 重温C#中的值类型和引用类型
    在C#中,数据类型分为值类型和引用类型两种。引用类型变量存储的是数据的引用,数据存储在数据堆中,而值类型变量直接存储数据。对于引用类型,两个变量可以引用同一个对象。因此,对一个变量的操作可能会影响另一个变量引用的对象。对于值类型,每个变量都有自己的数据副本,并且对一个变量的......