上面代码的输出结果是什么呢?如果你有C,Java等语言基础,那么你肯定会说上面的结果是
8.5
。但是在Rust中编译器会报错,如下图所示。
cannot add a float to an integer
,不能把浮点数加到整数上。在Rust中不会帮你隐式的转换格式。
0x02 类型转换表达式(Type Cast Expressions)
语法
类型转换表达式
:
Expression
as
TypeNoBounds
类型转换使用
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
4、
浮点数转换为整数时,将会直接
舍弃
小数位,保留整数部分
。另外还有下面3点要注意:
-
如果浮点数是
NAN
,转为整数时将会返回
0
-
如果当前的浮点数值大于所转换的整数类型的最大值,则将返回该整数类型的最大值
-
如果当前的浮点数值小于所转换的整数类型的最大值,则将返回该整数类型的最小值
示例代码:
// NAN 相当于 0.0 / 0.0
let a: f64 = f64::NAN;
// 正无穷大 +∞
let b: f64 = f64::INFINITY;
// 负无穷大 -∞
let c: f64 = f64::NEG_INFINITY;
println!("NAN 转换为整数的值为 {}", a as i32);
println!("+∞ 转换为整数的值为 {}", b as i32);
println!("-∞ 转换为整数的值为 {}", c as i32);
// 其它情况,直接舍弃小数,不会进行四舍五入
let d: f64 = 54.5;
let e: f64 = 65.1;
println!("浮点数 {} 转换为整数 {}", d, d as i32);
println!("浮点数 {} 转换为整数 {}", e, e as i32);
代码执行结果:
NAN 转换为整数的值为 0
+∞ 转换为整数的值为 2147483647
-∞ 转换为整数的值为 -2147483648
浮点数 54.5 转换为整数 54
浮点数 65.1 转换为整数 65
5、
整数转换为浮点数时,可能会发生数据浮动
。
-
如果发生数据浮动,将遵循
roundTiesToEven
模式。(数据round到到相邻最近的浮点数据上。如果两个浮点数据都一样近,则round到最后一位是偶数的浮点数据上)
-
如果转换时发生溢出,则将会输出为无穷大(∞)
PS:在数值类型中,溢出仅发生在
u128 as f32
的值大于或者等于
f32::MAX + (0.5 ULP)
时。
示例代码:
let a: i32 = 5;
println!("{} 转为浮点数 {}", a, a as f64);
// 溢出
let b: u128 = u128::MAX;
println!("{} 转为浮点数 {}", b, b as f32);
代码执行结果:
5 转为浮点数 5
340282366920938463463374607431768211455 转为浮点数 inf
6、
f32
浮点数可以完美无损的转换为
f64
浮点数。
示例代码:
let a: f32 = 98.0;
println!("f32浮点数 {} 转为 f64浮点数 {}", a, a as f64);
代码执行结果:
f32浮点数 98 转为 f64浮点数 98
7、
f32浮点数转换f64浮点数时,可能会发生数据浮动。
-
如果发生数据浮动,将遵循
roundTiesToEven
模式。(数据round到到相邻最近的浮点数据上。如果两个浮点数据都一样近,则round到最后一位是偶数的浮点数据上)
-
如果转换时发生溢出,则将会输出为无穷大(∞)
示例代码:
// 数据浮动,注意精度
let a: f64 = 9045.213123;
println!("f64浮点数 {} 转为 f32浮点数 {}", a, a as f32);
// 溢出
let b: f64 = f64::MAX;
println!("f64浮点数 {} 转为 f32浮点数 {}", b, b as f32);
代码执行结果:
f64浮点数 9045.213123 转为 f32浮点数 9045.213
f64浮点数 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 转为 f32浮点数 inf
8、布尔型转为整数型。true
转为整数的值是1
,false
转为整数的值是0
。Rust不允许由整数转为布尔型
示例代码:
let a = false;
let b = true;
println!("{} 转为 整数为 {}", a, a as i32);
println!("{} 转为 整数为 {}", b, b as i32);
代码执行结果:
false 转为 整数为 0
true 转为 整数为 1
9、u8
类型转换为char
类型
- 仅支持
u8
型整数转为char
类型。 char
类型转为整数时,如果整数位数长度不够,则将发生截断,同上面说的第3点
示例代码:
// u8转为char
let a: u8 = 97;
println!("u8型整数 {} 转为 char 为{}", a, a as char);
// char转整数
// 笑脸图标
let b: char = '\u{1F604}';
println!("char型 {} 转为i32的值为:{}, 其二进制为 {:032b}", b, b as i32, b as i32);
println!("char型 {} 转为i16的值为:{}, 其二进制为 {:032b}", b, b as i16, b as i16);
println!("char型 {} 转为i8的值为:{}, 其二进制为 {:032b}", b, b as i8, b as i8);
代码执行结果:
u8型整数 97 转为 char 为a
char型 😄 转为i32的值为:128516, 其二进制为 00000000000000011111011000000100
char型 😄 转为i16的值为:-2556, 其二进制为 00000000000000001111011000000100
char型 😄 转为i8的值为:4, 其二进制为 00000000000000000000000000000100
0x05 小结
我花费一篇文章来讲了Rust中的数值间的类型转换,希望对大家有所帮助。当然as
并不是仅可以应用于数值间的强制类型转换,还有如枚举,指针等等。其她类型的转换后续章节将会介绍。写到这里已经达到3000字了,由于篇幅问题,文章中并没有讲浮点数是如何转为二进制存储的,如果有感兴趣的同学可以查阅下资料。
0x06 参考资料
0x07 本节源码
008 · StudyRust - 码云 - 开源中国 (gitee.com)
下节预告——了解Rust的格式化输出。
<h3 id="rust--学习日记-第8课-类型转换">RUST 学习日记 第8课 ——类型转换</h3><hr><p><img src="https://gitee.com/haoyu3/p
rust中的类型转换rust中的类型转换From与IntoFromIntoTryFrom与TryInto字符串的to与From转换为字符串解析一个字符串
rust中的类型转换
基本类型可以通过显示类型转换机制(as)来实现相互之间的转换。
Rust通过使用trait来处理定制类型(enum、struct)之间的类型转换。
通用的类型转换一般使用的trait为From和To。
然而,对于常见的类型转换场景,有更多具体的trait。
尤其是在处理关于字符串转换的场景。
From与Into
traitFrom和I
一、数据类型系统
任何语言一定会存在两种类型,一种是原生的数据类型,比如常见的整形,双精度啥的;另外一种就是自定义的数据类型,这个就更好理解了,比如自定义的类和结构体等。对于有过C/C++编程经验的人都有过这种经验,比如把short转成int类型,或者把long 转成int类型。在后者的转换过程中,编译器会给一个警告,说会有裁剪导致数据丢失的问题。另外就是指针类型的转换使用reinterpret_cast,其它还有一些类似于static_cast、dynamic_cast等强制类型转换。
类型转换有显示的也
uint8_t *和char*的相互转换以及uint8_t *和int16_t*的相互转换
实际应用需要,实现uint8、int16_t、int32_t的按字节传输,实现发送和接收功能。如int16_t,需要将int16_t转为2字节发送,再接收两个字节解码转回为Int16_t。
intx与char *的转换:
#include <iostream>
using namespace std;
int main()
unsigned char buf...
Rust交叉编译——Windows To Linux
besitor:
Rust语言编程实例100题-039
Blockchain_KT: