乐趣区

关于rust:Rust基本数据类型

本文介绍 Rust 提供的内置数据类型。

布尔类型

布尔类型 代表“是”和“否”的逻辑值。它有两个值:truefalse,个别用在逻辑表达式中,能够执行“与”、“或”、“非”等运算:

fn main() {
    let x = true;
    let y: bool = !x;    //false,     取反运算
    
    let z = x && y;        //false, 逻辑与运算,带有短路性能
    let z = x || y;        //true, 逻辑或运算,带有短路性能
    let z = x & y;        //false,按位与运算,不带短路性能
    let z = x | y;        //true,按位或运算,不带短路性能
    let z = x ^ y;        //true,按位异或运算,不带短路性能
}

一些比拟运算表达式的类型是布尔类型:

fn logical_op(x: i32, y: i32) {
    let z = x < y;    // z 是布尔类型
    println!("z = {}", z);
}

布尔类型表达式能够用在 if/while 表达式中,作为条件表达式:

if a >= b {...} else {...}

C/C++ 会隐式地将字符、整数、浮点数和指针转换为布尔值;Python 容许在布尔值上下文中应用字符串、列表、字典、汇合。对于它们来说,如果这些值不为 0 或空,就将它们视为 true。相对而言,Rust 更加严格:if/while 表达式的条件必须是布尔类型表达式。

Rust 的 as 操作符能够把 bool 值显式地转换为整数类型:

assert_eq!(false as i32, 0);
assert_eq!(true as i32, 1);

然而,不能将数值类型转换为布尔类型,这种状况下必须进行显式转换:

let x = 0;
let y = 1;
assert_eq!(x as bool, false);    // 谬误,不容许应用 as 将数值类型转换为布尔类型
assert_eq!(y as bool, true);    // 谬误,不容许应用 as 将数值类型转换为布尔类型

// 必须应用显式比拟
if x == 0 {...}
if y == 1 {...}

实践上来讲,一个布尔类型仅仅须要一个比特位即可示意,然而 Rust 在内存中应用整整一个字节作为 bool 值,因而容许创立一个指向布尔值的指针。

字符类型

Rust 的字符类型 char 应用 4 个字节的内存空间来保留单个 unicode 码点。在代码中,单个字符字面量应用一对单引号突围:

let love = '❤' // 能够间接嵌入任何 Unicode 字符

字符字面量中能够应用本义符:

let c1 = '\n';          // 换行符
let c2 = '\u{7FFF}'; //Unicode 字符

依据 Unicode 字符的规范,char类型保留的码点范畴在 [0x0000,0xD7FF]U[0xE000,0x10FFFF] 之中。Rust 的类型零碎会进行动静查看,保障 char 的值始终在上述非法范畴当中。

Rust 从来不会隐式地在 char 与其余类型之间进行转换。如果有须要,能够应用 as 操作符将 char 类型转换为数值类型。如果指标数值类型的大小有余 4 个字节,字符的高位内存会被截断:

assert_eq!('*' as i32, 42);
assert_eq!('😻' as i32, 128571);
assert_eq!('😻' as i8, 59);    // 高位字节被截断

出其不意的是,as操作符只能将 u8 类型转换为 char 类型,这是因为任何其余数值类型都有可能会产生非法的 unicode 码点,这样就会导致运行时的字符值查看。不过,规范库的函数 std::char::from_u32() 能够将 u32 值转换为 Option<char> 值,从而确保了正确性。

除此之外,规范库也为字符类型提供了罕用的工具函数,例如:

assert_eq!('*'.is_alphabetic(), false);
assert_eq!('b'.is_alphabetic(), true);
assert_eq!('8'.to_digit(), Some(8));
assert_eq!(std::char::from_digit(2, 10), Some('2'));

整数类型

与其它大多数编程语言的整数类型雷同,Rust 整数类型是一组固定大小的类型,与古代 CPU 硬件里间接实现的类型对应。Rust 数值类型的命名遵循一种法则,即:同时写出位宽以及表现形式:

字节数 无符号整数 有符号整数
1 u8 i8
2 u16 i16
4 u32 i32
8 u64 i64
机器相干 usize isize

Rust 的整数类型应用补码示意。如果一个变量是有符号类型,那么它的最高位就是符号位,用来辨别这个值是负数还是正数;如果一个变量是无符号类型,那么它的最高位和其它位一样,都用来示意数据。

须要特地留神的是 usizeisize类型,它们占据的内存空间是不确定的,与程序所执行的平台相干。如果在 32 位零碎上,就应用四个字节;如果在 64 位零碎上,就应用八个字节。

