半小时学习Rust

2021-01-02 15:05:20

为了提高编程语言的流利程度,必须阅读大量的语言,但是如果您不知道它的含义,又怎么能阅读很多呢? 在本文中,我将不着重于一个或两个概念,而是尝试尽可能多地浏览Rust片段,并解释它们所包含的关键字和符号的含义。 让x:i32; //'i32'是一个有符号的32位整数x = 42; //有i8,i16,i32,i64,i128 //也有u8,u16,u32,u64,u128(无符号) 如果您声明一个名称并在以后对其进行初始化,则编译器将阻止您在对其进行初始化之前使用它。 下划线_是一个特殊名称-或更确切地说,是"缺少名称"。 从根本上讲,它意味着丢弃某些东西: //这没什么用,因为42是常数let _ = 42; //这会调用`get_thing`,但会丢弃其结果let _ = get_thing(); 以下划线开头的名称是常规名称,只是编译器不会警告它们未被使用:

//我们最终可能会使用_x,但是我们的代码仍在开发中//我们现在只想摆脱编译器警告。 令_x = 42; 可以引入具有相同名称的单独绑定-您可以隐藏变量绑定: 令x = 13; 令x = x + 3; //在该行之后使用`x`仅表示第二个`x`,//第一个`x`不再存在。 Rust具有元组,您可以将其视为不同类型的值的固定长度集合。 执行任务时,元组可以被解构,这意味着它们被分解为各自的字段: 当然,在破坏元组时,可以使用_丢弃其中的一部分: 让x = vec! [1、2、3、4、5、6、7、8]。 iter()。 映射(| x | x + 3)。 折叠(0,| x,y | x + y);

这是一个返回32位带符号整数的函数。 Thearrow指示其返回类型: //这会先打印" in&#34 ;,然后打印" out" fn main(){让x =" out" ; {//这是一个不同的`x`,让x =" in" ; println! (X ) ; } println! (X ) ;} 令x = {令y = 1; //第一条语句让z = 2; //第二条语句y + z //这是* tail *-整个块将求值} 这就是为什么在函数末尾省略分号的原因 与返回相同,即 这些是等效的: fn fair_dice_roll()-> i32 {match feel_lucky {true => 6,false => 4,}} 让a =(10,20); a。 0分 //这是10个let amos = get_some_struct(); amos。 昵称; //这是" fasterthanlime" 在此示例中,std是一个板条箱(〜一个库),cmp是一个模块(〜一个源文件),min是一个函数:

在use指令中,花括号具有另一种含义:它们是globs"。 如果要同时导入min和max,则可以执行以下任一操作: //这有效:使用std :: cmp :: min; 使用std :: cmp :: max; //这也可以:使用std :: cmp :: {min,max}; //这也有效! 使用std :: {cmp :: min,cmp :: max}; 让x =" amos" 。 len(); //这是4个让x = str :: len(" amos"); //这也是4 //`Vec`是常规结构,而不是原始类型let v = Vec :: new(); //这是完全相同的代码,但带有`Vec`的* full *路径,让v = std :: vec :: Vec :: new(); 令v1 = Vec2 {x:1.0,y:3.0}; 令v2 = Vec2 {y:2.0,x:4.0}; //顺序无关紧要,只有名称才重要 这就是所谓的“结构更新语法”,它只能在最后一个位置出现,并且不能跟逗号。 令v = Vec2 {x:3.0,y:6.0}; 令Vec2 {x,y} = v; // x的值现在是3.0,y的值现在是6.0

