Rust-数组

数组是一个容器,它在一块连续空间内存中,存储了一系列的同样类型的数据。

数组中元素的占用空间大小必须是编译期确定的。

数组本身所容纳的元素个数也必须是编译期确定的,执行阶段不可变。

如果需要使用变长的容器,可以使用标准库中的Vec/LinkedList等。数组类型的表示方式为[T;n]。

其中T代表元素类型;n代表元素个数;它必须是编译期常量整数;中间用分号隔开。

下面看一个基本的示例:

多维数组

既然[T;n]是一个合法的类型,那么它的元素T当然也可以是数组类型,因此[[T;m];n]类型自然也是合法类型。示例如下:

数组切片

对数组取借用borrow操作,可以生成一个"数组切片"(Slice)。

数组切片对数组没有"所有权",我们可以把数组切片看作专门用于指向数组的指针,是对数组的另外一个"视图"。

比如,我们有一个数组[T;n],它的借用指针的类型就是&[T;n]。

它可以通过编译器内部魔法转换为数组切片类型&[T]。

数组切片实质上还是指针,它不过是在类型系统中丢弃了编译阶段定长数组类型的长度信息,而将此长度信息存储为运行期的值。示例如下:

DST和胖指针

从前面的示例中可以看到,数组切片是指向一个数组的指针,而它比指针又多了一点东西------它不止包含有一个指向数组的指针,切片本身还含带长度信息。

Slice与普通的指针是不同的,它有一个非常形象的名字:胖指针(fat pointer)。

与这个概念相对应的概念是"动态大小类型"(Dynamic Sized Type,DST)。

所谓的DST指的是编译阶段无法确定占用空间大小的类型。为了安全性,指向DST的指针一般是胖指针。

比如:对于不定长数组类型[T],有对应的胖指针&[T]类型;对于不定长字符串str类型,有对应的胖指针αstr类型;以及在后文中会出现的Trait Object;等等。

由于不定长数组类型[T]在编译阶段是无法判断该类型占用空间的大小的,目前我们不能在栈上声明一个不定长大小数组的变量实例,也不能用它作为函数的参数、返回值。

但是,指向不定长数组的胖指针的大小是确定的,&[T]类型可以用做变量实例、函数参数、返回值。

通过前面的示例我们可以看到,&[T]类型占用了两个指针大小的内存空间。

Range

Rust中的Range代表一个"区间",一个"范围",它有内置的语法支持,就是两个小数点...。示例如下:

边界检查

在前面的示例中,我们的"索引"都是一个合法的值,没有超过数组的长度。如果我们给"索引"一个非法的值会怎样呢:

编译通过,执行thread'main'panicked at index out of bounds:the len is 5 but the index is10'。

可以看出,如果用/test10,则会出现数组越界,Rust目前还无法任意索引执行编译阶段边界检查,但是在运行阶段执行了边界检查。下面我们分析一下边界检查背后的故事。

在Rust中,"索引"操作也是一个通用的运算符,是可以自行扩展的。

如果希望某个类型可以执行"索引"读操作,就需要该类型实现std::ops::Index trait,如果希望某个类型可以执行"索引"写操作,就需要该类型实现std::ops::IndexMut trait。

对于数组类型,如果使用usize作为索引类型执行读取操作,实际执行的是标准库中的以下代码:

字符串

字符串是非常重要的常见类型。相比其他很多语言,Rust的字符串显得有点复杂,主要是跟所有权有关。Rust的字符串涉及两种类型,一种是&str,另外一种是string。

&str

str是Rust的内置类型。&str是对str的借用。Rust的字符串内部默认是使用utf-8编码格式的。而内置的char类型是4字节长度的,存储的内容是Unicode Scalar Value。

所以,Rust里面的字符串不能视为char类型的数组,而更接近u8类型的数组。

实际上str类型有一种方法:fn as_ptr(&self)->*const u8。

它内部无须做任何计算,只需做一个强制类型转换即可。

String

接下来讲string类型。它跟&str类型的主要区别是,它有管理内存空间的权力。

关于"所有权"和"借用"的关系,&str类型是对一块字符串区间的借用,它对所指向的内存空间没有所有权,哪怕&mut str也一样。比如:

let greeting:&str ="Hello";

我们没办法扩大greeting所引用的范围,在它后面增加内容。但是string类型可以。示例如下:

相关推荐
怒放吧德德2 小时前
Netty 4.2 入门指南:从概念到第一个程序
java·后端·netty
雨中飘荡的记忆4 小时前
大流量下库存扣减的数据库瓶颈:Redis分片缓存解决方案
java·redis·后端
心之语歌6 小时前
基于注解+拦截器的API动态路由实现方案
java·后端
华仔啊7 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang7 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构
Ray Liang9 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Java水解9 小时前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
蚂蚁背大象10 小时前
Rust 所有权系统是为了解决什么问题
后端·rust
布列瑟农的星空11 小时前
前端都能看懂的rust入门教程(五)—— 所有权
rust
SimonKing13 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员