整数值的字面量能够有许多的示意形式:

let var1: i32 = 32;        // 十进制
let var2: i32 = 0xFF;    // 十六进制
let var3: i32 = 0o55;    // 八进制
let var4: i32 = 0b1001;    // 二进制

字面量能够在任意的中央增加下划线,从而进步可读性。例如:

let var5 = 0x_1234_ABCD;    

此外,如果不指定整数字面量的类型,则默认应用 i32 类型;如果心愿显式地制订类型,能够在字面量的开端增加后缀:

let var8 = 32;            // 不写类型,默认是 i32
let var6 = 123usize;    //i6 是 usize 类型
let var7 = 0x_ff_u8;    //var7 是 u8 类型

u8值有点非凡,因为它能够示意十分罕用的 ASCII 字符,Rust 为此专门提供了 字节字面量

let a = b'A';    //u8,示意字符 A,也就是 65

字节字面量同样能够应用本义符:

let b = b'\\';    //u8,示意字符 \,也就是 92
let c = b'\n';    //u8,示意换行符,也就是 10
let d = b'\t';  //u8,示意制表符,也就是 9 

不同的整数类型之间能够应用 as 操作符进行类型转换。例如:

assert_eq!(10_i8 as u16, 10_u16);    // 对于负数,由小到大时在高位填充 0,正确。assert_eq!(10_i8 as u16, 10_u16);    // 对于负数,由小到大时在高位填充 0,正确。assert_eq!(-1i16 as i32, -1_i32);    // 对于正数,由小到大时在高位填充 1,正确。assert_eq!(1000_i16 as u8, 232_u8);        // 产生类型截断,高位数据被抛弃。assert_eq!(65535_u32 as i16, -1_i16);    // 产生类型截断,高位数据被抛弃。

Rust 整数类型运算的形式与其余语言有所不同。在整数的算术运算中,有一个比拟头疼的事件是“溢出”。在 C 语言中,无符号类型的算术运算永远不会产生溢出,如果超出了示意范畴,则主动舍弃高位数据;对于有符号类型的算术运算,溢出后的行为是未定义的。

未定义行为有利于编译器做出一些激进的性能优化,然而有可能在极其状况下产生诡异的 BUG。Rust 的设计思路更偏向于预防 BUG,而不是无条件地压迫效率。因而,Rust 在这个问题上的解决形式为:默认状况下,debug 模式编译时编译器会增加额定的代码来查看溢出,一旦产生了溢出,就会引发 panic;在 release 模式编译时,编译器不会查看整数溢出,而是采纳舍弃高位的形式。 与此同时,编译器还提供了一个独立的编译选项,用来手动设置溢出时的解决策略:overflow-checks=yes/no

如果须要更精密地自主管制整数溢出的行为,能够调用规范库中的 check_*saturating_*wrapping_* 系列函数,其中:

  • checked_*系列函数返回的类型是Option<_>,当呈现溢出时,返回的值是None
  • saturating_*系列函数返回的类型是整数,当呈现溢出时,返回的值是该类型可示意范畴的最大或最小值。
  • wrapping_*系列函数间接进行截断。

当安全性十分重要时,应该尽量应用这几个办法来代替默认的算术运算符:

fn main() {
    let i = 100i8;
    println!("checked: {:?}", i.checked_add(i));        //None
    println!("saturating {:?}", i.saturating_add(i));    //127
    println!("wrapping: {:?}", i.wrapping_add(i));        //-56
}

浮点类型

Rust 反对 IEEE 规定的单、双精度浮点类型,遵循 IEEE 754-2008 规范。这些类型蕴含正、负无穷,辨别正、负零,还有一个非数值的值:

类型 精度 范畴
f32 IEEE 单精度(至多 6 位小数) $$(-3.4\times10^{38},3.4\times10^{38})$$
f64 IEEE 双精度(至多 15 位小数) $$(-1.8\times10^{308},1.8\times10^{308})$$

与整数类型雷同,能够应用后缀 f32f64来显式地制订字面量的类型。

Rust 规范库为 IEEE 定义的浮点数非凡值定义了常量,比方 INFINITYNEG_INFINITYNAN,以及MINMAX等。同时,规范库中也为两种精度的浮点数类型都定义了罕用的数学函数:

fn main() {assert_eq!(5f32.sqrt() * 5f32.sqrt(), 5.0);
    assert_eq!(-1.01f64.floor(), -1.0);
    assert!((-1.0 / std::f32::INFINITY).is_sign_negative());
}

此外,Rust 不承受整数类型到浮点类型的主动类型转换。

退出移动版