Rust 类型的基础
Rust 类型的基础是一组固定宽度的数值类型,以及布尔类型和字符类型。基本类型包括:机器类型,元组(tuple),指针类型,数组、向量和切片,字符串类型。
机器类型
- 整数:无符号整数(u8, u16, u32, u64),有符号整数(i8, i16, i32, i64),
- 浮点数(f32, f64),
- 机器字(usize, isize):指的是运行代码的机器上内存地址的宽度,通常是32位或64位。
| 位数 | 无符号整数 | 有符号整数 | 浮点数值 |
|---|---|---|---|
| 8 | u8 | i8 | |
| 16 | u16 | i16 | |
| 32 | u32 | i32 | f32 |
| 64 | u64 | i64 | f64 |
| 机器字 | usize | isize |
整数类型
(1.1) 整数范围
- 无符号数范围: 0 到 2的n次方 - 1;
- 有符号数范围: -2的n-1次方 到 2的n-1次方 - 1。
- 机器字:精度取决于目标机器的寻址空间大小:32位机器上是32位长,64位机器上是64位长。
(1.2) 一些特点
- 整数字面量可以通过一个后缀表示类型。例如,32u8, 1980usize, -20i32。
- 整数字面量可以使用前缀 0x、0o、0b 分别表示 16进制,8进制,和二进制。例如:oxcafeu32,0o106。
- 整数(不论进制)长度较长时,为了可读性,可以在数字之间插入下划线。比如:21_485_295i32,0b0010_1010。
- 数组索引必须是 usize 值。数组或向量的长度,也用 usize 表示。
- 通常使用 u8 类型表示字节值;从 File 或 Socket 读取数据拿到的是 u8 值数据流。
(1.3) 整数溢出
- 在调试构建中,编译器会检查算术操作是否有整数溢出。 let b = std::i32::MAX + 1; // 发生panic, 会溢出
- 在发布构建中,这个操作会翻转为最小的 i32 负值。
- 建议使用: let a:i32 = std::i32::MAX; let b = a.wrapping_add(1);
(1.4) 字节字面量
- Rust还提供了字节字面量(byte literal),使用字符字面量表示 u8 值。字节字面量中只能出现ASCII编码的字符。例如:let c:u8 = b'x'; // 此处c为120u8。
- 某些特殊字符,需要进行转义。 例如:
let c = b'\''; // 单引号('),39u
let c = b'\\'; // 反斜杠(\),92u8
let c = b'\n'; // 换行,10u8
let c = b'\r'; // 回车, 13u8
let c = b'\t'; // 制表符, 9u8
- 反过来,对于难写或难读的字符,可以用十六进制写出他们的编码。
let d = b'\x41'; // 十六进制41这个数字,表示的字符,的字面量的u8数字。ASCII 不容易表示的字符,只能直接写成数字了。除非想强调是 ASCII 字符,否则直接写数字就行了。
let e: char = b'\x41' as char; // 这个数字代表的 char。
(1.5) 部分整数函数
assert_eq!(2u16.pow(3), 8);
assert_eq!((-5i32).abs(), 5);
assert_eq!(0b10_1101u8.count_ones(), 4);
let aa = -100i32;
println!("aa.is_negative = {}", aa.is_negative()); // aa.is_negative = true
2. 浮点数
- Rust支持单、双精度浮点类型,分别为 f32, f64。
- 如果浮点字面量中没有类型后缀,那么rust会根据上下文推断是 f32 还是 f64,若两种情况都有可能,则默认是 f64。
- 浮点数通用形式:31415.926e-4f64 ,组成包括:整数部分(31415) + 小数部分(.926) + 指数(e-4) + 类型后缀(f64)。
- 部分浮点函数:
assert_eq!(5f32.sqrt() * 5f32.sqrt(), 5.0);
assert_eq!(-1.0f64.floor(), -1.0);
assert!((-1.0/std::f32::INFINITY).is_sign_negative());
3. 布尔类型
- 布尔(bool)类型值有两个值: true 和 false。
- Rust的 as 操作符 可以把 bool 值转换为整数类型。
assert_eq!(true as u8, 1); assert_eq!(false as u8, 0); - 但是as不能反向转换,不能从数值 转换为 布尔值,除非使用表达式(如 a!= 0)。
4. 字符类型
-
字符类型 char 以 32 位值的形式表示单个 Unicode 字符。
-
Rust 使用 char 类型表示单个字符,但对字符串或文本流使用 UTF-8 编码。因此,String 将其文本表示为一个 UTF-8 字节的序列,而不是字符(char)的数组。
println!(" {}", std::mem::size_of::<char>()); // output: 4 let q1: char = 'a'; let q2: char = '好'; let s: String = "好a".to_string(); println!("{}, {}, {}", q1.len_utf8(), q2.len_utf8(), &s.len()); // output: 1, 3, 4 -
Rust 从不隐式地在 char 与其他类型直接进行转换. 若有需要,可以使用 as 操作符。在char 通过 as 转其他类型时,若目的类型小于 32 位,字符值的高位(upper bits) 则会被截断。
-
反过来,数字中,只有 u8 类型的整数可以直接转换为 char 类型。其他类型的数值,可能包含了非法的 Unicode 码点。 使用 std::char::from_u32 函数 会得到 Option 值。
-
字符类型的常用方法:
println!("{}", '*'.is_alphabetic()); // false println!("{}", 'β'.is_alphabetic()); // true println!("{:?}", '5'.to_digit(10)); // Some(5) println!("{:?}", std::char::from_digit(3, 10)); // Some('3') println!("{:?}", std::char::from_digit(10, 16)); // Some('a')
5. 元组类型
- 元组(tuple)由多个各种类型的值组成,使用点(.)索引来访问元组中的内容。例如:
let x:(&str, i32) = ("aa", 10);
println!("x0 = {}, x1 = {}", x.0, x.1); // x0 = aa, x1 = 10
fn split_at() -> (i32, &str); // 元组作为返回值
let str = "hello world";
let re = str.split_at(5);
println!("re.0 = {}, re.1 = {}", re.0, re.1); // re.0 = hello, re.1 = world
-
零元组 也被称为 基元类型(unit type),因为它只有一个值,写作 ()。 当不存在有意义的值而上下文又要要求某种类型时,Rust会使用这种基元类型。
-
没有返回值的函数的返回类型就是 ()。
fn swap<T>(x: &mut T, y: &mut T) {} // 先定义一个函数
let mut a = "10".to_string();
let mut b = 20.to_string();
let re = swap::<String>(&mut a, &mut b);
println!("re = {:?}", re); // 此处输出为: re = ()