类型转换
Rust 是类型安全的语言,因此在 Rust 中做类型转换不是一件简单的事。
首先看一段错误的实例,a 和 b 拥有不同的类型,Rust 不允许两种不同的类型进行比较:
1 2 3 4
| let a: i32 = 10; let b: u16 = 100;
if a < b { println!("a < b 执行"); } 代码报错,因为a和b是不同的类型,不能直接用于比较
|
解决方法很简单,把数据类型改成同一种就可以通过编译。针对数值类型(包括字符 ASCII),rust 提供了两种专属数值类型的转换方式 as
和 TryInto
as 转换
as 转换非常方便,但使用时需要小心。因为每个数值类型能表达的数据范围不同,如果把范围较大的类型转换成较小的类型,可能会造成数据溢出的错误。
因此尽量把范围较小的类型转换成较大的类型,来避免这些问题的发生。数值类型可以通过 i8::MAX
的形式查看该类型能表达的最大值。
数值与数值
1 2 3 4 5
| let a: i32 = 10; let b: u16 = 100; let transformed_a = a as u16; let transformed_b = b as i32; println!("{transformed_a}, {transformed_b}");
|
数值与字符
转换字符,只有 u8
类型的数据(ASCII 范围)才能转换成字符,但字符可以转换成包含 u8 范围的数值类型,如 i16,u16 等
1 2 3 4 5
| let a = 'a'; let transformed_a = a as u8; let c: u8 = 99; let transformed_c = c as char; println!("{transformed_a}, {transformed_c}");
|
数值与内存指针
rust 指针可通过 as_mut_ptr
获取,它的形式与 C
一样,数组的指针也是第一个元素的指针。
指针常用 usize(4 bytes(32 bit) 或 8 bytes(64 bit)表示。
数组指针偏移,第 N+1 元素地址 = 第 N 元素地址 + 元素内存大小
1 2 3 4 5 6 7 8 9 10 11 12
| let mut v = vec![0; 3]; let p1: *mut i32 = v.as_mut_ptr(); let first_address = p1 as usize; let second_address = first_address + size_of::<i32>(); let p2 = second_address as *mut i32; unsafe { *p2 += 1; } println!( "v = {:?}, second_address = {:?} p2 = {:?}", v, second_address, p2 );
|
强制类型转换的边角知识
- 转换不具有传递性 就算 e as U1 as U2 是合法的,也不能说明 e as U2 是合法的(e 不能直接转换成 U2),因为 as 关键字执行的转换可能涉及到具体的转换逻辑和额外的步骤,这些逻辑在不同的转换路径中可能不适用。
TryInto 特征
在一些场景中,使用 as 关键字会有比较大的限制,比如转换失败直接 panic。如果希望在类型转换上拥有完全的控制而不依赖内置的转换,例如处理转换错误,那么可以使用 TryInto 特征。
如果你要使用一个特征的方法,那么你需要引入该特征到当前的作用域中,如果希望使用 try_into 方法,需要引入对应的 TryInto 特征。
在 1.75.0,TryInto 已通过 std::prelude
预导入,无需手动 use 手动导入。
try_into 方法会尝试进行一次转换,并返回一个 Result,此时就可以对其进行相应的错误处理(使用时需要给结果标注转换后的类型)。
1 2 3 4 5 6 7 8 9
| use std::convert::TryInto;
let a = 8 as i32; let b: u8 = a.try_into().expect("转换失败"); let c: u8 = match a.try_into() { Ok(v) => v, Err(e) => panic!("expr"), }; println!("{b}, {c}");
|
巩固 rust 认识
rust 编译的过程,会根据给定的类型生成对应的代码,给变量标注类型和给表达式指定类型的效果是一样的:
1 2
| let a = 8 as u8; let b: u8 = 8;
|
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| fn main() { let a: i32 = 10; let b: u16 = 100; println!("{:?}", i8::MIN); println!("{:?}", u8::MIN == 0);
let transformed_a = a as u16; let transformed_b = b as i32; println!("{transformed_a}, {transformed_b}");
let a = 'a'; let transformed_a = a as u32; let c: u8 = 99; let transformed_c = c as char; println!("{transformed_a}, {transformed_c}");
let mut v = vec![0; 3]; let p1: *mut i32 = v.as_mut_ptr(); let first_address = p1 as usize; let second_address = first_address + size_of::<i32>(); let p2 = second_address as *mut i32; unsafe { *p2 += 1; } println!( "v = {:?}, second_address = {:?} p2 = {:?}", v, second_address, p2 );
let a = 8 as i32; let b_1: u8 = a.try_into().unwrap(); let b: u8 = a.try_into().expect("转换失败"); let c: u8 = match a.try_into() { Ok(v) => v, Err(e) => panic!("expr"), }; println!("{b}, {c}"); }
|