1. rust中 if else 语句是表达式 它一定返回一个值,所以可以将其赋值给一个变量。比如:
let codition = true;
let x = if condition {5} else {6};
2. rust 函数体 可以用return x;返回值;也可以在最后一行用一个表达式来表示要返回的值;使用"->"表示函数返回值的类型 比如:
fn five()->i32 {
5
}
fn main(){
let x= five();
println!("The value of x is: {x}");
}
3. loop 循环 。可以使用 break 跳出循环 ,continue 进入下次循环。可以使用break 表达式,为loop循环返回值。可以使用 ’my_loop_label 写在loop关键字前,用来表示一个这样名称的标签,然后在作用域范围内例用 break my_loop_label 跳出这个指定的loop循环。如下代码:
let result = loop{
break 5;
}
'my_loop_label loop{
loop{
break 'my_loop_label;//直接结束外层循环
}
}
4. for 循环。 for 元素 in 集合{...};
let array = [1,2,3,4];
for element in array{
println("element is {element}");
}
4.1 for循环常和 Range 类型结合使用。Range是一个用圆括号和..来表示一个指定范围内的整数集合的类型,比如(1..4)表示1,2,3 即包含前面的不包含后面的。
for element in (1..5).rev(){
println("{element}");//打印出4 3 2 1
}
5.Rust的所有权机制
Box的所有者来管理堆内存释放
Rust会自动释放Box的堆内存
Rust内存释放机制
如果一个变量拥有一个Box(即该Box的所有权人是这个变量且仅是这个变量),当rust释放变量的frame(栈桢)时,Rust也会释放Box的堆(Heap)内存
Rust中,像Vec、String、HashMap等集合类型,都使用了Box
移动堆数据原则(所有权转移原则)
如果一个变量x将堆内存Heap所有权转移给另一个变量y,那么在移动后,变量x就不能再使用。
5.2 引用(引用是没有所有权的指针)
使用 "&" 符号加变量名的方式,用在函数形参中,这就是表示要为该函数传递一个引用类型的参数。引用是没有所有权的。
注意下图中,引用的本质,引用g1,g2指向了拥有所有权的变量m1,m2上,并不是直接指向堆。所以当引用超出作用范围时,并不会释放堆内存。
5.2.1 输出一个变量及其引用在栈内存上的地址的示例:
let a = String::from("Hello");
let reference_a = &a;
let address_in_reference_a = reference_a as *const String;
println!("a:{}",a);
println!("&a{{:p}},即变量a在Stack上的内存地址:{:p}",&a);
println!("reference_a:{}",reference_a);
println!("address_in_reference_a{{:p}},即reference_a的值的内容:{:p}",address_in_reference_a);
println!("&reference_a{{:p}},即变量reference_a在Stack上的内存地址:{:p}",&reference_a);
以下为输出结果:
a:Hello
&a{:p},即变量a在Stack上的内存地址:0x9bab8ff858
reference_a:Hello
address_in_reference_a{:p},即reference_a的值的内容:0x9bab8ff858
&reference_a{:p},即变量reference_a在Stack上的内存地址:0x9bab8ff870
- 以下代码打印出来的结果都是 hello world
let m = String::from("hello world");
println!("{}",m);
println!("{}",&m);
println!("{}",&&m);
5.2.2 解引用
解引用指针以方问数据,解引用运算符:* 看下图:
5.2.3 rust所有权机制设计的一些目的和手段
-
Rust中经常在【成员.方法名()】的用法中进行隐式的引用或解引用,看下图:
-
别名(堆内存的无所有权的直接引用者)和可变性不可同时存在(本质的意思是说不允许某个引用修改了它指向的堆上的数据但别的引用却不知道。避免空指针、保障线程安全)
换句话说:数据不应同时被别名引用而又具有可变性
比如下图阐述了一段会造成空指针问题的代码:
但是,可以通过间接方式(注意,这和别名引用不同),把变量(指向堆内存的)的引用赋给多个变量的方式来间接让多个变量访问同一块堆内存数据并且原变量还具有可变性,比如下图代码:
5.3 rust确保引用安全性的底层保障手段--借用检查器,数据在编绎器底层时被细分为三种不同的权限(读、写、拥有【移动、释放】)
下面是一个数据在被创建引用时,各变量自动获得和失去三种权限的一个动态变化情况:
在创建了另一个别名num后数,v同时失去了W和O的权限,只保留了R的权限。在打印那一语句执行完后,num及*num随即失去了三种权限,同时三种权限归还给了变量v。
而最后一行执行完后,当数据不再被后面代码使用到,则v立即失去三种权限,一旦数据所有者变量v失去数据所有权,则栈内存被释放的同时堆上的数据也被立即释放。个人体会:这种设计得以堆内存的数据随时为被释放做好准备,体现了Rust是高性能的语言高在了哪里。
以又是一个示例演练。
猜想:在执行完第二个语句后,x会重新获得堆数据的所有权,但是如果这之后没有再引用到变量x,则x同时会被释放栈和它指向的堆上的数据的内存。
5.4 权限定义于哪里?权限是定义在“位置”(Places)上的,任何可以放在赋值符号左边的位置都可以获得和改变权限。也包括它们的组合
比如:变量、解引用、数组元素、元组和结构体的成员访问,以及它们的组合比如:*((*a)[0].field1)
(个人理解不如把它们统称为“数据访问者”,它引发自己或其他数据访问者权限状态改变的改变 Trigger)
为什么随者位置的不再使用,“位置”会失去所有权?因为权限是互斥的。(个人阐述为随者数据访问者的先后触发权限改变,后触发者会改变前面触发者的权限状态,有时就是让前面触发者失去某些权限)如下图:
5.5 借用检查器的工作原理
借用检查器能发现权限违规。Rust在借用检查器里使用RWO等权限。借用检查器查找涉及引用的潜在不安全操作。下图简单示意了借用检查器的工作原理:
可变引用可能会临时降级为只读,如下图:
权限在引用生命周期结束时被返回,如下图:
如果有if else等分支控制语句,也是这样,一个引用生命周期开始和结束,都会影响到期他数据访问者的权限:
5.6 生命周期概念的前置背景
以下代码一和代码二,其函数无法通过编绎,提示缺少生命周期说明符。
代码一:(以下代码,从函数的两个输入参数无法确定函数的返回值的生命周期【一般情况下,出参和入参生命周期一致】)
代码二:(因为按照前面所学,在函数返回时a早已经超出生命周期而被释放了)
fn return_a_string()->&String{
let a = String::from("hello");
let b = &a;
return b;
}
代码三:(n是分配在栈上的值类型变量,在incr函数内部,m会在栈上创建,其值为n的地址,*m即对m解引用的结果就是n的值。该代码最终输出2)
fn incr(m: &mut i32) {
*m += 1;
}
let mut n=1;
incr(&mut n);
println!("{}",n);