Rust cheatsheet

之前的rust教程只是把基础的整理完了,虽然看完+跟着做也都可以完成,并且可以做一些简单的算法题目、应用题目等,但是篇幅过长,需要看比较久,同时还写了一堆解释性的文字,导致占用了更多的篇幅;

前几天看了一些 cheatsheets 相关的内容,就是把一些语言、常用的东西进行了一个简要的总结,可以快速帮助入门使用,并且还可以当做工具手册查看;所以突然感觉,其实学习一个编程语言或者其他的应用、工具,首先先去用它;上来就搞一堆复杂的,晦涩难懂的高级知识、底层原理,一方面很难看到成就,一方面因为他的晦涩难懂很容易吓退学习者;

所以,重新按照 cheatsheets 的思路,去整理一篇可以快速入门并且上手解决简单应用的文章;后面也会逐步加深对相关部分的理解。

一、安装

参考官方链接的说明,需要在终端执行

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

上面这个命令只能在mac、linux这种系统上使用,如果想要在window上安装,请参考链接

安装后(验证是否安装成功请参照前面的官方链接),可以通过普通文本编辑器,新建一个文件,例如名字叫做 main.rs,然后再文件中输入

fn main() {
  println!("Hello, World!");
}

然后打开电脑上的终端,进入到main.rs 文件所在的目录,执行rustc main.rs,如果没有问题,则会在main.rs所在目录下,生成一个可执行的文件,名字叫做main的文件,可以通过终端输入./main 运行,看到输出Hello, World!就可以了,第一个程序就完成了。

二、基础内容

以下代码,均省略 fn main() {} 部分,可以自己在编辑器中输入,然后将代码填充到 {}

1、输出
println!("Hello, World!"); // 输出Hello, World! 并换行
print!("Hello, World"); // 输出Hello, World! 不换行,区别在print后面是否有ln,可以认为ln就是line的意思
println!("Hello, {}", String::from("Alice")); // 这里可以通过动态方式将值传递到前面,前面 {} 占位使用

// 格式化输出
println!("{}", 1); // 这里只会输出1,前面{}只是占位
println!("{} {}", 1, 2); // 按顺序填充前面的{}
println!("{0} {1}", "Hello", "Alice"); // 也可以在前面占位符里面填写数字,表示使用后面哪一个参数
println!("{0:b} {0} {0:o} {0:0x}", 15); // {}中的冒号前面的数字代表第一几个参数,后面代表格式,这句输出的意思是,对后面的15,按照2进制、10进制(默认的)、8进制、16进制输出,结果是 1111 15 17 f

// 还有输出复杂对象的时候使用 {:?},这个以后会提及
2、注释
// 这是单行注释,以两个 / 开头
/// 这也是单行注释,以三个 / 开头
/// 注释的代码只会在编译器中存在,不会编译到最终结果里
/// 三个 / 和两个 / 的区别在于,三个的可以通过 rust 的 doc工具,生成文档,两个的只存在代码源文件中,不会被看到
//! 这个也是给 doc 用的,不过这个一般写在文件开头,来说明这个文件的功能
/** 这个是多行注释,中间可以写很多内容,
也可以换行 */
3、基本类型
类型说明
bool布尔值,可以表示真假
char字符类型,例如’a’ ‘b’ '1’等
f32, f64精度类型,就是常说的小数,例如1.1 4.2 0.0 等,后面的数字表示能表示的精度,数字越大能表示的越精确
i8, i16, i32, i64整数类型,例如1 2 10 100,后面的数字表示位数,数字越大,表示的数就越大
u8, u16, u32, u64无符号整数,和前面整数区别在于,无符号的数只能是非负数,其他相同
isize整数类型,这个是不定,也就是当不确定具体位数的时候可以使用
usize无符号整数,同isize整数说明

示例

let bool_false_value: bool = false; // 定义一个值为 false 的 bool 类型,这里指定了类型 bool
let bool_true_value = true; // 定义一个值为 true 的 bool 类型,也可以不指定类型 bool,rust 会根据赋予的值推断

let char_value = 'c'; // 这里省略了 char,注意这里是单引号,如果是双引号就不会推断为字符类型

let f32_value = 1.2345;
let f64_value = 1.2345; // 数字比较小的时候 f32 f64都可以,没有区别,总之就是64这个范围更大

let i8_value = 12; // 有符号整数类型,后面的数字8意思是能表示的二进制位数为 8 位,去掉一个符号位,可以表示的范围应该是 2^7
let u8_value = 12; // 无符号整数,因为首位不当做符号位,所以可以表示的范围应该是 2^8

// isize、usize 方式同前面,在人为视觉上使用起来没有区别
4、变量