struct Number {奇数:布尔,值:i32,} fn main(){设一个= Number {奇数:true,值:1};设两个= Number {奇数:false,值:2}; print_number(一个); print_number(two);} fn print_number(n:Number){如果让Number {奇数:true,值} = n {println! ("奇数:{}&#34 ;,值); } if if让Number {奇数:false,值} = n {println! ("偶数:{}&#34 ;,值); }} //打印://奇数:1 //偶数:2

fn print_number(n:Number){匹配n {Number {奇数:true,值} => println! ("奇数:{}&#34 ;,值),数字{奇数:false,值} => println! (" Even number:{}&#34 ;, value),}} //与以前一样打印

fn print_number(n:Number){match n {Number {value:1,..} => println! (" One"),数字{value:2,..} => println! (" Two"),数字{value,..} => println! (" {}&#34 ;, value),//如果最后一个臂不存在,我们将得到一个编译时错误}}

fn print_number(n:Number){匹配n。值{1 => println! (" One"),2 => println! (" Two"),_ => println! (" {}&#34 ;, n.value),}}

结构编号{奇数:布尔值,值:i32,}展示编号{fn is_strictly_positive(self)->布尔{自我。值> 0}}

fn main(){let minus_two = Number {奇数:false,值:-2,}; println! (" positive?{}&#34 ;, minus_two.is_strictly_positive()); //这会显示"错误"}

fn main(){令n =数字{奇数:true,值:17,}; n。奇=假; //错误:无法分配给`n.odd`,//因为`n`没有声明为可变的}

fn main(){令n =数字{奇数:true,值:17,}; n =数字{奇数:false,值:22,}; //错误:无法两次分配给不可变变量`n`}

fn main(){let mut n = Number {奇数:true,值:17,} n。价值= 19; // 都好}

表示数字{fn is_strictly_negative(self)->布尔{自我。值< 0}} fn main(){令n =数字{奇数:false,值:-44}; println! (" {}&#34 ;, n.is_strictly_negative()); //打印" true"}

impl代表i32 {fn is_strictly_negative(self)->布尔{self< 0}} fn main(){让n:i32 =-44; println! (" {}&#34 ;, n.is_strictly_negative()); //打印" true"}

//`Neg`特性用于重载一元减号运算符`-`。 impl std :: ops :: Neg for Number {类型Output = Number; fn neg(self)-> Number {Number {value:-self。值,奇数:自我。奇数,}}} fn main(){设n =数字{奇数:真,值:987};令m = -n; //这仅可能是因为我们实现了`Neg` println! (" {}&#34 ;, m.value); //打印" -987"}

一个impl块始终是一种类型,因此在该块内部,Selfmeans就是该类型:

impl std :: ops :: Neg for Number {type Output = Self; fn neg(self)->自我{自我{值:-自我。值,奇数:自我。奇数,}}}

有些特征是标记-它们不是说类型实现某些方法,而是说某些事情可以用类型来完成。

fn main(){让a:i32 = 15;令b = a; //复制a,让c = a; //`a`被再次复制}

fn print_i32(x:i32){println! (" x = {}&#34 ;, x);} fn main(){让a:i32 = 15; print_i32(a); //复制`a` print_i32(a); //`a`被再次复制}

fn main(){令n =数字{奇数:true,值:51};令m = n; //`n`被移入`m` let o = n; //错误:使用移动值:`n`}

fn print_number(n:Number){println! (" {}数字{}&#34 ;,如果n.odd {" odd"}否则{" even"},n.value);} fn main( ){让n =数字{奇数:是,值:51}; print_number(n); //`n`被移动print_number(n); //错误:使用移动值:`n`}

fn print_number(n:& Number){println! (" {}数字{}&#34 ;,如果n.odd {" odd"}否则{" even"},n.value);} fn main( ){让n =数字{奇数:是,值:51}; print_number(& n); //在调用print_number(& n)的时间内借入`n`; //`n`再次借用}

如果一个函数采用了可变的引用,它也可以工作-但前提是我们的变量绑定也是mut。

fn反转(n:& mut号){n。值= -n value;} fn print_number(n:& Number){println! (" {}数字{}&#34 ;,如果n.odd {" odd"}否则{" even"},n.value);} fn main( } {//这次,'n`是可变的let mut n = Number {奇数:true,值:51}; print_number(& n);反转(& mut n); //`n是可变借用的-一切都是显式的print_number(& n);}

impl std :: clone ::克隆数字{fn clone(& self)->自我{自我{.. *自我}}}

fn main(){令n =数字{奇数:true,值:51};让mut m = n。克隆();米值+ = 100; print_number(& n); print_number(& m);}

//注意:`Copy`要求实现`Clone`也是impl std :: clone ::克隆数字{fn clone(& self)-> Self {Self {.. * self}}} impl std :: marker ::复制数字{}

fn main(){令n =数字{奇数:true,值:51};令m = n。克隆();令o = n。克隆();}

fn main(){令n =数字{奇数:true,值:51};令m = n; //`m`是`n`的副本let o = n; //相同。 n既不移动也不借用。}

#[derive(Clone,Copy)] struct Number {奇数:布尔值,值:i32,} //扩展为“ impl Clone for Number”和“ impl Copy for Number”块。

它们可以具有多个类型参数,然后可以在函数的声明及其主体中使用它们,而不是具体的类型:

fn打印< T:显示> (值:T){println! (" value = {}&#34 ;, value);} fn print< T:调试> (值:T){println! (" value = {:?}&#34 ;, value);}

使用std :: fmt :: Debug; fn比较< & (左:T,右:T)其中T:Debug + PartialEq,{println! (" {:?} {} {:?}&#34 ;,如果左边==右边{" =="}否则{"!=&#34 ;},正确);} fn main(){比较(" tea&#34 ;," coffee"); //打印:" tea" !="咖啡"}

泛型函数可以被视为名称空间,其中包含具有不同具体类型的无穷函数。

与板条箱,模块和类型相同,可以使用::浏览和导航泛型函数(导航?)。

fn main(){使用std :: any :: type_name; println! (" {}&#34 ;, type_name ::< i32>()); //打印" i32" println! (" {}&#34 ;, type_name ::<(f64,char)>()); //打印"(f64,char)"}

结构对& {a:T,b:T,} fn print_type_name< & (_val:& T){println! (" {}&#34 ;, std :: any :: type_name ::< T>());} fn main(){让p1 = Pair {a:3,b:9};令p2 =对{a:true,b:false}; print_type_name(& p1); //打印" Pair< i32>" print_type_name(& p2); //打印" Pair< bool>"}

fn main(){让mut v1 = Vec :: new(); v1。推(1);让mut v2 = Vec :: new();第2版​​。推(假); print_type_name(& v1); //打印" Vec< i32>" print_type_name(& v2); //打印" Vec< bool>"}

说到Vec,它带有一个宏,该宏或多或少地提供了&veve字面量&#34 ;:

fn main(){让v1 = vec! [1,2,3];让v2 = vec! [true,false,true]; print_type_name(& v1); //打印" Vec< i32>" print_type_name(& v2); //打印" Vec< bool>"}

恐慌也是一个宏。如果启用了错误消息,则会猛烈停止执行,并显示错误的文件名/行号:

有些方法也惊慌失措。例如,Option类型可以包含某些内容,也可以不包含任何内容。如果在其上调用.unwrap(),并且不包含任何内容,则会出现恐慌:

fn main(){设o1:选项< i32> =约(128); o1解开(); //这很好,让o2:Option< i32> =无; o2解开(); //这恐慌!} //输出:thread' main'在``src / libcore / option.rs:378:21''的``无''值上惊慌于名为``Option :: unwrap()`''

枚举Option< & {None,Some(T),} impl< &选项< & {fn unwrap(self)-> T {//枚举变量可以在模式中使用:match self {Self :: Some(t)=> t,Self :: None =>恐慌 ! (" .unwrap()在None选项上调用"),}}}使用self :: Option :: {None,Some}; fn main(){设o1:选项< i32> =约(128); o1解开(); //这很好,让o2:Option< i32> =无; o2解开(); //这恐慌!} //输出:thread' main'惊恐于' .unwrap()调用了None选项,src / main.rs:11:27

fn main(){// x不存在{让x = 42; //`x`开始现有的println! (" x = {}&#34 ;, x); //`x`停止存在} //`x`不再存在}

fn main(){// x不存在{让x = 42; //`x`开始现有的let x_ref =& x; //`x_ref`开始存在-它借用`x` println! (" x_ref = {}&#34 ;, x_ref); //`x_ref`停止存在// //`x`停止存在} //`x`不再存在}

fn main(){让x_ref = {让x = 42; & x}; println! (" x_ref = {}&#34 ;, x_ref); //错误:`x`寿命不够长}

fn main(){令x = 42;令x_ref1 =& x;令x_ref2 =& x;令x_ref3 =& x; println! (" {} {} {}&#34 ;, x_ref1,x_ref2,x_ref3);}

fn main(){让mut x = 42;让x_ref =& x; x = 13; println! (" x_ref = {}&#34 ;, x_ref); //错误:由于被借用,因此无法分配给x}

fn main(){让mut x = 42;令x_ref1 =& x;令x_ref2 =& mut x; //错误:无法借用可变的`x`,因为它也借作不可变的println! (" x_ref1 = {}&#34 ;, x_ref1);}

fn print(x:& i32){//在整个调用此函数的整个过程中(从外部)借入了x。

struct Number {value:i32,} fn number_value< ' > (num:& a Number)-> & ' i32 {#。值} fn main(){设n =数字{值:47};令v = number_value(& n); //`v`借用`n`(不可变),因此:`v`不能超过`n`。 //尽管存在`v`,但是不能可变地借用,改变或移动`n`}

当只有一个输入生存期时,不需要命名它,并且所有内容都具有相同的生存期,因此以下两个函数是等效的:

fn number_value< ' > (num:& a Number)-> & ' i32 {#。 fn number_value(num:& Number)-> & i32 {#。值}

结构NumRef< ' > {x:& ' a i32,} fn main(){让x:i32 = 99;让x_ref = NumRef {x:& x}; //`x_ref`不能超过`x`等,}

结构NumRef< ' > {x:& ' i32,} fn as_num_ref< ' > (x:&' a i32)-> NumRef< ' > {NumRef {x:& x}} fn main(){让x:i32 = 99;让x_ref = as_num_ref(& x); //`x_ref`不能超过`x`等,}

结构NumRef< ' > {x:& ' i32,} fn as_num_ref(x:& i32)-> NumRef< ' _> {NumRef {x:& x}} fn main(){让x:i32 = 99;让x_ref = as_num_ref(& x); //`x_ref`不能超过`x`等,}

暗示' > NumRef< ' > {fn as_i32_ref(& a self)-> & '一个i32 {self。 x}} fn main(){让x:i32 = 99; let x_num_ref = NumRef {x:& x};让x_i32_ref = x_num_ref。 as_i32_ref(); // ref都不能超过`x`}

struct Person {名称:& '静态str,} fn main(){令p =人员{名称:" fasterthanlime&#34 ;,};}

struct Person {名称:& '静态str,} fn main(){让名称=格式! (" fasterthan {}&#34 ;," lime");设p =人员{name:& name}; //错误:“名称”的寿命不足}

在最后一个示例中,本地名称不是静态字符串,而是字符串。它是动态分配的,将被释放。它的生存期少于整个程序(即使它恰好在主程序中)。

结构人< ' > {名称:& ' a str,} fn main(){让名称=格式! (" fasterthan {}&#34 ;," lime");设p =人员{name:& name}; //`p`不能超过`name`}

struct Person {name:String,} fn main(){let name = format! (" fasterthan {}&#34 ;," lime");令p =人{name:name}; //`name`已移入`p`,它们的生命期不再受限。}

说到:在结构文字中,当字段设置为具有相同名称的变量绑定时:

fn main(){让v = vec! [1,2,3,4,5];令v2 =& v [2 .. 4]; println! (" v2 = {:?}&#34 ;, v2);} //输出:// v2 = [3,4]

以上并非魔术。索引运算符(foo [index])重载了Index和IndexMut特征。

..语法只是范围文字。范围只是标准库中定义的一些结构。

如果前面带有=,则它们可以是开放式的,并且它们的最右边界可以是包含性的。

fn main(){// 0或更大的println! (" {:?}&#34 ;,(0 ..)。包含(& 100)); // true //严格小于20 println! (" {:?}&#34 ;,(.. 20)。包含(& 20)); // false // 20或小于20 println! (" {:?}&#34 ;,(.. = 20)。包含(& 20)); // true //仅3,4,5 println! (" {:?}&#34 ;,(3 .. 6)。包含(& 4)); // true}

fn tail(s:& [u8])-> & [u8] {& s [1 ..]} fn main(){令x =& [1,2,3,4,5];令y =尾(x); println! (" y = {:?}&#34 ;, y);}

fn main(){让y = {让x =& [1,2,3,4,5];尾(x)}; println! (" y = {:?}&#34 ;, y);}

fn main(){让y = {让v = vec! [1,2,3,4,5]; tail(& v)//错误:`v`寿命不长}; println! (" y = {:?}&#34 ;, y);}

fn file_ext(name:& str)->选项< &力> {// //这不会创建新的字符串-它返回//参数的一部分。名称 。分割("。")。 last()} fn main(){让名字="读我。或不输入txt。#34; ;如果让Some(ext)= file_ext(name){println! ("文件扩展名:{}&#34 ;, ext); } else {println! ("无文件扩展名"); }}

fn main(){let ext = {let name = String :: from(" Read me。or don' t.txt"); file_ext(& name)。 unwrap_or("")//错误:“名称”的寿命不足}; println! ("扩展名:{:?}&#34 ;, ext);}

fn main(){让s = std :: str :: from_utf8(& [240,159,141,137]); println! (" {:?}&#34 ;, s); //打印:Ok("🍉")let s = std :: str :: from_utf8(& [195,40]); println! (" {:?}&#34 ;, s); //打印:Err(Utf8Error {valid_up_to:0,error_len:Some(1)})}

fn main(){让s = std :: str :: from_utf8(& [240,159,141,137])。解开(); println! (" {:?}&#34 ;, s); //打印:"🍉" let s = std :: str :: from_utf8(& [195,40])。解开(); //打印:线程' main'在`Err`值上惊恐地叫`Result :: unwrap()`//:Utf8Error {valid_up_to:0,error_len:Some(1)}&#39 ;, // src / libcore / result。 rs:1165:5}

fn main(){让s = std :: str :: from_utf8(& [195,40])。期望(" valid utf-8"); //打印:线程' main'对有效utf-8感到惊恐:utf8Error // // {valid_up_to:0,error_len:Some(1)}&#39 ;, src / libcore / result.rs:1

......