Rust 切片

发布: (2025年12月23日 GMT+8 10:25)
5 min read
原文: Dev.to

Source: Dev.to

Cover image for Rust Slices

我大多数关于 Rust 的写作都是从 JavaScript/TypeScript 开发者的视角出发的。直观上,当你通过另一种语言学习新语言时,往往会在两者之间建立概念映射。例如,Rust 中的 struct 可以映射到 TypeScript 中的 interface 或 type。这样做可以让你更容易在新语言中吸收知识,因为概念突然变得熟悉。

但这种学习模式会带来一个微妙的问题:一旦你习惯了不断进行概念映射,就会更难真正掌握在新语言中没有直接对应的概念。这正是我在 Rust 中遇到切片(slices)时的障碍。

本文假设读者已经具备 Rust 基础概念的理解,如引用、借用和所有权。

常见的 Rust 模式

在 Rust 中,当编写不需要修改参数的函数时,通常的最佳实践是使用不可变(只读)引用。为了说明这一点,我们来编写一个接受全名并返回仅包含名字的函数。

fn get_first_name(full_name: &str) -> &str {
    full_name
        .split_whitespace()
        .next()
        .unwrap_or("")
}

这段代码在做什么?

  • 该函数借用一个字符串切片(&str);它并不获取所有权。
  • 它按空白字符将字符串拆分成若干单词。
  • 它取出第一个单词(如果有的话)。
  • 如果没有单词,则返回 ""
  • 它返回的是原始字符串的切片,而不是一个新的 String

让我们拆开来看看 😌😉

“返回切片”到底是什么意思?

该函数并没有创建一个新字符串,而是仅仅指向现有字符串的一部分。

如果我们的原始字符串是 "Lex Luthor",一个切片可以指向:

  • "Lex"
  • "Luthor"
  • "thor"
  • "ex Lu"
  • 或者甚至是 "Lex Luthor"(整个字符串)

所有这些都只是对同一底层字符串数据的视图。

JavaScript 心智模型(这有帮助)

如果你来自 JavaScript,脑中可能会直接想到 子串。子串是另一个字符串的一部分,其起始和结束索引都位于原字符串的范围内。如果起始索引是 0,结束索引是 string.length,则该子串代表整个原字符串。

这在概念上也类似于 Rust 中的切片——但有一个重要区别:

切片是引用,而不是新值。 这一点至关重要。

为什么会有切片

如果你已经拥有一个字符串的引用,并且想引用该字符串的一部分,你可以分配一个新字符串并将数据复制进去。这将涉及:

  • 分配新内存
  • 复制字节
  • 做一些你其实不需要的额外工作

Rust 说:为什么不直接引用原始数据的一部分呢? 没有复制,没有新分配,一切仍然快速且明确。这正是切片存在的原因。

切片不仅适用于字符串

切片同样适用于数组,语法看起来非常相似。

对字符串

let original_value = String::from("Hello world");
let slice = &original_value[1..7];

slice 是一个指向 original_value"ello w"&str

对数组

let ages = [13, 21, 37, 4, 55];
let slice = &ages[2..4];

slice 是对数组一部分的引用:[37, 4]

切片的形式为 &original_value[start_index..end_index],其中 start_index 为包含,end_index 为不包含。你也可以省略一个或两个索引:

  • &value[..] → 整个值
  • &value[..3] → 从开头到索引 2(不含 3)
  • &value[3..] → 从索引 3 到结尾

最终感想

Slices 一开始让我感到陌生,因为我一直试图把它们强行套用到熟悉的 JS 概念中。等我不再把它们当作“新值”来思考,而是把它们视为对已有数据的引用时,一切就明白了。

如果你想深入了解,官方的 Rust 书籍对 slices 进行了精彩且更详细的解释,并提供了一个强有力的示例,说明为什么应该使用 slices:

👉

Back to Blog

相关文章

阅读更多 »

适合初学者的 Rust 入门方式

介绍 Rust 是一种强大的语言,但对初学者来说,入门可能会感到不知所措。当我开始学习 Rust 时,我意识到我需要一个简单的、...