diff --git a/projects/string_demo/Cargo.toml b/projects/string_demo/Cargo.toml index 1fdddff..2638033 100644 --- a/projects/string_demo/Cargo.toml +++ b/projects/string_demo/Cargo.toml @@ -1,8 +1,6 @@ [package] name = "string_demo" version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +edition = "2024" [dependencies] diff --git a/projects/string_demo/src/main.rs b/projects/string_demo/src/main.rs index 1300967..47b48f2 100644 --- a/projects/string_demo/src/main.rs +++ b/projects/string_demo/src/main.rs @@ -1,11 +1,10 @@ fn main() { - let s = "नमस्ते"; + let data = "初始内容"; - for c in s.chars() { - println! ("{}", c); - } + let s = data.to_string(); - for b in s.bytes() { - println! ("{}", b); - } + // 该方法直接在字面值之上也工作 + let s = "初始内容".to_string(); + + println! ("{s}"); } diff --git a/src/common_collections/strings.md b/src/common_collections/strings.md index faa6f31..1b459a1 100644 --- a/src/common_collections/strings.md +++ b/src/common_collections/strings.md @@ -1,69 +1,69 @@ # 以字符串存储 UTF-8 编码的文本 -在第 4 章中,我们曾讨论过字符串,现在我们将对其进行更深入的研究。新的 Rust 公民通常卡在字符串上,原因有三: +我们在第 4 章中讨论过字符串,而现在我们将更深入研究他们。新手 Rustacean 们通常会因为以下三个原因的结合,而在字符串上陷入困境: -- Rust 有暴露可能错误的倾向; -- 字符串是种比许多程序员认为的更复杂的数据结构; +- Rust 暴露可能错误的倾向; +- 字符串属于一种比许多程序员所认为的更复杂的数据结构; - 以及 UTF-8。 -当咱们从其他编程语言转至 Rust 时,这些因素就会以看起来很难的方式,纠缠在一起。 +当咱们来从其他编程语言时,这些因素以一种看似困难的方式结合在一起。 -我们之所以会在集合语境下讨论字符串,是因为字符串是作为字节集合,加上一些在这些字节被解释为文本时,提供有用功能的方法实现的。在本节中,我们将讨论那些 `String` 上的、每种集合类型都有的操作,比如创建、更新及读取等。我们还将讨论 `String` 与其他集合的不同之处,即由于人与计算机在解析 `String` 数据时的差异,而对 `String` 的索引会变得如何复杂。 +我们之所以会在集合的上下文中讨论字符串,是因为字符串是作为字节的集合实现的,加上一些在这些字节被解释为文本时提供有用功能的方法。在这一小节中,我们将讨论 `String` 上的、每种集合类型都有的操作,比如创建、更新及读取等。我们还将讨论 `String` 与其他集合的不同之处,即由于人与计算机在解析 `String` 数据方式上的差异,而怎样导致对 `String` 的索引会变得复杂。 -## 何为字符串? +## 定义字符串 + +我们将首先定义 *字符串* 这一术语的含义。Rust 在核心语言中只有一种字符串类型,即通常以其借用形式 `&str` 看到的字符串切片 `str`。在第 4 章中,我们讨论过 [字符串切片](../ownership/the_slice_type.md#字符串切片),他们属于对存储在别处的一些 UTF-8 编码字符串数据的引用。例如,字符串的字面值存储在程序的二进制文件中,而因此属于字符串切片。 + +所谓 `String` 类型,是由 Rust 的标准库提供而非编码到核心语言中,是一种可增长、可变、被拥有(所有权)、UTF-8 编码的字符串类型。当 Rustacean 们提及 Rust 中的 “字符串” 时,他们可能指的要么是 `String`,或者是字符串切片 `&str` 类型,而不单是这两种类型之一。虽然这一小节主要是有关 `String`,但这两种类型在 Rust 的标准库中都大量使用,并且 `String` 和字符串切片都是 UTF-8 编码的。 -我们将首先定义出所谓 *字符串* 的含义。Rust 的核心语言中,只有一种字符串类型,即通常以其借用形式 `&str` 出现的字符串切片 `str`。在第 4 章我们曾谈到过 [*字符串片切片*](../ownership/the_slice_type.md#字符串切片),他们是对存储在别处的 UTF-8 编码字符串数据的一些引用。例如,字符串的字面值,就存储在程序的二进制文件中,而因此属于一些字符串的切片。 - - -所谓 `String` 类型,则是由 Rust 的标准库提供,而未被编码到核心语言,是种可增长、可变、有所有权、UTF-8 编码的字符串类型。当 Rust 公民提及 Rust 中的 “字符串” 时,他们可能指的是 `String` 或字符串切片的 `&str` 类型,而不单是其中一种类型。虽然本节主要讨论 `String`,但这两种类型在 Rust 的标准库中都有大量使用,同时 `String` 和字符串切片均为 UTF-8 编码的。 - - -## 创建一个新的 `String` - -对 `Vec` 的许多相同操作对 `String` 也可使用,因为 `String` 实际上是作为字节矢量的封装器实现的,不过带有一些额外的保证、限制及功能。`Vec` 和 `String` 下以同一方式工作的函数示例,便是创建出一个实例的 `new` 函数,如下清单 8-11 所示。 +## 创建新的 `String` +由于 `String` 实际上是作为对字节矢量的封装器实现的,并有着一些额外的保证、限制及功能,因此可用于 `Vec` 的许多相同操作也可用于 `String`。一个在 `Vec` 和 `String` 上工作方式相同的函数示例,便是创建实例的 `new` 函数,如下清单 8-11 中所示。 + ```rust let mut s = String::new(); ``` -*清单 8-11:创建一个新的空 `String`* +**清单 8-11**:创建一个新的空 `String` -这行代码会创建出一个名为 `s` 的新空字符串,然后我们就可以向其中加载数据。通常情况下,我们会使用一些咱们开始该字符串的初始数据。为此,我们会使用 `to_string` 方法,该方法适用于任何实现了 `Display` 特质的类型,正如字符串字面量那样。下面清单 8-12 展示了两个示例。 +这行代码创建了个名为 `s` 的新空字符串,随后我们可以加载数据到其中。通常,我们将有一些我们打算以其开始字符串的初始数据。为此,我们会使用 `to_string` 方法,其在任何实现了 `Display` 特质的类型上都可用,字符串字面量便如此。下面清单 8-12 展示了两个示例。 + ```rust let data = "初始内容"; let s = data.to_string(); - // 该方法同样直接工作于字面值之上 + // 该方法直接在字面值之上也工作 let s = "初始内容".to_string(); ``` -*清单 8-12:使用 `to_string` 方法从某个字符串字面值创建出 `String`* +**清单 8-12**:使用 `to_string` 方法从字符串字面值创建 `String` -这段代码会创建出一个包含 `初始内容` 的字符串。 - - -我们还可以使用函数 `String::from`,从某个字符串字面量创建出字符串。下面清单 8-13 中的代码,等同于清单 8-12 中使用 `to_string` 的代码。 +这段代码会创建一个包含 `初始内容` 的字符串。 + +我们还可使用函数 `String::from` 从字符串字面量创建 `String`。下面清单 8-13 中的代码与清单 8-12 中使用 `to_string` 的代码等价。 + ```rust let s = String::from("初始内容"); ``` -*清单 8-13:使用 `String::from` 函数,从某个字符串字面值创建出 `String`* +**清单 8-13**:使用 `String::from` 函数从字符串字面值创建 `String` -由于字符串的用途非常广泛,我们可以使用许多不同的字符串通用 API,从而为我们提供了大量选择。其中有些看起来是多余的,但他们都有自己的用武之地!在这个示例中,`String::from` 和 `to_string` 做的是同一件事,所以咱们选择哪个只是风格与可读性的问题。 +由于字符串的用途非常广泛,我们可以使用许多不同的字符串通用 API,从而提供给我们很多选择。其中一些 API 看似多余,但他们都有他们的用处!在这一情形下,`String::from` 和 `to_string` 完成同一件事,因此咱们选择哪个取决于样式与可读性。 -请记住,字符串是 UTF-8 编码的,因此我们可以在其中包含任何正确编码的数据,如下清单 8-14 所示。 +请记住,字符串都是 UTF-8 编码,因此我们可以在他们中包含任何正确编码的数据,如下清单 8-14 中所示。 + ```rust let hello = String::from("السلام عليكم"); let hello = String::from("Dobrý den"); @@ -79,16 +79,14 @@ let hello = String::from("👋"); ``` -*清单 8-14:以字符串存储不同语言的问候语* +**清单 8-14**:以字符串存储不同语言的问候语 所有这些都是有效的 `String` 值。 ## 更新字符串 -在咱们向某个 `String` 中压入更多数据时,其大小和内容都会发生变化,就像 `Vec` 的内容一样。此外,咱们还可以方便地使用 `+` 运算符或 `format!` 宏,连接多个 `String` 值。 - - +当咱们压入更多数据到 `String` 中时,其大小会增加且其内容会变化,就像 `Vec` 的内容一样。此外,咱们可以方便地使用 `+` 运算符或 `format!` 宏连接 `String` 值。 ### 使用 `push_str` 与 `push` 追加内容到某个 `String`