Rust基础学习笔记(零):复习基本知识
由于一个学期没有碰Rust,相关知识殆已忘尽。最近各课逐渐停授,余出时间来从基础重温这些知识,也算是对没有写的基础知识的补充。另外这次复习主要参照了Youtube上的Crush Course视频,两个小时的视频一气看下来还是很累的啊。原视频链接
下载Rust,并在VSCode环境下使用
首先打开Rust官网,点击Get Started,下载对应的64位版本。运行下载程序并启用默认设置就可以。我的电脑里已经有旧版本,故只进行了更新操作。然后找到下载的bin文件夹路径添加环境变量即可,这个路径一般在users/YourName/.cargo/bin
中
然后在VSCode的插件里搜索Rust,安装列表第一个插件即可。下面运行第一个小程序。
- 打开任意文件夹,创建一个文件
Hello.rs
,在里面输入如下代码:
fn main(){
println!("Hello, World!");
}
- 在终端中输入
rustc "Hello.rs"
,正常编译后会在相同路径下出现对应的Hello.exe
,运行时即在终端输出
> Hello, World!
删除这些文件,在一个空文件夹里新建一个空工程。在终端输入如下指令:cargo init
Rust会为你自动生成一个完备的工程文件,包含一个Hello World程序。编译正常运行,到此基本配置已经结束。接下来就是Rust的一些基础使用方法。不过要指出的是这些内容并没有涉及到Rust的核心,也就是说几乎只是一个套皮的C、Python、Java或者其他语言的另一种写法。关于Rust的独到之处,还要进一步复习。在此只是记录备忘。
基本输出
把内容和参数打印到屏幕上可能是学习每门语言最先接触的东西了。Rust输出参数的时候会用到{}
,是在哪里见过呢……
//原始形态
println!("Hello, world!");
//参数用{}标记
println!("Number: {}",1+2);
//{}中可加入指示位置的数字
println!("{1},{0},{2},{0}",
"Alice","Bob","Eve");
//{}中可加入参数名,不过要在参数列表处加以说明
println!("{name} stands by {num}",
name = "Bob",num = 1);
//格式化输出
println!("Binary:{:b} Hex:{:x} Oct:{:o}",10,10,10);
//{:?}可以输出元组,准确的说可以打印任何类型的具体信息。好像可以用来debug?
println!("{:?}",(12,true,"Hello"));
//参数列表可以进行简单的数学运算,这一点与C/C++等多数语言相同,不再赘述
定义变量
Rust中定义变量一般不需指明类型,而且默认是不可以改变其中的值的。要想改变需要额外添加mut字段。
let name = "Brad";
let age_1 = 20;
//age_1 = 21; //这里会报错,因为默认age_1是不可以改变的
let mut age = 20;
println!("I am {}",age); //输出20
age = 21;
println!("I am now {}", age); //输出21
println!("My name is {}", name);
//也可以定义常量
const ID:i32 = 001; //在变量名后面添加 :类型名 来指定类型
println!("My ID: {}",ID);
//可以一次定义多个变量
let (my_name, my_age) = ("Bob", 20);
println!("{} is {}", my_name, my_age);
基本类型
Rust中的一些基本类型见下:
- 整形用i/u + 数字(8/16/32/64/128) 表示 如u8,i64
- 浮点型有f32和f64两个类型
- 布尔型 bool
- 字符类型 Char
- Tuples和Arrays
//普通整型默认为 "i32"类型
let x = 1;
//普通浮点数默认为"f64"类型
let y = 1.2;
//显式定义类型
let y:i64 = 123456789;
//显示Max size
println!("Max i32: {}", std::i32::MAX);
println!("Max i64: {}", std::i64::MAX);
//定义布尔值
let is_Act = true;
println!("{:?}",(x,y,is_Act));
//也可以从表达式获得bool值,不赘述*
//甚至可以用unicode保存emoji,格式为"\u{codeX}"
let face = '\u{1f600}';
println!("{}",face);
字符串类型
相似,不赘述
let mut hello = String::from("Hello!"); //声明一个可变字符串变量
println!("{}",hello);
//有判空、获得长度、获得占用空间、接续字符/字符串等类方法
println!("Length: {}",hello.len());
hello.push('!');
println!("{}",hello);
hello.push_str("???");
println!("{}",hello);
println!("cap:{}",hello.capacity());
println!("isEmpty:{}",hello.is_empty());
//可以匹配内部内容,如contain返回是否包含字段,replace返回替换指定内容的字符串(不改变原本内容)
println!("Contains \"Hello\"?: {}",hello.contains("Hello"));
println!("Contains \"World\"?: {}",hello.contains("World"));
println!("Replace: {}",hello.replace("llo", "LLO"));
hello = String::from("Hello world!");
for word in hello.split_whitespace(){
println!("{}",word);
}
//可以指定字符串所占的空间
let mut s = String::with_capacity(10);
s.push('a');
s.push('b');
//断言语句,不成立时投出panic
//assert_eq!(3,s.len()); //cause panic!
assert_eq!(2,s.len());
println!("{}",s);
tuple元组
元组是不同类型数据的集合,最多拥有十二个数据。
let person:(&str,&str,i8) = ("Brad","Mass",20);
println!("{} is from {} and is {}",person.0,person.1,person.2);
静态数组array
支持索引、切片。
//显式指定类型和长度
let mut numbers :[i32;5] = [1,2,3,4,5];
//let numbers :[i32;5] = [1,2,3,4]; //会报错-长度必须匹配
println!("{:?}",numbers);
//用索引得到单独的值
println!("{}",numbers[1]);
//对可变的数组可以对其中的值单独重新赋值
numbers[2] = 12;
println!("{:?}",numbers);
//求长度
println!("Array Len: {}", numbers.len());
//这里使用std::mem库获得占有空间大小
println!("Array occupies {} bytes",std::mem::size_of_val(&numbers));
//切片语法
let slc:&[i32] = &numbers[0..2];
println!("Slice:{:?}",slc);
动态数组vectors
和array类似,可以push和pop,用迭代器进行遍历
//只要明确类型
let mut numbers: Vec<i32> = vec![1,2,3,4];
//添加
numbers.push(5);
println!("{:?}",numbers);
//弹出首元素
numbers.pop();
println!("{:?}",numbers);
//用迭代器进行遍历
for x in numbers.iter(){
println!("Numbers: {}",x);
}
//用可变迭代器可以对内容进行修改
for x in numbers.iter_mut(){
*x *=2;
}
println!("Numbers Vec:{:?}",numbers);
逻辑结构
条件语句
let age = 15;
let gender:char = 'M';
//If-else
if age>=18 {
println!("Adult!");
} else {
println!("Not");
}
if age<=18 && gender=='M'{
println!("Boy");
}
//用if-else进行快速赋值,类似于?:表达式
let is_adult = if age >= 18 {true} else {false};
println!("An adult: {}", is_adult);
循环语句
let mut count = 0;
//最基本的loop循环,需要内部指明跳出条件
loop{
count += 1;
println!("Number: {}",count);
if count == 5{
break;}
}
//while循环,用法类似其他
while count <= 100{
if count % 15 == 0{
println!("Fuzzbuzz");
} else if count % 25 == 0{
println!("by 25");
} else if count % 5 == 0 {
println!("{}",count);
}
count += 1;
}
//for循环,遍历容器中的内容
for x in 0..20{
if x % 5 == 0 {println!("Go!{}",x);}
}
函数调用
参数的声明以及返回值的书写比较值得注意,闭包的写法也要注意
pub fn run(){
greeting("Jane", "Hello");
println!("2+3={}",add(2,3));
//闭包可以使用外部的变量
let n3:i32 = 3;
let add_nums = |n1:i32, n2:i32| n1 + n2 + n3;
println!("Sum:{}",add_nums(1,2));
}
fn greeting(greet: &str, name: &str){
println!("{},{}!",greet,name);
}
fn add(n1:i32, n2:i32) -> i32 //类型在此声明
{
n1 + n2 //返回值后面没有分号
}
引用指针
这里只是简单的介绍,还有很多内容没有写入
let arr1 = [1,2,3];
let arr2 = arr1;
println!("{:?}",arr1);
println!("{:?}",arr2);
//Array为原生类型,因此在这里无事发生
//非原生类型重新赋值时会导致赋值方不再保留原来的内容,出现所有权的移交
//这种情况下需要使用引用指针
let vec1 = vec![1,2,3];
let vec2 = &vec1; //使用了引用,vec1认为无事发生
//let vec2 = vec1; //这个语句会导致vec1不再拥有原来的数据
println!("Val:{:?}",(&vec1,vec2));
结构体
比较特殊,从成员变量的声明到成员函数的加入。
//最基本的结构体,注意成员变量间用','分隔
struct Color {
red: u8,
green: u8,
blue: u8,
}
//元组的形式声明的结构体
struct Color2(u8,u8,u8);
//一个部署了成员方法的结构体,方法在后面用impl引出
struct Person{
first_name: String,
last_name: String,
}
impl Person{
//构造函数
fn new(first: &str, last: &str) -> Person{
Person{
first_name: first.to_string(),
last_name: last.to_string(),
}
}
fn full_name(&self) -> String{
format!("{} {}", self.first_name,self.last_name)
}
fn set_last_name(&mut self, last: &str){
self.last_name = last.to_string();
}
fn to_tuple(self) -> (String,String){
(self.first_name,self.last_name)
}
}
pub fn run(){
//最基本的初始化方法
let mut c = Color {
red: 255,
green: 0,
blue: 0,
};
//使用和修改时指明名称即可
println!("Color: {} {} {}",c.red,c.green,c.blue);
c.red = 200;
println!("Color: {} {} {}",c.red,c.green,c.blue);
//初始化元组结构体
let mut d = Color2(0,255,0);
//使用和修改时指明位置
println!("Color: {} {} {}",d.0,d.1,d.2);
//使用构造函数和其他成员函数
let mut p = Person::new("John", "Doe");
println!("Person {} {}",p.first_name,p.last_name);
println!("Person {}",p.full_name());
p.set_last_name("Williams");
println!("Person {}",p.full_name());
println!("{:?}",p.to_tuple());
}
枚举类
枚举是只有具体的几个值的数据类型。具体值由编写者确定。
enum Movement{
Up, Down, Left, Right
}
可以作为参数,也可以用match进行选择
fn move_avatar(m: Movement){
match m {
Movement::Up => println!("Avatar moving up"),
Movement::Down => println!("Avatar moving down"),
Movement::Left => println!("Avatar moving left"),
Movement::Right => println!("Avatar moving right"),
}//match类似于switch,注意用=>指向具体操作,之间用逗号分隔。
}
pub fn run(){
let avatar1 = Movement::Up;
let avatar2 = Movement::Down;
let avatar3 = Movement::Left;
let avatar4 = Movement::Right;
move_avatar(avatar2);
move_avatar(avatar3);
move_avatar(avatar1);
move_avatar(avatar4);
}
以上介绍了Rust的基本写法。