【RUST学习日记】第8课 类型转换(上)

简介: 【RUST学习日记】第8课 类型转换(上)

0x00 回顾


上一节讲解了字面量和常见一些运算符,还记得上节课最后留了一个练习题吗。

小明有5块钱,小红有3块5,小明和小红总共有多少钱呢?

你们成功运行出结果了吗,这节咱们介绍下Rust的类型转换。


0x01 类型转换(Type Cast)


与其它语言不同,在Rust中,整数和浮点数不能再一起做运算。先看下示例:

let o = 5;
    let p = 3.5;
    dbg!(o + p);

上面代码的输出结果是什么呢?如果你有C,Java等语言基础,那么你肯定会说上面的结果是8.5。但是在Rust中编译器会报错,如下图所示。


0a2653c851af460fa595bd959398a8f1.png


cannot add a float to an integer,不能把浮点数加到整数上。在Rust中不会帮你隐式的转换格式。


0x02 类型转换表达式(Type Cast Expressions)


语法

类型转换表达式 :

ExpressionasTypeNoBounds

类型转换使用as操作符来表示。它可以将as左边的类型强制转换为右边的类型。示例如下:

let o = 5;
let q = o as f64;
dbg!(q);

代码执行结果:

[src\main.rs:13] q = 5.0

不可变变量o默认的类型是i32,将其强制转换为f64的类型复制给不可变变量q,结果变为了5.0,类型变为f64浮点型。


0x03 旧题重解


咱们得知as可以类型转换,那么题目的答案就显而易见了。

// 先将 o 转为 f64类型,再做加法
dbg!(o as f64 + p);

代码执行结果:

[src\main.rs:16] o as f64 + p = 8.5

现在的程序就不会报错了,结果也计算出来了。


0x04 类型转换规则(Coercion Rule)


as可以被用于显示的强制类型转换。在数值进行强制转换时可能会存在精度问题。这里我再介绍下数值间强制转换的一些注意事项。


1、在两个相同长度大小的整数间进行有无符号强制转换,请注意符号位和整数范围。例如:u8 -> i8


下面是扩展知识。要理解这条规则,需要先明白在计算机中是如何存储数值的。

在计算机中存在有符号和无符号数两种数值,有符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位,三种表示方法各不相同。在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。

上面提到了有符号数3个概念,原码,反码,补码。下面以+1-1为例,简单解释下这三个概念,以8位整数类型为例。有符号数的最高位是符号位,0表示正数,1表示负数,因此+1的原码就是0000 0001-1的原码就是1000 0001对于正数来说,其原码,反码,补码都相同负数的反码,则是对除符号位的每一位都取反(有关取反操作上节已经介绍了)。那么-1的反码就是1111 1110补码就是在反码的基础上再加1-1的补码就是1111 1111。如果反码在加1操作后,8位变为了9位,则将会舍弃最高位。


Rust强转的示例代码如下:

let a: i8 = 1;
    let b: i8 = -1;
    println!("[有符号数] {} 转为[无符号数]: {}, 转换后的二进制为 {:08b}", a, a as u8, a as u8);
    println!("[有符号数] {} 转为[无符号数]: {}, 转换后的二进制为 {:08b}", b, b as u8, b as u8);
    let a: u8 = 1;
    let b: u8 = 255;
    println!("[无符号数] {} 转为[有符号数]: {}, 转换后的二进制为 {:08b}", a, a as i8, a as i8);
    println!("[无符号数] {} 转为[有符号数]: {}, 转换后的二进制为 {:08b}", b, b as i8, b as i8);

代码执行结果:

[有符号数] 1 转为[无符号数]: 1, 转换后的二进制为 00000001
[有符号数] -1 转为[无符号数]: 255, 转换后的二进制为 11111111
[无符号数] 1 转为[有符号数]: 1, 转换后的二进制为 00000001
[无符号数] 255 转为[有符号数]: -1, 转换后的二进制为 11111111

2、较长位数的整数转换为较短位数的整数时会发生截断。例如:i16 -> i8

16位整数300转为8位整数会发生什么?计算机会将300的二进制高位舍弃,只保留低位,这就是截断,会发生精度损失。示例如下:

let a: i16 = 300;
    println!("{} 的 二进制为:{:016b}", a, a);
    // 发生数据截断,保留了低位,截断了高位
    println!("16位整数 {} 转为 8位整数:{},其二进制为:{:016b}", a, a as i8, a as i8);

代码执行结果:

