在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 > end 或 end > len 时),代码在测试中正常工作,但在生产中引发了“恐慌”,并在高负载时导致了进程意外停止。
故事
在内部并发哈希库中使用了 &mut [T],多个线程同时对同一个数组获取不同的切片。一个线程修改切片,而另一个线程在同一内存中获取另一个切片。程序可以编译,但由于错误的分割,可能会因不安全代码(使用 unsafe)导致未定义行为,如果切片确实重叠。
故事
在系统网络数据包解析器中,以不安全的方式创建了切片(原始指针和 from_raw_parts)。开发人员忘记检查输入数据包的有效长度。结果,在边界之外读取的尝试导致应用程序崩溃并形成漏洞(潜在的越界访问),这可以通过正确使用安全切片来避免。