在前面已经出现过,使用 let修饰的一个英文单词,这个英文单词称为变量,例如前面的let char_value中,char_value就是一个字符(因为是字符类型,不是因为名字里面有 char )变量;

需要注意一点,前面定义的变量均是不可变的,如果想要修改他们,需要加上关键字 mut

// num 不可变
let num = 100;
// num = 200; // 这里会报错,编译器提示 cannot assign twice to immutable variable

let mut new_num = 100;
new_num = 200; // 这里是正常的,因为前面声明的时候加了 mut 关键字,表示可以修改
5、函数

函数的格式为 fn function_name(param1: type1, param2: type2){}

// 用fn表示这是一个函数,是function的简写
// fn 后面跟着函数名称,建议名字看到了就能知道是干什么的
// 后面跟着参数,以及参数类型,根据函数实际的功能去添加对应的参数
// -> i8 表示返回一个 i8 类型的值
fn add(num1: i8, num2: i8) -> i8 {
	// 通过return 关键字将 num1 + num2 计算的值返回给调用处
  return num1 + num2;
}

fn main()
{
  // 通过函数名,括号,以及所需参数调用函数
  let result = add(1, 2);  // 这里得到 result 为 3
}
6、复杂类型

这里用复杂类型不太合适,所以加一句说明,这一部分主要是除了前面基础类型外的类型,前面基本类型可以认为都是数值类型的,例如 bool 中的 true、false 可以认为是 1、0(实际上编译器不认), char 中的字符可以转换成 ascii 码(如果直接写 let c: char = 97 编译器会提示不正确,需要用到关键字as,例如 let c: char = 97 as char);

这一节主要是非简单的数值类型

类型说明
[type; count]数组类型,用中括号表示,其中分号前面表示类型,例如前面提到的i32,char等,后面表示数组的个数
&str字符串类型,这里准确点说应该是字符串引用,字符串类型是String
&[]切片(slices),主要是数组、字符串等的局部引用,可以看示例理解
VecVector类型,和数组类型差不多,只是这里长度是可变的,数组是定长
()元组类型,一对圆括组成
let arr: [i32; 3] = [1, 2, 3]; // 这里意思是包含三个 i32 类型的数组,类型可省略;arr[0] arr[1] 可调用相应位置的值

let s: &str = "Hello"; // 定义一个字符串引用

let str: String = String::from("Hello"); // 创建字符串,或者 "Hello".to_string() 也可以

let slice = &arr[0..2]; // 表示从数组 arr 里面,第0个位置开始,找到第 2 - 1 个位置

let v = vec![1, 2, 3];  // 定义了一个向量(Vector)类型,这里 vec! 是 rust 提供的一个创建向量的方便的宏(当做工具好了),以后会说到宏的创建和使用,这里只当做是一个封装好的工具就好了

let tuple: (i32, i32, i32) = (1, 2, 3); // 定义了一个元组类型,左边括号中,需要把对应的类型填进去,然后右边按照顺序填写值,使用的时候可以  tuple.0  tuple.1 等调用相应位置的值
7、字符串

很多语言都会单独把字符串拿出来说明,虽然这篇只想写简要的东西,但是还是单独说明一下 String 的使用方法

let literal_str: &str = "这是一个字面值"; // 字面值可以当做是写死的一个值,或者当下写定的一个值

let name = String::from("Alice"); // 通过string 的from 方法创建了一个值为 alice 的name 字符串变量

let empty_str = String::new(); // 创建了一个空字符串

let mut mut_empty_str = String::new(); // 前面创建的都是不可变的,这里创建一个可变的
mut_empty_str.push_str("new value"); // 向空字符串插入一个值,可以多次调用插入更多的值
8、操作符
操作符说明
==,!=== 判断是否相等,结果是bool值;!=判断是否不相等
>,>=,<,<=大于,大于等于,小于,小于等于,结果是bool值
+,-,*,/,%加,减,乘,除,最后一个%取余数,例如 10 % 3 = 1(除3余1,所以得1)
&&,||,!&& 判断两边同时为真则得到真,否则是假;|| 两边任何一个是真就得到真,否则是假;!真的取假,假的取真
&,|,^,~这四个是按位操作,即需要将操作数转成二进制再进行计算;详细说明看后面示例
>>,<<也是按位操作,第一个是把转化后的二进制数右移,左边补0,第二个是向左边移,右边补0
let value = 1 == 2; // 这是判断 1 是否等于 2,得到的结果是 false
let value = 2 == 2; // 判断 2 是否等于 2,结果是真

let value = 1 != 2; // 这是判断 1 是否不等于 2,得到的结果是 true
let value = 2 != 2; // 判断 2 是否不等于 2,结果是 false

// 所以 == 和 != 是相反的判断

let value = 2 > 1; // 得到 true,如果是 2 < 1,得到 false;如果是 >= <= 多了一个对两边数字的一个相等对比