300 的 二进制为:0000000100101100
16位整数 300 转为 8位整数:44,其二进制为:0000000000101100

3、较短位数的整数转换为较长位数的整数时会有下面两种情况。例如:i8 -> i16

  • 如果该值是无符号数,则高位使用0填充
  • 如果该值是有符号数,则高位使用符号数填充

示例代码:

let a: u8 = 45;
    // a 是8位整数,但是输出时的格式我加了0填充,可以忽略前8位的显示
    println!("8位无符号整数 {} 的 二进制为:{:016b}", a, a);
    println!("8位无符号整数 {} 的 转为16位整数的二进制为:{:016b}", a, a as u16);
    let b: i8 = -121;
    // b 是8位整数,但是输出时的格式我加了0填充,可以忽略前8位的显示
    println!("8位有符号整数 {} 的 二进制为:{:016b}", b, b);
    println!("8位有符号整数 {} 的 转为16位整数的二进制为:{:016b}", a, b as i16);

代码执行结果:

8位无符号整数 45 的 二进制为:0000000000101101
8位无符号整数 45 的 转为16位整数的二进制为:0000000000101101
8位有符号整数 -121 的 二进制为:0000000010000111
8位有符号整数 45 的 转为16位整数的二进制为:1111111110000111


0x05 小结


本篇文章仅仅是介绍了3个类型转化规则,还有6个规则没有介绍,由于篇幅过长不适合阅读,就分成两篇文章。小伙伴们不要忘记了......

未完待续,源码将在下节提供...........

相关文章
|
10天前
|
存储 Rust 网络协议
【Rust学习】10_定义枚举
在这一章我们学习 枚举(enumerations),也被称作 enums。枚举允许你通过列举可能的 成员(variants) 来定义一个类型。首先,我们会定义并使用一个枚举来展示它是如何连同数据一起编码信息的。接下来,我们会探索一个特别有用的枚举,叫做 Option,它代表一个值要么是某个值要么什么都不是。然后会讲到在 match 表达式中用模式匹配,针对不同的枚举值编写相应要执行的代码。最后,我们将学习 if let 结构,另一个简洁方便处理代码中枚举的结构。
26 7
|
1月前
|
Rust 算法 安全
学习Rust
【10月更文挑战第13天】学习Rust
52 8
|
1月前
|
Rust 安全 算法
Rust的学习
【10月更文挑战第12天】Rust的学习
28 2
|
1月前
|
Rust 算法 安全
如何学习Rust编程?
【10月更文挑战第12天】如何学习Rust编程?
41 1
|
1月前
|
Rust API
【Rust学习】09_方法语法
结构体让你可以创建出在你的领域中有意义的自定义类型。通过结构体,我们可以将相关联的数据片段联系起来并命名它们,这样可以使得代码更加清晰。在 impl 块中,你可以定义与你的类型相关联的函数,而方法是一种相关联的函数,允许您指定结构体的实例具有的行为。 但是结构体并不是创建自定义类型的唯一方式:让我们转向 Rust 的 enum 功能,将另一个工具添加到你的工具箱中。
17 0
|
2月前
|
Rust 索引
【Rust学习】08_使用结构体代码示例
为了了解我们何时可能想要使用结构体,让我们编写一个计算长方形面积的程序。我们将从使用单个变量开始,然后重构程序,直到我们改用结构体。
92 2
|
2月前
|
存储 Rust 编译器
【Rust学习】07_结构体说明
**struct**或 ***structure***是一种自定义数据类型,允许您命名和包装多个相关的值,从而形成一个有意义的组合。如果您熟悉面向对象的语言,那么**struct**就像对象中的数据属性。在本章中,我们将比较和对比元组与结构体,在您已经知道的基础上,来演示结构体是对数据进行分组的更好方法。
25 1
|
3月前
|
存储 Rust 安全
【Rust学习】06_切片
所有权、借用和切片的概念确保了 Rust 程序在编译时的内存安全。Rust 语言提供了跟其他系统编程语言相同的方式来控制你使用的内存,但拥有数据所有者在离开作用域后自动清除其数据的功能意味着你无须额外编写和调试相关的控制代码。
26 1
|
2月前
|
Rust Linux Go
Rust/Go语言学习
Rust/Go语言学习
|
4月前
|
Rust 编译器
【Rust学习】05_引用和借用
在这章我们将开始学习Rust的引用和借用,它们是Rust中重要的概念,它们允许我们创建可变引用,以及创建不可变引用。
29 0