Rust基础
Rust基础
基础
两个冒号调用静态方法
声明变量的关键字 let,rust里的的变量默认是不可变的(immutable),不可变变量;让变量可修改就加上个 mut
let a = 1
let mut a = 1
- 传参
// 传一个字符串
read_line(guess)
// 传一个可变字符串
read_line(mut guess)
// 方法的参数是通过引用传递的。
// 传一个可变字符串的引用。&是取地址符,表示这个参数是个引用,代表可以在不同地方访问同一个参数。
read_line(&mut guess)
Prelude Trait
Prelude
在rust的标准库中,有一个prelude的子模块,这个模块包含了默认导入的所有符号。
- std库是默认导入的,std库中也有prelude的模块,里面的东西也是默认导入的。
- **默认导入的意思就是不用手动在 use something::something; **
trait
一种抽象接口(可以理解为一个抽象类),这个抽象接口可以被继承,并且trait只能由3部分组成:function, types, constants
流程基础
变量与可变性
- 声明变量使用let关键字
- 默认情况下,变量是不可变的(Immutable),加上mut关键字就可以改变了。
变量与常量
常量绑定值以后也是不可变的,和不可变变量的区别如下:
- 不可以使用mut,常量永远是不可变的。
- 声明常量使用const关键字,它的类型必须被标注。
- 常量可以在任何作用域内进行声明,包括全局作用域。
- 常量只可以绑定到常量表达式,无法绑定到函数的调用结果或只能在运行时才计算出的值。
在运行期间,常量在其声明的作用域内一直生效。常量的值可以加下划线增加可读性。
const MAX_POINTS: u32 = 100_000;
重影(隐藏) Shadowing
可以使用相同的名字声明新的变量,新的变量就会shadow之前声明的同名变量。重影过后,原来的变量的值就会变换成新的值(在后续的代码中,这个变量名代表的就是新的变量)。
// 不合法
let x = 5;
x = x + 1;
// 合法,重影
let x = 5;
let x = x + 1;
shadow 和把变量标记为mut是不一样的:
- shadow不使用let关键字,给非mut变量赋值会报错。
- let声明的同名新变量也是不可变的,但是可以和以前的类型不同。
理解:可变变量重新赋值的时候不需要重影,只有不可变变量重新赋值的时候要重影,重影要带let。
数据类型
rust是静态编译语言,在编译时必须知道所有变量的类型。
- 基于使用的值,编译器一般能推断出它的具体类型。
- 类型比较多(比如Sting转整数的parse方法),就必须添加标注,否则编译会报错。
指明变量 let guess: u32 = guess.trim().parse().expect("Not u32 type.")
标量类型
整数类型
整数类型没有小数部分。
- u32 无符号的帧数类型,占据32位的空间。
- 无符号(非负)由 u 开头。(u8/u16/u32/u64/u128/arch(usize))
- 有符号(有正有负))由 i 开头。(i8/i16/i32/i64/i128/arch(isize))
isize和usize
由架构序所决定:x86, x64
整数字面值
使用不同进制的数字时怎么表示。可以用下划线增加可阅读性。
- 10进制 98222
- 16进制 0xff
- 8进制 0o877
- 2进制 0b11_00
- Byte(u8 only) b'A'
除了byte类型外,所有的数值字面值都允许使用类型后缀。
- 57u8 u8类型的数值57
let mut guess = 57u8;
Rust默认类型
- 整数默认 i32
整数溢出
超出了范围。比如u8类型给了个256,那么在调试模式下编译会panic,发布模式下不检查。
发生了溢出,rust会进行“环绕”操作(清零),256变成0,257变成1。
浮点类型
- f32 32位,单精度
- f64 64位,双精度
Rust默认类型
- f64
布尔类型
bool -> true and false。
字符类型
- char 最基础单个字符。
- 字符类型的字面值使用单引号。
复合类型
复合类型可以将多个值放在一个类型里。
元组(tuple)
多个类型的多个值放在一个类型里。长度是固定的,一旦声明之后就无法修改了。
创建tuple
在小括号里,将值用逗号分开。tuple中的每个位置都对应一个类型,各个类型元素不必相同。在tuple里也可以指明每个值的类型。
使用时下标用点标记法,从0开始。
创建: let foo: (i32, f64, u32) = (-1, 6.5, 8);
使用: println!("{} {} {}", foo.0, foo.1, foo.2);
解构赋值
let (x, y, z) = foo;
数组
数组可以将多个值放在一个类型里,每个元素的类型必须相同,长度也是固定的。在中括号里,用逗号分开。
数组类型以这种形式标识:[类型; 长度]
创建 let foo: [i32; 3] = [1, 2, 3]
特殊声明,仅用于数组里的所有值都一样。
创建 let a = [3;5]
let a = [3, 3, 3, 3, 3]
存放在栈内存上,并能保证有固定的数量,此时应该用数组。
EG: rust里可以用Vector,这个类型由标准库提供,长度可以改变(类似python中的list),一般用Vector。
访问数组使用中括号内放下标。Foo[0]
如果访问时超出了数组的范围,此时会出现数组越界。编译会通过,运行会报错。
rust 不允许其继续访问相应地址的内存。(C/C++会允许)
函数
使用fn关键字,使用snake case命名规范。只要函数声明了,并且够得着就行。
形参和实参
和python或其他语言也差不多,但是必须声明每个参数的类型
fn getAccount(account: i32, password: u64){}
函数体中的语句和表达式
函数体由一系列语句组成。函数和函数的定义也是语句。
{}块语句由一个表达式结束,最后一个语句如果是表达式不加分号会直接返回该值,加了分号就是返回tuple (),因为变成了语句。
简单理解
表达式:有返回值,会计算产生一个值。
语句:没有返回值,一些动作的指令。所以不可以使用let将一个语句赋给一个变量,有返回值才能赋给一个变量。
函数的返回值
- 在 -> 符号后面声明函数的返回值类型,但是不可以为返回值命名。
- 在rust里返回值就是函数体里面最后一个表达式的值。
- 若想提前返回,使用retrun并指定一个值。(大多数函数都是默认使用最后一个表达式作为返回值)
fn main(){
// 5
let x = returnFive()
// tuple
let y = returnPlusFive(6)
}
fn getAccount(account: i32, password: u64){}
fn returnFive() -> i32{
// 返回5
5
}
fn returnPlusFive(arg: i32) -> (){
// 这里是语句,加了; 会返回一个tuple ()
arg + 5;
}
关于语句和表达式的一点整理
- 表达式属于语句,语句分为声明语句和表达式语句。
- 声明语句:声明各种语言项。
- 表达式语句:如果此表达式语句用了;结尾,那么求值结果将被舍弃,并总是返回 单元类型 tuple (),也代表无返回值,不需要在函数签名中指定返回类型。
- 当遇到函数的时候,会将函数体的花括号识别为块表达式,块表达式总是返回最后一个表达式的值。
总结:在Rust中,如果一个语句不以分号结尾,那么他就是一个表达式(expression),有返回值;如果一个语句有分号,那么它就是一个语句(statement),没有返回值。
if/else/else if
if x != 5{
println!("5");
} else if x % 3 == 0 {
println!("!=5")
} else {
println!("kkk")
}
if 的重构
用match来重构。
if 表达式
if 因为是表达式,所以可以被变量接收。(和python if简写一样,要多写个花括号)
let number = if x == "hi" {6} else {5};
if else不允许拥有不兼容的类型,返回的类型必须是一样的。接收的变量的值的类型一定不能是不确定的。rust要求if else表达式里面每个可能成为结果的分支返回的类型必须是一样的。
循环
3种循环:loop, while, for
loop
反复执行,直到主动停止。使用 break 关键字停止循环。
loop 可以有返回值,接在break后面。
break 2*2
while
条件循环。每次执行一次循环体之前都判断一次条件。
while number != 0{}
配合数组使用的时候容易出现数组越界。while速度比较慢。
for
遍历集合建议使用for。
let a = [1, 2, 3];
for i in a.iter(){
// 这个i是个引用,并没有复制出来。
println!("{}", i)
}
for 不会数组越界。安全,简洁。
Range
和python的一样。指定一个开始数字和结束数字(不含结束)。
(1..4) // 1到3,不包含4
rev
rev可以翻转Range。
for i in (1..4).rev(){}