1.概述Rust是一种编译型语言(AOT-aheadoftime),需要编译后才能生成可执行代码,这与JavaScript等解释型语言有着根本的区别。2.变量和可变性Rust使用let来声明变量,但let声明的变量默认是不可变(_Immutable_)变量。如果让声明一个变量并试图修改它的值,编译时会报错。fnmain(){让a=5;一=6;//error:cannotassigntwicetoimmutablevariable}我们可以用下面两种方法来解决这个问题让声明变量用mut关键字修饰,说明是可变变量。需要注意的是,Rust是强类型语言,所以即使声明为可变变量,也只能重新赋值给相同数据类型的值fnmain(){letmuta=5;一=6;//改变数据类型,编译错误a="6";//error:expectedinteger,found`&str`}使用阴影特性,再次声明该变量覆盖之前的值,不受之前数据类型的限制。相当于重新声明,隐藏前一个变量fnmain(){leta='5';//'5'让a=5;//5让a=a+1;//6让a=a*2;//12}3.常量在Rust中,常量是通过const关键字声明的。常量和变量的区别在于不能使用mut关键字。常量在声明时必须指定数据类型。常量可以声明在任何作用域,包括Global作用域的常量只能绑定常量表达式命名约定:所有字母大写,单词用_连接,如constMAX_AGE:u32=10_0000;4.数据类型4.1标量类型4.1.1整数类型有符号整数使用i以$$[-(2^n-1),2^{n-1}-1]$$开头无符号整数使用u以$$开头[0,2^n-1]$$isize和usizetype位数由程序运行的计算机的体系结构决定。在64位计算机上,64位整数的默认类型是i324.1.1.1。整数文字使用0x表示十六进制,使用0o表示八进制。二进制以0b开头,字节类型只以u8开头,除字节类型外都用b开头,所有数字字面量都允许类型后缀,比如//表示u8类型的值57leta=57u8;4.1。1.2整数溢出如果将u8(0-255)类型的变量设置为256,会出现如下情况:在开发模式下,Rust检测到溢出,程序运行时会panic。在发布模式下,Rust不会检测溢出。发生溢出时进行换行:256->0257->1...4.1.2Float类型f32,单精度f64,双精度(Rustfloats的默认类型,因为f64和f32在现代CPU上速度差不多same)Rust浮点类型使用IEEE-754标准4.1.3Boolean类型占用一个字节符号为bool,值为true|false4.1.4字符类型符号是使用单引号的字符字面值4.2复合类型4.2.1元素组(元组)的长度在声明后是不可变的。您可以组合不同数据类型的值。//声明一个元组让tup:(i32,f64,u8)=(500,5.6,23);//获取元组的成员//1.解构let(x,y,z)=tup;println!("{},{},{}",x,y,z);//500,5.6,23//2.点符号println!("{},{},{}",tup.0,tup.1,tup.2);//500,5.6,234.2.2数组和元组一样,声明后不可变长度的数组成员的数据类型必须相同栈内存中存储的数组类型用[type;长度]让arr:[i32;5]=[1,2,3,4,5];//特殊数组声明方法letsameMemberArray=[3;5];//[3,3,3,3,3]//访问数组成员letf=arr[0];//1//越界访问数组-Rust编译器将执行简单的越界检查letmore=arr[6];//编译错误//越界访问数组-rust编译器无法检测场景lettemp=[6,7,8,9];letmore_temp=arr[temp[0]];//编译5.使用fn关键字在Rust中声明函数。对于函数和变量名,使用snakecase规范命名(单词小写,使用_拼接)。参数在定义时必须指定数据类型。如果你想提前返回一个值,那么使用return关键字函数默认的返回值是一个空元组fnmain(){letnumber=get_number(5);println!("{}",数字);//10}fnget_number(a:i32)->i32{//如果函数的最后一行是表达式,那么表达式的值将作为函数的返回值//如果分号是添加在行尾,会被识别为语句,不会作为函数a+5}6的返回值。控制流程6.1条件分支-if需要注意的是,如果每个分支块都有返回值,数据类型必须相同leta=3;//ifelseifa==3{println!("ais3");}else{println!("aisnot3");}//利用表达式的特点,实现其他语言中三元表达式的效果letb=ifa==3{5}否则{6};//56.2Looploop循环会无限循环地执行循环体中的代码,直到被break中断break可以为loop循环表达式提供返回值//looploopletmutcount=0;letvalue=loop{count+=1;如果计数==10{中断计数*2;}}println!("{}",值);//20whileletarr=[1,2,3,4,5];letmutindex=0;//使用while循环遍历数组whileindex<5{println!("{}",arr[index]);index=index+1;}forletarr=[1,2,3,4,5];foriteminarr.iter(){println!("foritem{}",item);}//使用范围达到指定的循环次数//1.(1..5)->一个包含1,2,3,4的Iterator//2.使用rev方法对(1..5).rev中的item进行逆向(){println!("rangeitemis{}",item)}7.OwnershipOwnership是Rust的核心特性,可以在不使用GC的情况下保证内存安全7.1内存和分配当变量超出作用域时,Rust会自动调用drop函数将内存空间还给操作系统7.2Stack上的数据复制:copy是针对Simplescalar数据类型,下面的代码最终会将两个5压入栈中,本质上是因为标量类型实现了CopytraitCopy这个trait用于存储在栈中的数据类型,如整型,需要分配内存的数据类型都不能实现这个trait如果实现了Copytrait,旧变量赋值后仍然可以使用(需要满足成员都是具有Copy特征的数据类型)letx=5;lety=x;println!("{},{}",x,y);//5,57.3变量与数据的交互方式:move对应一种长度未知的复合数据类型,一个变量赋值给另一个变量后,前者就失效了(在Rust中叫做move,即内存空间s1指向的被移动到s2,移动完成后s1会失效,避免s1和s2超出作用域时相同内存空间的doublefree操作)doublefree是一个严重的bug其他需要手动控制内存的语言,可能会释放其他程序正在使用的内存,造成未知问题lets1=String::from("haha");lets2=s1;println!("{}",s1);//错误:move7.4后这里借用的值所有权类似于函数实际传值给函数和变量的情况。移动或复制发生main(){letstring=String::from("hello");//移动,所有权被移动并传递到函数作用域中move_case(string);/**调用move_case时,string指向的内存空间的所有权已经被移动。*调用move_case时,string指向的内存空间已经释放。*所以后面如果访问string,编译时会报错*///println!("{}",string);//移动后在这里借用的值//--------------------------------------------------------------------让数字=12;//复制,传入number值的副本copy_case(number);/**number是一个简单的标量类型,实现了Copytrait*调用copy_case时,只传入一个副本,*所以后面可以继续使用*/println!("{}",number);//-----------------------------------------------------------------让bar=String::from("bar");/**下面函数的调用过程中,将bar指向的内存空间的所有权移至函数作用域,*take_ownership_and_return该函数的作用是获取一块内存空间的所有权并归还,*最后foo取得了内存空间的所有权,其实这段代码的效果和letfoo=bar;是一样的。*/letfoo=take_ownership_and_return(bar);println!("{}",foo)}fnmove_case(string:String){println!("{}",string);}fncopy_case(number:u32){println!("{}",number);}fntake_ownership_and_return(s:String)->String{s}8.Stack&Heapstack是一个连续的内存空间。堆是一个散列的内存空间。指向堆内存的指针存储在堆栈中。存储在堆栈上的所有数据必须具有已知大小。运行时大小未知或运行时大小可能变化的数据必须存储在堆上
