Rust 学习笔记 07:Slice 类型

“Slice and dice your data safely.”

在 Go 语言中,Slice (切片) 是一个非常核心的概念,它底层是一个结构体 (ptr, len, cap)。 在 Rust 中,Slice 也是类似的,但它有一个本质的区别:Rust 的 Slice 是一种引用(Borrowed Type)

它不拥有数据,它只是借用了数据的一部分。

1. 字符串切片 (String Slices)

假设我们有一个字符串 s

1let s = String::from("hello world");

我们可以创建一个切片,指向它的一部分:

1let hello = &s[0..5]; // 指向 0,1,2,3,4
2let world = &s[6..11];

注意那个 & 符号,说明 hello 是一个引用。 它的类型是 &str(读作 “string slice”)。它内部包含两个字段:

  1. 指向数据的指针 (ptr)
  2. 切片的长度 (len)

这和 Go 的 Slice 结构几乎一样,只是少了容量 (cap),且必须依附于原字符串存在。

2. 切片与所有权

既然 Slice 是引用,它就受借用规则的约束。

1let mut s = String::from("hello world");
2let word = first_word(&s); // word 借用了 s
3
4s.clear(); // 错误!试图获取可变引用来修改 s
5// 但 s 已经被 immutable borrow (借给 word) 了。
6
7println!("the first word is: {}", word);

编译器会阻止我们在切片依然有效时,去修改原数据。这避免了悬垂引用(dangling pointer),即切片指向了无效内存。

3. 都可以是 Slice

有没有发现,函数的参数如果定义为 &str,它既能接收 String 的切片,也能接收字符串字面量?

1fn first_word(s: &str) -> &str { ... }
2
3let s = String::from("Hello");
4first_word(&s); // 传 String 的引用(自动强转为 slice)
5first_word(&s[..]); // 传全切片
6
7first_word("Hello"); // 传字面量(字面量本身就是 &str)

所以,在定义函数参数时,能用 &str 就尽量用 &str,而不是 &String。这会让函数更通用。

4. 数组切片

除了字符串,普通数组也可以切片。

1let a = [1, 2, 3, 4, 5];
2let slice = &a[1..3]; // 类型是 &[i32]

用法和字符串切片完全一样。

5. 小结

第七篇笔记,我们补全了 Rust 引用体系的重要一环 —— Slice。

  • Slice 是不持有所有权的引用。
  • &str 是字符串切片,比 &String 更轻量、更通用。
  • Slice 让你安全地访问集合的一部分,且不用担心内存安全(编译器看着呢)。

至此,Rust 的"所有权三部曲"(所有权、借用、切片)终于讲完了。 这三座大山翻过去之后,接下来的内容(结构体、枚举)对 Go 开发者来说就亲切多了。

下一篇,我们将学习 结构体 (Structs)。你会发现 Rust 的 Struct 和 Go 的很像,但也有一些奇怪的变体(比如元组结构体)。


练习题

  1. 编写一个函数,接收一个整数数组切片 &[i32],返回其中最大的元素。
  2. 尝试使用切片操作中文子串,例如 "你好世界"[0..1],看看会发生什么?(提示:UTF-8 编码)。

思考题

Go 的 Slice 可以动态扩容(append),Rust 的 Slice (&[T]) 可以扩容吗?为什么?如果想用可变长度的数组,应该用什么类型?


本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读