浅谈Rust基础类型
基础类型
rust是一门静态编程语言, 所以我们有必要知道它的类型, rust的类型可以分为基本类型和复合类型(也可以称之为复杂类型), 基本类型指的就是原子化最小的类型, 它不能转换为其他类型;
rust不像ts, ts是js的超集, ts可以更好的推断类型, 但是rust拥有一个很聪明的编译器, 你可以无需指定类型, 让编译器去自动推断, 但是某些情况下编译器无法推断类型, 比如这样
let guess = "42".parse().expect("Not a number!");
鬼知道guess是什么类型, 所以编译器会报错, 你只需要显式的指定类型即可;
数值类型
rust创建数值非常简单
let a = 1;
整数
我们继续来探讨整数类型, 我们之前了解过的i32类型, 表示有符号的32位整数
i表示integer, 与之相反的是u, 代表无符号
类型统一定义为 “有无符号” + “位数(bit)”, 无符号表示就是正数, 有符号就是正负; 简单的使用准则需要我们记住, rust整形默认使用i32, 可以首选i32, 而且性能也是最好的;
我们在处理整型的时候, 如果设置的值超过了范围, 那么rust会区分模式, 做不同的决策, 比如在debug模式中, 程序会报错退出; 如果是release环境, 会被补码为范围内的最小值, 因此这样的结果是不符合预期的, 会被认为是错误的.
浮点数
浮点数默认类型是f64, 但是rust有一个浮点数的陷阱, 我们通常会使用十进制表达浮点数, 但是rust底层是使用二进制实现浮点数类型的, 比如说0.5在十进制上存在精确表达, 但是在二进制中不存在, 所以就会造成歧义, 所以想要表达完整的真实浮点数字, 就必须使用无限精度的浮点数才行.
还有一个注意的点就是, 我们不要对浮点进行比较, 这和js一样, 由于rust的浮点类型底层是二进制, 而js同样在浮点数运算时也是二进制, 都会存在不准确的问题; 在rust中对浮点数进行比较的时候, float声明了PartialEq
, 注意它不是Eq
; 在map数据结构中的k类型, rust是需要你传入声明过Eq
的类型, 很显然float不满足要求; 而且当我们使用浮点做比较的时候, 会造成编译器错误.
NaN
和js一样, 我们可以在rust中做一个防御性编程:
fn main() {
let x = (-42.0_f32).sqrt();
if x.is_nan() {
println!("未定义的数学行为")
}
}
序列
rust提供了一种简洁的方式生成连续的数值
// 生成1-5 (包括5)
1..=5
// 生成1-5 (不包括5)
1..5
字符, 布尔, 单元类型
这一部分比较简单,
char
fn main() {
let c = 'z';
let z = 'ℤ';
let g = '国';
let heart_eyed_cat = 'hhh';
}
不管是ascii, 还是unicloud都算作rust字符char; 另外字符是用’’
包裹的, “”
是表达为字符串
bool
rust中的布尔类型和其他语言一样, 存在true/false
单元类型
0长度的元组, 单元类型使用()
来表达, 我们可以用单元类型占位, 它不占用任何内存, rust函数中的main还有print函数都会返回一个单元类型. 我们不能说main函数没有返回值, 因为没有返回值在rust中是有单独的定义的(发散函数: diverge function)
, 顾名思义, 无法收敛的函数.
语句和表达式
在rust的函数体中是一系列语句组成, 最后是由表达式返回, 比如这样
fn add(x: i32, y: i32) -> i32 {
let x = x + 2; // 语句
let y = y + 3; // 语句
x + y // 表达式
}
语句
let x = x + 2; // 语句
let y = y + 3; // 语句
由于let是语句, 我们不能将let赋值给其他值:
let b = (let a = 8);
这样编译器会报错…
表达式
表达式会进行运算/求值, 比如1+2, 会返回3, 我们在语句上面写了这段代码:
let x = x + 2;
这里的x + 2确实是一个表达式, 只要记住只要能返回值, 它就是表达式
而且表达式不能包含分号, 比如下面一段代码
let y = {
let x = 3;
x + 1
};
如果x + 1包含了分号, 那么此时这个语句块不会返回任何值了, 也就不算作表达式了, 所以我们在rust中编写函数的时候, 如果要返回值, 就要注意这里不需要加分号;
函数
rust的函数很简单, 下面是一个例子, 有关键字, 函数名称, 形参名称和类型, 函数返回值类型, 以及一个代码块, 就构成了一个最简单的函数:
fn add(i: i32, j: i32) -> i32 {
i + j
}
- 首先rust是强类型的语言, 我们在编写函数的时候, 参数的类型是必须的, 如果不提供参数的类型是会报错的.
- 函数的返回值就是代码块的最后一行的表达式返回值, 当然我们也可以使用return关键字提前返回也可以
- 在单元类型中, 我们提到了无返回值, 我们可以使用单元类型作为返回, 而一些表达式你不幸加了分号变成了语句, 那么此时也会返回一个单元类型.
- 在上文提到了diverge function, 我们可以使用
!
作为函数返回类型, 这一般会作为程序崩溃的函数, 代表永不返回:
fn end() -> ! {
panic!("it is over...");
}