1、变量与可变性
全用let关键字来声音变量,一般浏览器会给他推断为i32类型,一般默认为不可变,如果需要声明变量,需要加mint关键字声明。
- 变量和常量
- 常量(constant), 常量在绑定值以后也是不可变的,但是它与不可变的变量有很多区别:
- 不可以使用mut, 常量永远都是不可变的
- 声明常量使用const关键字,它的类型必须被标注
- 常量可以在任何作用域进行声明,包括合局作用域
- 常量只可以绑定到常量表达式,无法绑定到函数的调用结果或只能在运行时才能计算出的值
- 在程序序运行期间,常量在其声明的作用域内一直有效
- 命名规范: Rust 里常用使用全大写字母,每个单词之间用下划线分开,例如:MAX_POINITS
- 例子: const MAX_POINTS:u32 = 100_000
- 常量(constant), 常量在绑定值以后也是不可变的,但是它与不可变的变量有很多区别:
- shadowing
- 可以使用相同的名字声明新的变量,新的变量就会shadow(隐藏)之前声明的同名变量
- 在后续的代码中这个变量名代表的就是新的变量
let x= 5; let x = x+1; let x = x *2;- shadow 与 mut关键字声音的区别
- 如果不使用let关键字,那么重新给mut的变量赋值会导致编译时错误
- 而使用let声明的同名新变量,也是不可变的
- 使用let声明的同名新变量,它的类型可以与之前不同
- 可以使用相同的名字声明新的变量,新的变量就会shadow(隐藏)之前声明的同名变量
2、数据类型
- 标量和复合类型
- Rust 是静态编译语言, 在编译时必须知道所有变量的类型
- 基于使用的值,编译器通常能够推断它的具体类型
- 但如果可能的类型比较多(例如把string转为整数的parse方法),就必须添加类型的标注,否则编译会报错。
et guess: u32 = "42".parse().expect("Not a number!");
标量类型
整数类型
- 整数类型没有小数部分
- 例如 u32 就是一个无符号的整数和类型,占据 32们的空间
- 无符号整数类型以U开头
- 有符号整数类型以i开头
- isize和usize类型的位数由程序运行的计算机的架构所决定
- 使用isize或usize的主要场景是对某种集种集合进行索引操作
- 整数字面值
- 除了byte类型外,所有的数值字面值都允许使用类型后缀 例如:57u8
- 如果你不太清楚应该使用哪种类型,可以使用rust相应的默认类型
- 整数的默认类型就是i32
- 总体上来说速度很快,即使在64位系统中
整数溢出
- 调试模式下编译:Rust 会检查整数溢出,如果发生溢出,程序在运行时会panic
- 发布模式下(--release)编译:rust不会检查可能有导致panic的整数溢出
- 如果溢出发生:rust会执行“环绕操作”
浮点类型
- rust 有两种基础的浮点类型
- f32 32位 单精度类型
- f64 64位 双精度
- rust的浮hokodga全用了ieee-754标准来表述
- f64是默认类型,因为在现代cpu上f64和f32的速度差不多,而且精度更高
布尔类型
- 关键字 bool
- 两个值 true 和 false
- 占一个字节
字符类型
- rust 语言中char类型被用来描述语言中最基础的单个字符
- 字符类型的字面值使用单引号
- 占用4字节大小
- 是unicode 标量值, 可以表示仳ascll多得多的字符内容:拼音、中日韩文、零长度空白字符、emoji表情等。
- U+0000 ~ U+D7DD
- U+E000 ~ U+10FFFF
- 但unicode中并没有“字符”的概念,所以直觉上认为的字符也许与rust中的概念并不相符
复合类型
- 复合类型可以将多个值放在一个类型里
- rust提供了两种基础的复合类型:元组(tuple)、数组
元组(tuple)
- tuple长度是固定,一旦声明不能修改
- 获取tuple的元素值
- 可以使用模式匹配来解构(destructure)一个tuple来获取元素的值
fn main() { let tup = (500, 6.4, 1); let (x, y, z) = tup; println!("The value of y is: {}", y); }- 可以使用点标记法
fn main() { let x: (i32, f64, u8) = (500, 6.4, 1); let five_hundred = x.0; let six_point_four = x.1; let one = x.2; }
数组的用处
- 如果想让你的数据存入在stack上而不是heap上,或者想保证有固定数量的元素,这时使用数组更有好处。
- 数组没有vector灵活
- vector和数组类似,它由标准库提供
- vector 的长度可以改变
- 如果你不确定当前的场景是用数组还是vector,那么估计你应该用 vector
数组的类型
- 数组的类型以这种形式表示
#![allow(unused)]
fn main() {
let a: [i32; 5] = [1, 2, 3, 4, 5];
}
- 另外一种声明数组的方法
- 在中括号里指定初始值
- 然后是一个;
- 然后是数组的长度
#![allow(unused)]
fn main() {
let a = [3; 5];
}
- 访问数组的元素
fn main() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
}
- 数组是stack上分配的单个块的内存
- 可以使用索引来访问数组的元素(例子)
- 如果访问的索引超出了数组的范围, 那么:
- 编译会通过
- 运行时会报错 (runtime时会panic)
- rust不会允许其继续访问相应该地址的内存
函数
- 声音函数使用fun关键字
- 依照惯例,针对函数和变量名,Rust使用snake case 命名规范:
- 所有的字母都是小写的,单词之间使用下划线分开
- 函数的参数
- parameters, arguments
- 必须指明每个参数类型,可以有多个
- 函数体中的语句和表达式
- 函数体由一系列语句组成,可选的由一个表达式结束
- Rust 是一个基于表达式的语言
- 语句是执行一些动作的指令
- 表达式会计算产生一个值
- 函数的定义也是语句
- 语句不返回值,所以不可以使用let将一个语句赋给一个变量
- 函数的返回值
- 在 -> 符号后边声明函数返回值的类型, 但是不可以为返回值命名
- 在 Rust 里面,返回值就是函数体里面最后一个表达式的值
- 若想提前返回,需使用 return 关键字, 并指定一个值
- 大多数函数都是默认使用最后一个表达式作为返回值
- 注释
- 单行注释
- 多行注释
- 文档注释
控制流
- if表达式允许你根据条件来执行不同的代码分支
- 这人条件必须是bool类型
- if 表达式中,与条件相关联的代码块叫做分支(arm)
- 可选的,在后边可以另一个else表达式
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
Rust的循环
Rust提供了3种循环:loop,while,for
loop
loop关键字告诉rust反复的执行一块代码,直到你喊停
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {}", result);
}
while 条件循环
fn main() {
let mut number = 3;
while number != 0 {
println!("{}!", number);
number -= 1;
}
println!("LIFTOFF!!!");
}
for循环
- 可以使用while或loop来遍历集合,但是易错且低效
- 使用for循环更简洁紧凑,它可以针对集合中的每个元素来执行一些代码
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {}", element);
}
}
- 由于for循环的安全、简洁性,所以它在rust里用的最多
- Range
- 标准库提供
- 指定一个开始数字和一个结束数字, range可以生成它们之间的数字(不含结束)
- rev 可以反转