Rust变量
rust中使用let关键字来初始化一个变量,变量在初始化的时候必须有一个初始值,同时rust中变量不可变,在初始化之后就不可以再更改了:
//变量不可变
let x = 5;
//这种情况是不允许的,不可以二次赋值
x = 6;
使用mut关键字可以使得变量成为可以改变的:
//变量不可变
let mut x = 5;
//这种情况是允许的,mut变量二次赋值
x = 6;
使用const关键字可以定义常量,常量不可以mut,并且必须声明类型,可以在全局定义,全大写。常量可以在任何作用域中声明,比如main函数之前:
const X:i32 = 1000;
如果我们先声明一个变量,之后再用let声明同一个变量,这是允许的,我们称之为第一个变量隐藏了,这一个过程中,变量的类型和数值都可以改变,这一个操作的好处是节约内存:
//shadow
let x = 5;
let x = true;
Rust基础数据类型
Rust 是静态类型语言,也就是说在编译时就必须知道所有变量的类型
- 整数
rust的整数分为有符号和无符号两种,同时我们可以通过设定长度来限制整数的长度,长度可以设置为8,16,32,64,128这几种,同时rust还支持使用isize
这样的形式定义整数,它可以根据本机的位数来设定长度,比如64位的电脑就与i64的效果一致。可以使用下面两种方式来定义一个指定类型的整数
let num:u8 = 42;
let num = 42u8;
同时我们可以使用多种进制来表述一个整数类型值
//十进制,可以使用_隔开,与98222一致
let num = 98_222;
//十六进制
let num = 0xff;
//八进制
let num = 0o77;
//二进制
let num = 0b1111;
//单字节字符(仅限u8)
let num = b'A';
- 浮点数
浮点数仅有32和64位两种类型,默认类型是 64位浮点数
//这个时候就算f64
let x = 2.0;
let y:f32 = 2.0;
Rust 中的所有数字类型都支持基本数学运算:加法、减法、乘法、除法和取余,分别使用 +,-,*,/,%符号来完成,除法会向下取最接近的整数。
- 布尔型
Rust 中的布尔类型(bool)有两个可能的值:true和 false
//boolean
let t:bool = true;
- 字符类型
rust中的字符类型数据占4给字节,并且使用 Unicode 编码,所以我们可以使用英文字母,外文字母,emjoy表情等字符:
let c = 'z';
let z: char = 'ℤ';
let heart_eyed_cat = '😻';
Rust复合数据类型
复合类型将多个值组合成一个类型,Rust 有两个原生的复合类型:元组(tuple)和数组(array)
- 元组
元组tuple,长度固定,且内容不能修改,元组中的数据类型可以不同
let tup = (10,21,'c');
使用模板匹配的方式可以提取出元组的每一个数据,也可以通过下标来访问
let (x,y,z) = tup;
let k = tup.1;
不带任何值的元组有个特殊的名称,叫做单元(unit) 元组。这种值以及对应的类型都写作 ()
,表示空值或空的返回类型。如果表达式不返回任何其他值,则会隐式返回单元值。
- 数组
数组array同样长度固定,但是其中的类型必须一致,内容也同样不可变:
let arr = [1,2,3,4];
//使用[类型;数量]的方式可以定义数组的类型
//同时如下方式可以直接生成[3,3,3,3,3]5个3的数组
let a:[i32;5]= [3;5];
数组可以通过下标访问
let first = a[0];
Rust的函数
fn
关键字,它用来声明新函数,函数中的参数必须声明类型,如果函数有返回值,返回的内容也必须给出类型,函数的定义如下:
//函数定义,参数类型必须指明,返回值也需要声明
fn test(x:i32,y:i32) -> i32 {
5
}
函数中的执行某些操作的指令被称为语句,语句由分号结尾;二返回一个值的指令被曾为表达式,表达式不能由分号结尾,一个函数可以包括多个语句,同时在函数结尾需要一个表达式来作为函数的返回值。
//函数定义,参数类型必须指明,返回值也需要声明
fn test(x:i32,y:i32) -> i32 {
//语句
let x = x+1;
let y = y+1;
//表达式
x+y
}
Rust控制流
rust和其他语言类似具有if等条件控制语句,也有while和for等循环语句
- if
if 表达式允许根据条件执行不同的代码分支。if 语句中包含一个表达式,表达式的值必须是一个bool类型,返回true或者false,要注意,rust并不会将其他类型的值转化为bool进行运算,if(1)这些的写法是不允许的:
if number > 5 {
println!("1");
}else if number == 5 {
println!("2");
}else{
println!("3");
}
//这样是不允许的:
if number {
}
可以通过在 if 语句中返回一个表达式来实现“三目运算” 等类似操作,但是返回值必须是同一个类型
let condition = true;
//相当于三目运算,但是返回值必须一致
let num = if condition {5} else {6};
- loop循环
loop 循环将循环执行它包含的语句,直到遇到 break 关键字将其中断,同时在break之后还可以编写一个表达式作为返回值。要注意,此处需要一个分号,因为整个语句是一个赋值语句。
let mut conuter = 1;
let re = loop {
conuter += 1;
if conuter == 10 {
//返回,并且可以返回值
break conuter * 2;
}
};
//整个相当于一个 let re = 10 * 2; 这样的语句
如果有多重循环,可以通过给定一个循环标签的方式来告知中断哪一个循环
fn main() {
let mut count = 0;
//给定一个标签
'counting_up: loop {
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 {
break;
}
if count == 2 {
//中断指定标签的循环
break 'counting_up;
}
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}
- while循环
while 循环在指定的条件为真时循环执行
while conuter != 0 {
conuter = conuter -1;
}
- for循环
for 循环可以限定循环的次数,你可以用 for 语句遍历一个数组中的每一个元素,也可以使用range自己创建一个循环的范围来限定循环次数,使用range创建的范围是 [ a,b ) 的区间,可以取到初值但是不能取到末值
let a = [10, 20, 30, 40, 50];
for e in a {
println!("{}",e);
}
//在一个范围内运行,不包含10,包含1
for e in (1..10) {
println!("{}",e);
}
Rust结构体
rust使用struct来定义一个包含多种数据类型的结构,struct 中的每个字段需要给出名字和数据类型,在创建一个struct 实例时,需要对其中的每一个字段赋值,同样,struct 实例也可以是可变的,如果一个 struct 实例是可变的,那么其中的每一个字段都是可变的,使用 .
记号可以找到实例中的字段
struct User {
name:String,
email:String,
active:u32,
}
//实例化
let mut user1 = User{
email:String::from("122"),
name:String::from("zs"),
active:1,
};
//修改一个值
user1.email = String::from("121212");
//如果给与一个字段的值和他的名称一致,可以省略不写,如下:
let email = String::from("122");
let mut user2 = User{
email,
name:String::from("zs"),
active:1,
};
使用扩展运算符 ..
可以将一个struct 实例展开,展开的 struct 可以用于填出其他的 struct 实例
let mut user2 = User{
..user1
};
rust 还支持元组 struct 这样的 struct ,他的定义类似于元组,字段不需要名称,字段的获取方式也和元组类似
//tuple struct,变量没名字
struct Color(i32,i32,i32);
let black = Color(0,0,0);
使用 impl
块可以为 struct 创建方法,需要传入一个 &self 代表本身,传入这个参数之后,可以调用 struct 中的字段元素,在 self 之后可以传入其他元素,将 struct 实例化之后,使用 .
来调用对应的方法,要注意,调用方法时,并不需要传入 &self 这个参数
struct Long{
a:u32,
b:u32,
};
//impl块用于定义方法
impl Long {
fn greater(&self, other: &Long) -> u32 {
if self.a > other.a {
1
}else{
2
}
}
};
println!("{}",l1.greater(&l2))
如果函数中不包含 &self 这个参数,那么这个函数不需要实例化也可以调用,调用方式也是使用 ::
来调用,类似我们之前使用的在String中的 String::from ,这类函数常用于初始化一个 struct 实例,类似于其他语言中的 new
impl Long {
fn creat_long(a: u32) -> Self {
Self {
a: a,
b: a,
}
}
}
let l3 = Long:: creat_long (1);
Rust枚举
枚举类型允许你给出所有的可能值作为成员创建一种新的数据类型,使用 ::
可以创建一个枚举中一种类型的实例。当你使用 IpAddrKind 作为变量类型时,IpAddrKind::V4 和IpAddrKind::V6 都可以与其匹配
enum IpAddrKind {
V4,
V6,
}
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
//route(IpAddrKind::V4) 和 route(IpAddrKind::V6) 都可以传入
fn route(ip_kind: IpAddrKind) {}
在rust中,我们可以直接将数据附加到枚举的每个成员上,这里直接展示一个例子来说明:
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
//这种方式相当于,loopback的类型是IpAddr::V6,同时home的值是"::1"
可以使用 impl
来为结构体定义方法那样,也可以在枚举上定义方法,其使用方式与 struct 类似
impl IpAddr {
fn call(&self) {
// 在这里定义方法体
}
}
let loopback = IpAddr::V6(String::from("::1"));
loopback.call();
Rust空值
rust 并没有很多其他语言中有的空值功能,空值的问题在于当你尝试像一个非空值那样使用一个空值,会出现某种形式的错误。但是rust是一门追求安全的语言,所以rust 并没有空值,但是提供了一个 Option<T>
枚举,他包含两个值,一个是 None 代表空,一个是 Some ,代表非空
enum Option<T> {
None,
Some(T),
}
let some_thing = Some(5);
let absent_number : Option<i32> = None;
因为rust需要确保安全,所以 Option 和 T 不能直接进行运算
let x: i8 = 5;
let y: Option<i8> = Some(5);
//这是不允许的,即使y不是None
let sum = x + y;
match 控制流
match 控制符允许我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码,例如使用一个枚举类型,我们可以根据输入值是枚举的哪一项执行不同的操作,match的每一项返回值必须是同一个类型,如果仅返回一个值,不需要大括号进行包裹,但是如果你需要执行多个语句,则需要一个大括号进行包裹
enum Coin{
Penny,
Nickel,
Dime,
Quarter(i32),
}
fn in_cents(coin:Coin) -> u8 {
match coin {
Coin::Penny => {
println!("111");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("{}",state);
25
},
}
}
当然如果你仅需要匹配其中的部分内容,你可以使用占位符 _
代表其他剩余的元素
fn in_cents(coin:Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
_ => 2,
}
}
如果的只需要匹配其中一个元素,你还可以使用 if let 语法糖来优化,下面两种表达的效果相同
match coin {
Coin::Quarter(state) => println!("State quarter from {:?}!", state),
_ => count += 1,
}
//和上面表述相同
if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}!", state);
} else {
count += 1;
}