let value = 1 + 2; // 计算加法,可以根据实际情况换成 -  *  /. % 等
let value = 5 % 4; // 这里商1,余1,所以取余数1

let value = true && true; // 这里是 true,其中任何一个 true 变成了 false,结果都是 false
let value = false || false; // 这里结果是 false,其中任何一个 false 变成 true,结果都是 true
let value = !true; // 结果是 false,如果是 !false ,那么结果就是 true

let value = 8 & 5; 
// 一个 & 是按位运算,所以这里先将8和5转成二进制,分别为1000,0101
// 然后,按照顺序(从左到右或者从右到左都可以),一位位的去比较,
// 例如按照从右向左的顺序,分别计算 0 & 1 = 0, 0 & 0 = 0, 0 & 1 = 0, 1 & 0 = 0
// 所以最终二进制结果是 0000,换成10进制就是0,所以 8 & 5 = 0
// 同理,其他几个按位的符号,都需要先转化成2进制,然后 & 取交集,|并集,
// ^这个叫异或,就是 1 ^ 0 = 0^ 1 = 1,其他异或都是0
// ~这个只需要一个操作数,换成二进制后,0变1,1变0,然后再转成十进制

let value = 2 >> 1; // 先把 2 换成二进制是 0010,然后右移动1位,变成0001,所以十进制结果是1
let value = 2 << 1; // 先把 2 换成二进制是 0010,然后左移动1位,变成0100,所以十进制结果是4
9、流程控制
9.1、判断
9.1.1 if 语句
// if 语句,后面跟着可以判断真假的表达式,例如 1 > 2,
// 如果得到true,就执行 {}里面的内容,否则跳过
if condition {
  
}

// 当有多个判断条件的时候,可以添加 else if 分支,然后后面填写想要判断的条件
// 当所有的条件都不符合,就进入到else的流程里面
if condition1 {
} else if condition2 {
} else {
}

// 举例子
// 假设 score < 60,不及格; score < 70 中等,score < 80 良好, score <= 100优秀
// 需要注意前面的条件,当进入到 score < 70的时候,其实是隐含了 60 <= score < 70
// 后面同理
let score = 59;

if score < 60 {
  	println!("不及格");
} else if score < 70 {
    println!("中等");
} else if score < 80 {
    println!("良好");
} else {
  // 这里 else 可以写成 else if score <= 100
  // 因为前面都判断完了,所以这里可以直接简单写成 else
    println!("优秀");
}

除了前面的用法外,还可以使用 if let语法

let arr = [1, 2, 3];

// 判断数组里面的数值是否为1,2,3包括顺序也相同
// 如果按照前面的方法
if arr[0] == 1 && arr[1] == 1 && arr[2] == 3 {
  // 执行
}

// 可以看到前面比较繁杂,这里可以使用if let去简化一下
if let[1, 2, 3] = arr {
    // 执行
}

// 如果只想看第一位和第三位是否一样,使用 _ 占位,是什么都行
if let[1, _, 3] = arr {
    // 执行
}
9.1.2 match 语句

基本上if 能用的地方 match 都可以使用,而且,match 还有一个好处就是,需要你列出所有存在的情况,否则会提示错误,先看示例去理解;

// 拿前面的分数示例来说明
let score = 59;

match score {
    0..=59 => println!("不及格"),
    60..=70 => println!("中等"),
    70..=80 => println!("良好"),
  	80..=100 => println!("良好"),
    _ => println!("无效分数") // 因为score是一个整数,所以可以取的范围出了前面写的0-100外,还可能存在其他的,如果不写这一行,就会提示 Match must be exhaustive [E0004],提示必出把所有情况写全;因为不需要负数和大于100的,所以,这里就用 _ 代表其他,等价于 else 
}
9.2、循环
9.2.1 for 循环
// rust 里面的 for 循环只有一种,就是其他语言里面常说的 for-in
// 如果需要修改,下面item前面应该添加 mut 关键字
for item in 1..100 {
  // 输出1-99,如果想输出100,可以写成 1..=100
  println!("{}", item);
}
9.2.2 loop 循环
// loop 比较简单
loop {
  // 执行
}
// 如果没有意外情况,上面的loop会一直执行,直到强制结束程序
// 可以看下面例子
let mut num = 1;
loop {
  num = num + 1;
  if num > 100 {
    break; // 通过 break 语句结束 loop
  }
}

// 如果想在前面代码基础上,增加一条,输出偶数,那么可以
let mut num = 1;
loop {
  num = num + 1;
  if num > 100 {
    break; // 通过 break 语句结束 loop
  }
  
  if num % 2 == 0 {
    println!("是偶数");
    // 假设 num 是偶数的时候,输出,然后就不让继续执行后面
    // 的代码,让他直接进入下一轮循环,可以使用continue
    continue;
  }
  
  // 做点别的
}
9.2.3 while 循环
while condition {
  
}
// 将前面loop的例子搬过来,改成 while 写法
let mut num = 1;
while num < 100 { // 这里等价于 loop 中的 if num > 100 {break;}
  num = num + 1;
}
10、函数

