- 作者:老汪软件技巧
- 发表时间:2024-09-15 15:01
- 浏览量:
在 Rust 这门强大而独特的编程语言中,基本类型是构建程序的基石。它们不仅定义了数据的存储和表达方式,还赋予了 Rust 语言在性能、安全性和表达力方面的卓越特性。
一、基本类型
Rust 的基本类型,包括数字类型、布尔类型、字符类型、元组类型、数组、字符串、指针、单元类型等,为编程提供了强大的基础。
数字类型:
布尔类型:只有两个可能值 true 和 false,占用一个字节。
字符类型:表示单个 Unicode 字符,存储为 4 个字节。
元组类型:元组是两个、或三个、四个、五个、⋯⋯不同类型的值的组合。例如,("Brazil", 1985) 是一个元组,类型是(&str, i32)。通过t.0、t.1、⋯⋯来访问它的元素。
数组类型:类型[T; N] 表示一个有N 个元素的数组,每个元素的类型都是T。长度必须在编译期已知,不能添加新元素或者缩减元素。
vector类型:类型Vec,是类型T 的向量。动态分配、可增长的类型T 的值的序列。存储在堆中,按需更改大小:可以添加新的元素、附加其它vector、删除元素等。。
切片类型:类型&[T] 和&mut [T] 分别是类型T 的共享切片和可变切片,是数组或vector 等其它值中的一部分元素的引用。可以把切片当做一个指向第一个元素的指针再加上一个可访问的元素数量。
字符串:字符串字面量和字符串切片 &str及String类型。let str = "hello, world!";
指针类型:用来表示内存地址的类型,包括引用、智能指针、原始指针等;例如: let ptr = ∫let box = Box::new(1);
单元类型:即 (),其唯一的值也是 ()。主要用于表示函数没有返回值的情况,与元组不同,元组可以包含多个不同类型的值,而单元类型没有任何值。
二、数字类型(一)整数类型
1.无符号整数包括正数和0;u8、u16、u32、u64、u128、usize等;范围[0, 2^n - 1];其中usize依赖运行程序的计算机架构,在 64 位架构上是 64 位,在 32 位架构上是 32 位的;
2.有符号整数包括正数、负数和0; i8、i16、i32、i64、i128、isize等;范围[-2^(n-1), 2^(n-1) - 1];其中isize依赖运行程序的计算机架构,在 64 位架构上是 64 位,在 32 位架构上是 32 位的;
表示方式:
(二)浮点类型
Rust 提供IEEE 的单精度和双精度浮点数。这两个类型还包括正无穷、负无穷、正0、负0 和非数值。
整数部分之后的部分都是可选的,但小数部分、指数、或者类型后缀至少需要有一个,才能和整数字面量区分开。小数部分可以只有一个单独的小数点,因此5. 是一个有效的浮点数。
f32 和f64 类型还关联了IEEE 要求的特殊常量值例如INFINITY、NEG_INFINITY(负无穷)、NAN(非数值)、MIN 和MAX(最小和最大的有限值):
三、布尔类型
Rust 的布尔类型bool 只有两个值:true 和false。比较运算符例如== 和< 会产生bool 类型的结果:2 < 5 的结果是true。
Rust 非常严格:像if 和while 这样的控制流的条件必须是bool 表达式,短路求值运算符&& 和|| 也是这样。不能是其他非空的类型;
四、字符类型
Rust 的字符类型char 代表一个单独的Unicode 字符,是一个32 位的值。
Rust 使用char 表示单个字符,但使用UTF-8 编码字符串和文本流。因此,String 表示的文本是一个UTF-8 字节序列,而不是字符的数组。
五、元组类型
元组是一种可以组合不同类型值的数据结构,长度固定。可作为函数返回值来返回多个值;
字面量("lonely hearts",) 是一个包含单个字符串的元组,类型是(&str,)。最后的逗号是必须的,为了和单纯的用括号把表达式括起来相区分。
六、数组、vector 和切片
Rust 有三种表示一系列值的类型:
(一)数组类型
类型[T; N] 表示一个有N 个T类型元素的数组,每个数组的长度必须在编译期已知,不能添加新元素或者缩减元素。
表示方式:
let lazy_caterer: [u32; 6] = [1, 2, 4, 7, 11, 16];
let taxonomy = ["Animalia", "Arthropoda", "Insecta"];
let mut sieve = [true; 10000];
(二)vector类型
类型Vec,是类型T 的向量。一个Vec 是一个长度可变的类型T 的数组,它的元素都存储在堆上。
表示方式:
let mut primes = vec![2, 3, 5, 7];
let mut pal = Vec::new();
let v: Vec<i32> = (0..5).collect();
(三)切片类型
切片写作[T],没有长度。它表示数组或vector 的一部分。因为切片可以是任意长度,因此切片不能直接存储在变量中或者作为参数传递。切片必须通过引用传递。
切片的引用是胖指针:包含指向切片中第一个元素的指针和切片中元素数量的双字值。
类型&[T] 和&mut [T] 分别是类型T 的共享切片和可变切片,&mut [T] 让你可以读取并修改元素,但不能被共享;共享的切片&[T] 允许你在多个读者间共享数据,但不能修改元素。
表示方式:
let v: Vec<f64> = vec![0.0, 0.707, 1.0, 0.707];
let a: [f64; 4] = [0.0,-0.707,-1.0,-0.707];
let sv: &[f64] = &v;
let sa: &[f64] = &a;
七、字符串类型
Rust 中有两种主要的字符串类型:不可修改的 &str 和可增长、可改变的 String 类型。&str 是字符串切片,通常指向一个已存在的字符串数据,它是不可变的。String 类型是可变的字符串,拥有自己的内存空间,可以进行增长和修改操作。
一个&str (读作“stir”或者“字符串切片”)是一个指向其他值拥有的UTF-8 文本的引用,&str 是一种胖指针,包括实际数据的地址和长度。
String 类似于Vec,个String 都有它自己的在堆上分配的缓冲区,这个缓冲区不和其他任何String 共享。
Rust 的字符串不能像某些语言那样通过下标直接访问单个字符。如果想要访问字符串的部分内容,可以使用切片的方法。例如,let s = "Hello, Rust!"; let slice = &s[0..5];,这里创建了一个指向原始字符串中从索引 0 到索引 5(不包括 5)的切片。
表示方式:
let s = "Hello, Rust!".to_string();
let s_slice = &s[0..5];println!("{}", s_slice);
八、指针类型(一)引用
Rust 中的引用分为不可变引用和可变引用,它们是安全的指针类型。不可变引用允许对底层数据进行只读访问,而可变引用则允许对底层数据进行修改。引用不会转移所有权,并且在引用离开作用域后,其指向的值也不会被丢弃。
一个&String(读作“ref String”)类型的值是一个String 值的引用,一个&i32 类型的值是一个i32 值的引用,等等。
在运行时,一个i32 的引用&i32,是一个单独的机器字,里面存储的是指向的i32 值的地址,可能在栈上也可能在堆上。
(二)智能指针
Rust 中有多种智能指针,如Box、Rc等,它们具备额外的元数据和功能。
Box:用于在堆上分配数据,当Box离开作用域时,它会自动释放所包含的数据。
表示方式:
let heap_allocated_i32 = Box::new(1);
struct LargeData { data: [i32; 1000000],}
fn main() {
let boxed_data = Box::new(LargeData {
data: [0; 1000000],
});
}
Rc:用于实现多所有权,通过引用计数来管理数据的生命周期。当引用计数为零时,数据将被释放。
表示方式:
use std::rc::Rc;
#[derive(Debug)]
struct Person { name: String, age: u32,}
fn main() {
let person1 = Rc::new(Person { name: "Alice".to_string(), age: 25, });
let person2 = Rc::clone(&person1); let person3 = Rc::clone(&person1);
println!("姓名:{},年龄:{}", person1.name, person1.age);
println!("名称:{},年龄:{}", person2.name, person2.age);
println!("姓名:{},年龄:{}", person3.name, person3.age);
println!("参考计数:{}", Rc::strong_count(&person1));
}
(三)原始指针
Rust 原始指针类型:mut T 和const T。原始指针类似于C++ 中的指针。
使用原始指针是不安全的,需在unsafe块中解引用。
原始指针分为不可变原始指针const T和可变原始指针mut T。不可变原始指针指向的数据不可被修改,而可变原始指针指向的数据可以被修改。
表示方式:
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe {
// *r1 = 1; // 编译错误,r1 是不可变原始指针,不能修改指向的数据
*r2 = 1;
}
println!("num={:?}", num);
九、单元类型
单元类型即 (),它唯一的值也是 ()。主要用于表示函数没有返回值的情况。比如在一些不需要返回任何有意义值的函数中,可以使用单元类型来明确表示函数的返回类型。
表示方式:
fn no_return() -> () {
println!("This function returns nothing.");
}
let result = no_return();
println!("Result of no_return function: {:?}", result);