自学内容网 自学内容网

Rust 中那些让人眼花缭乱的类型转换

> 本文将介绍类型转换,因为rust是一门类型安全的语言,所以在rust中进行类型转换不是一件简单事轻松的事情。rust中类型转换大体分为`as转换`,`TryInto 转换`,`通用类型转换`等三大类。
## as转换
我们先看一个简单的小类型转大类型的例子:
```rust
fn main(){
   let x:i32 = 12;
   let y:u16 = 10;
   if a < b {
      println!("a比b小!!");
   }
}
```
首先我们定义两个变量`x`和`y`,**x**的类型是`i32`类型,**y**的类型是`u16`类型。i32明显表示的范围要比u16大,那么一个大范围类型的数据和一个小范围的数据类型做比较明显的不合时宜,打个比方我们大人和小孩子做比较,你能把大人变成小孩子吗,明显的不可能,同理可得在编程语言中也是如此,编程只不过对我们人类世界的模仿,那么模仿就要遵循人类社会的一些规则,这就造就了编程语言的语法和规则。因此我们对于大小不同类型的数据类型做比较要有一定的手段和方法,我们都之都我们不可能回到过去但是我们可以畅想未来,假设此时未来在于当下是小范围的,而过去则是大范围的。我们只需要把未来无限叠加就会到跟过去一样的时间维度。那么类型转换也是一样,我们把小数据类型需要转成大数据类型。
> 使用类型转换需要小心,因为如果执行以下操作 300_i32 as i8,你将获得 44 这个值,而不是 300,因为 i8 类型能表达的的最大值为 2^7 - 1,使用以下代码可以查看 i8 的最大值:
```rust
let a = i8::MAX;
println!("{}",a);
```
下面我们给出常用的类型转换:
```rust
fn main() {
   let a = 3.1 as i8;
   let b = 10_i8 as i32;
   let c = 'b' as u8; // 将字符'a'转换为整数,98
   println!("{},{},{}", a, b, c);
}
```
as类型转换中还有一个比较特殊的存在就是`内存地址`转化为`指针`,下面我们给出一个例子来说明这种转化类型的具体用法:
```rust
fn   mem_address_change_point() {
    let mut values: [i32; 2] = [1, 3];
    let p1: *mut i32 = values.as_mut_ptr();
    let first_address = p1 as usize; // 将p1内存地址转换为一个整数
    let second_address = first_address + 4; // 4 == std::mem::size_of::<i32>(),i32类型占用4个字节,因此将内存地址 + 4
    let p2 = second_address as *mut i32; // 访问该地址指向的下一个整数p2
    unsafe {
        *p2 += 1;
    }
    assert_eq!(values[1], 3);
}
```
需要注意的是类型转换不具备传递性:就算 `e as U1 as U2` 是合法的,也不能说明 `e as U2` 是合法的(e 不能直接转换成 U2)。
## TryInto 转换
我们根据上面的as转换得出as转换会导致好精度丢失的问题,可能转换的数据和原来的差距比较的大例如:`300_i32 as i8`的结果是`44`是不是和原来的300相差很大啊,那么rust提供了另外一种解决思路就是我们现在讲到的`TryInto 转换`。先看一个例子:
```rust
let value: u32 = 10;
let result: Result<i32, TryFromIntError> = value.try_into();
match result {
    Ok(num) => println!("转换成功: {}", num),
    Err(e) => println!("转换失败: {}", e),
}
/// 打印出:转换成功: 10
```
> TryInto被实现为泛型trait,这意味着它可以用来转换任何实现了TryInto的类型。当你对一个值使用try_into()方法时,它会尝试将该值转换成目标类型。如果转换成功,它返回Ok包含转换后的值;如果失败,则返回Err包含错误信息。
## 通用类型转换
```rust
struct Foo {
    x: u32,
    y: u16,
}

struct Bar {
    a: u32,
    b: u16,
}

fn reinterpret(foo: Foo) -> Bar {
    let Foo { x, y } = foo;
    Bar { a: x, b: y }
}
```
这段Rust代码定义了两个结构体`Foo`和`Bar`,以及一个函数`reinterpret`,该函数将`Foo`类型的实例转换为`Bar`类型的实例。下面是对代码的逐行解释:

1. 定义了一个名为`Foo`的结构体,它包含两个字段:
   - `x`:一个无符号的32位整数(`u32`)。
   - `y`:一个无符号的16位整数(`u16`)。

2. 定义了一个名为`Bar`的结构体,它也包含两个字段:
   - `a`:一个无符号的32位整数(`u32`)。
   - `b`:一个无符号的16位整数(`u16`)。

3. 定义了一个名为`reinterpret`的函数,它接受一个`Foo`类型的参数并返回一个`Bar`类型的实例:
   - 函数参数`foo`是一个`Foo`实例。
   - 使用`let Foo { x, y } = foo;`解构`foo`,将`foo`的`x`和`y`字段分别赋值给局部变量`x`和`y`。
   - 创建一个新的`Bar`实例,将`x`赋值给`Bar`的`a`字段,将`y`赋值给`Bar`的`b`字段。
   - 返回这个新创建的`Bar`实例。

这个函数的目的是将`Foo`结构体的字段直接“重新解释”为`Bar`结构体的字段。这里的“重新解释”实际上只是简单的字段赋值,因为两个结构体的字段类型是相同的。在这种情况下,并没有进行任何底层的位级操作或内存重新解释,仅仅是字段值的复制。

这种转换是安全的,因为`Foo`和`Bar`的字段类型完全匹配,且没有涉及到任何可能会导致数据丢失或错误的类型转换。这个函数可以用于不同结构体之间的数据共享,或者在需要将一种类型的数据结构转换为另一种类型但保持数据不变的情况下使用。


原文地址:https://blog.csdn.net/qq_27632921/article/details/143626932

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!