前面提到过函数了,这里再详细说明一下

// 基本函数,例如 main 函数
fn main() {} // 这里是一个无参的main函数,同时 {}也没有东西,代表什么也不干,也没有返回值

// 带有参数的函数
fn test_func(param1: i32) {} // 这里有一个参数,是i32类型的,也什么都不干,没有返回;参数可以有多个,这里只写了1个

// 带有参数,且有返回
// 这里偷个懒,直接把param1返回了,也可以返回其他i32类型的值
// 这里需要提一下,如果返回语句是最后一行,可以不加return,不加分号,直接写返回的值或者变量
fn test_func_with_return(param1: i32) -> i32 { return param1; } 

// 带参数,且有返回,且函数做点什么事情
fn test_func_with_return2(param1: i32) -> i32 {
  param1 + 1 // 这个函数只是把传过来的参数加一返回,这里是最后一行,可以省略 return 和分号
}

// 注意:这里只写了简单的函数,以及简单参数,例如数组、元组、结构体(自定义类型)等不在这里说明,因为涉及到什么所有权啦,借用啦等等比较繁杂的概念,以后会补充例子,这篇只想简单搞一搞
11、闭包

这里不说复杂的内容,只是把他形式,以及简单使用拿出来说一下;

闭包定义的话,可以当做一个匿名函数,就是,他是函数,但是没有函数名,来使用

// 正常的一个函数
fn test_func(param1: i32) -> i32 { return param1; }

// 匿名函数
|param1| param1;

// 前面这个例子有点奇怪,搞个稍微复杂一点点的
// 下面函数,只对正数做加法,任何一个是负数,都返回0
// 不要问这里为什么不用u32,只是为了做例子多写点函数体的内容
fn add(n1: i32, n2: i32) -> i32 {
  if n1 <= 0 || n2 <= 0 {
    return 0; // 不能直接写 0,要加return
  }
  
  return n1 + n2; // 直接写 n1 + n2 也行
}

// 改成匿名函数的形式
|n1: i32, n2: i32| -> i32{
    if n1 <= 0 || n2 <= 0 {
        return 0;
    }

    n1 + n2
};
// 可以看到从函数到匿名函数的变化
// 函数名字去掉了,包裹参数的圆括号变成了两个竖线,
// 返回值 -> i32,也可以去掉,也可以保留
// 其他就没变化了

// 这里最好给他一个变量,让承载一下这个匿名函数,这个变量不是必须的,
let add_fun = |n1: i32, n2: i32| -> i32{
    if n1 <= 0 || n2 <= 0 {
        return 0;
    }

    n1 + n2
};

// 匿名函数可以当做参数传递给函数,所以给名字可以复用,也可以不给,一次用完就算了
// 例如
fn operation(num1: i32, num2: i32, oper: fn(i32, i32) -> i32) {
    println!("{}", oper(num1, num2));
}

// 调用,因为这里写的简单,所以和直接调用 add_fun 没有区别,但是可以复用
operation(1, 2, add_fun);

// 再看一个例子

fn add(n1: i32, n2: i32) -> i32 {
    n1 + n2
}

fn sub(n1: i32, n2: i32) -> i32 {
    n1 + n2
}

fn operation(num1: i32, num2: i32, oper: fn(i32, i32) -> i32) {
    println!("{}", oper(num1, num2));
}

// 调用,因为add 和sub,余operation 定义的函数参数格式一样,所以可以直接调用
// 当然前面的函数也可以写成匿名函数;这里不做使用场景的说明
operation(1, 2, add);
operation(1, 2, sub);

三、总结

这篇文档只是简要的,按照手册的形式书写;只能作为入门,或者至少熟悉文档中的内容后,可以看明白一些算法题、基础应用题等;当然,如果需要书写代码,还需要了解更多的内容,例如前面提到的闭包,会对作用域的说明;自定义类型结构体、枚举等;还有字符串的切片;rust最重要的所有权系统等等。

所以前面内容只是作为一个简单的入门手册,或者有其他更准确的名词你也可以自己去定义,前面的绝对不是一个能让你完全熟练并应用rust的东西。

后面会按照一定的顺序(其实也没什么顺序,尽量把相关联的东西放在一起,这样顺序影响就不是很大了),例如rust的模块,测试,内存管理和安全,异常、并发、宏、网络(这个不一定,主要是应用层面的了,就根据不同人,不同方向自己去研究了)等等内容,会不定期更新。

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值