编程后端开发者

Rust中的切片机制是如何工作的,有哪些切片类型,如何确保安全性,以及尝试越界切片会发生什么?

用 Hintsage AI 助手通过面试

答案

在Rust中,切片是集合部分的动态表示,其元素在内存中是连续的。切片的典型示例是 &[T]&mut [T]。切片不拥有数据,而是引用外部缓冲区。所有切片都有一个与引用一起存储的长度。

主要类型:

  • &[T] — 不可变切片
  • &mut [T] — 可变切片
  • 对于字符串:&str(实际上是字节切片,始终是有效的UTF-8)

切片的安全性是在编译器和运行时级别上保证的:任何尝试访问切片边界之外的元素都会在运行时引发恐慌(panic),不会像C/C++中那样导致不可恢复的内存错误。

示例:

let v = vec![1, 2, 3, 4, 5]; let s: &[i32] = &v[1..4]; // 切片,引用元素2, 3, 4 println!("{:?}", s); // [2, 3, 4] // s[3]; // panic! (越界)

带陷阱的问题

切片可以是空的吗?空切片与 None 有什么区别?

答案: 是的,切片可以是空的(&[]),这意味着指向长度为零的数据部分,但并不等同于 None。空切片是安全使用的,而 Option<&[T]> 用于区分“是否存在切片”。

示例:

let s: &[i32] = &[]; assert!(s.is_empty()); // 如果切片可能根本不存在,则使用 Option<&[i32]>。

由于对主题细节了解不足而导致的真实错误示例


故事

在一个大型日志服务中,程序员根据用户数据动态计算范围来获取切片。在切片计算错误(例如,当 start > endend > len 时),代码在测试中正常工作,但在生产中引发了“恐慌”,并在高负载时导致了进程意外停止。


故事

在内部并发哈希库中使用了 &mut [T],多个线程同时对同一个数组获取不同的切片。一个线程修改切片,而另一个线程在同一内存中获取另一个切片。程序可以编译,但由于错误的分割,可能会因不安全代码(使用 unsafe)导致未定义行为,如果切片确实重叠。


故事

在系统网络数据包解析器中,以不安全的方式创建了切片(原始指针和 from_raw_parts)。开发人员忘记检查输入数据包的有效长度。结果,在边界之外读取的尝试导致应用程序崩溃并形成漏洞(潜在的越界访问),这可以通过正确使用安全切片来避免。