mirror of
https://github.com/rust-lang-cn/book-cn.git
synced 2025-02-02 15:28:40 +08:00
doc: Optimize the description at ch08-02
This commit is contained in:
parent
c9c49457d7
commit
fc13f1ae5c
@ -2,19 +2,19 @@
|
|||||||
|
|
||||||
第四章已经讲过一些字符串的内容,不过现在让我们更深入地了解它。字符串是新晋 Rustacean 们通常会被困住的领域,这是由于三方面理由的结合:Rust 倾向于确保暴露出可能的错误,字符串是比很多开发者所想象的要更为复杂的数据结构,以及 UTF-8。所有这些要素结合起来对于来自其他语言背景的开发者就可能显得很困难了。
|
第四章已经讲过一些字符串的内容,不过现在让我们更深入地了解它。字符串是新晋 Rustacean 们通常会被困住的领域,这是由于三方面理由的结合:Rust 倾向于确保暴露出可能的错误,字符串是比很多开发者所想象的要更为复杂的数据结构,以及 UTF-8。所有这些要素结合起来对于来自其他语言背景的开发者就可能显得很困难了。
|
||||||
|
|
||||||
在集合章节中讨论字符串的原因是,字符串就是作为字节的集合外加一些方法实现的,当这些字节被解释为文本时,这些方法提供了实用的功能。在这一部分,我们会讲到 `String` 中那些任何集合类型都有的操作,比如创建、更新和读取。也会讨论 `String` 与其他集合不一样的地方,例如索引` String` 是很复杂的,由于人和计算机理解 `String` 数据方式的不同。
|
在集合章节中讨论字符串的原因是,字符串就是作为字节的集合外加一些方法实现的,当这些字节被解释为文本时,这些方法提供了实用的功能。在这一部分,我们会讲到 `String` 中那些任何集合类型都有的操作,比如创建、更新和读取。也会讨论 `String` 与其他集合不一样的地方,由于人和计算机理解 `String` 数据方式的不同,`String` 索引是非常复杂的。
|
||||||
|
|
||||||
### 什么是字符串?
|
### 什么是字符串?
|
||||||
|
|
||||||
在开始深入这些方面之前,我们需要讨论一下术语 **字符串** 的具体意义。Rust 的核心语言中只有一种字符串类型:`str`,字符串 slice,它通常以被借用的形式出现,`&str`。第四章讲到了 **字符串 slice**:它们是一些储存在别处的 UTF-8 编码字符串数据的引用。比如字符串字面值被储存在程序的二进制输出中,字符串 slice 也是如此。
|
在开始深入这些方面之前,我们需要讨论一下术语 **字符串** 的具体意义。Rust 的核心语言中只有一种字符串类型:`str`,字符串 slice,它通常以被借用的形式出现,`&str`。第四章讲到了 **字符串 slice**:它们是一些储存在别处的 UTF-8 编码字符串数据的引用。比如字符串字面值被储存在程序的二进制输出中,字符串 slice 也是如此。
|
||||||
|
|
||||||
称作 `String` 的类型是由标准库提供的,而没有写进核心语言部分,它是可增长的、可变的、有所有权的、UTF-8 编码的字符串类型。当 Rustacean 们谈到 Rust 的 “字符串”时,它们通常指的是 `String` 和字符串 slice `&str` 类型,而不仅仅是其中之一。虽然本部分内容大多是关于 `String` 的,不过这两个类型在 Rust 标准库中都被广泛使用,`String` 和字符串 slice 都是 UTF-8 编码的。
|
称作 `String` 的类型是由标准库提供的,而没有写进核心语言部分,它是可增长的、可变的、有所有权的、UTF-8 编码的字符串类型。当 Rustacean 们谈到 Rust 的 “字符串”时,它们通常指的是 `String` 和字符串 slice `&str` 类型,而不仅仅是其中之一。虽然本部分内容大多是关于 `String` ,不过这两个类型在 Rust 标准库中都被广泛使用,`String` 和字符串 slice 都是 UTF-8 编码。
|
||||||
|
|
||||||
Rust 标准库中还包含一系列其他字符串类型,比如 `OsString`、`OsStr`、`CString` 和 `CStr`。相关库 crate 甚至会提供更多储存字符串数据的选择。看到这些由 `String` 或是 `Str` 结尾的名字了吗?这对应着它们提供的所有权和可借用的字符串变体,就像是你之前看到的 `String` 和 `str`。举例而言,这些字符串类型能够以不同的编码,或者内存表现形式上以不同的形式,来存储文本内容。本章将不会讨论其他这些字符串类型,更多有关如何使用它们以及各自适合的场景,请参见其API文档。
|
Rust 标准库中还包含一系列其他字符串类型,比如 `OsString`、`OsStr`、`CString` 和 `CStr`。相关库 crate 甚至会提供更多储存字符串数据的选择。看到这些由 `String` 或是 `Str` 结尾的名字了吗?这对应着它们提供的所有权和可借用的字符串变体,就像是你之前看到的 `String` 和 `str`。举例而言,这些字符串类型能够以不同的编码,或者内存表现形式上以不同的形式,来存储文本内容。本章将不会讨论其他这些字符串类型,更多有关如何使用它们以及各自适合的场景,请参见其 API 文档。
|
||||||
|
|
||||||
### 新建字符串
|
### 新建字符串
|
||||||
|
|
||||||
很多 `Vec` 可用的操作在 `String` 中同样可用,从以 `new` 函数创建字符串开始,如示例 8-11 所示。
|
很多 `Vec` 可用的操作在 `String` 中同样可用,从 `new` 函数创建字符串开始,如示例 8-11 所示。
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
@ -45,9 +45,9 @@ let s = String::from("initial contents");
|
|||||||
|
|
||||||
<span class="caption">示例 8-13:使用 `String::from` 函数从字符串字面值创建 `String`</span>
|
<span class="caption">示例 8-13:使用 `String::from` 函数从字符串字面值创建 `String`</span>
|
||||||
|
|
||||||
因为字符串应用广泛,这里有很多不同的用于字符串的通用 API 可供选择。其中一些可能看起来多余,不过都有其用武之地!在这个例子中,`String::from` 和 `.to_string` 最终做了完全相同的工作,所以如何选择就是风格问题了。
|
因为字符串应用广泛,这里有很多不同的用于字符串的通用 API 可供选择。其中一些可能看起来多余,不过都有其用武之地!在这个例子中,`String::from` 和 `to_string` 最终做到了完全相同的事情,所以如何选择,就是风格问题了。
|
||||||
|
|
||||||
记住字符串是 UTF-8 编码的,所以可以包含任何可以正确编码的数据,如示例 8-14 所示。
|
请记住,字符串是 UTF-8 编码的,所以可以包含任何正确编码的数据,如示例 8-14 所示。
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let hello = String::from("السلام عليكم");
|
let hello = String::from("السلام عليكم");
|
||||||
@ -104,7 +104,7 @@ s.push('l');
|
|||||||
|
|
||||||
<span class="caption">示例 8-17:使用 `push` 将一个字符加入 `String` 值中</span>
|
<span class="caption">示例 8-17:使用 `push` 将一个字符加入 `String` 值中</span>
|
||||||
|
|
||||||
执行这些代码之后,`s` 将会包含 “lol”。
|
执行这些代码之后,`s` 将会包含 `lol`。
|
||||||
|
|
||||||
#### 使用 `+` 运算符或 `format!` 宏拼接字符串
|
#### 使用 `+` 运算符或 `format!` 宏拼接字符串
|
||||||
|
|
||||||
@ -128,9 +128,9 @@ fn add(self, s: &str) -> String {
|
|||||||
|
|
||||||
首先,`s2` 使用了 `&`,意味着我们使用第二个字符串的 **引用** 与第一个字符串相加。这是因为 `add` 函数的 `s` 参数:只能将 `&str` 和 `String` 相加,不能将两个 `String` 值相加。不过等一下 —— 正如 `add` 的第二个参数所指定的,`&s2` 的类型是 `&String` 而不是 `&str`。那么为什么示例 8-18 还能编译呢?
|
首先,`s2` 使用了 `&`,意味着我们使用第二个字符串的 **引用** 与第一个字符串相加。这是因为 `add` 函数的 `s` 参数:只能将 `&str` 和 `String` 相加,不能将两个 `String` 值相加。不过等一下 —— 正如 `add` 的第二个参数所指定的,`&s2` 的类型是 `&String` 而不是 `&str`。那么为什么示例 8-18 还能编译呢?
|
||||||
|
|
||||||
之所以能够在 `add` 调用中使用 `&s2` 是因为 `&String` 可以被 **强转**(*coerced*)成 `&str`。当`add`函数被调用时,Rust 使用了一个被称为 **解引用强制转换**(*deref coercion*)的技术,你可以将其理解为它把 `&s2` 变成了 `&s2[..]`。第十五章会更深入的讨论解引用强制转换。因为 `add` 没有获取参数的所有权,所以 `s2` 在这个操作后仍然是有效的 `String`。
|
之所以能够在 `add` 调用中使用 `&s2` 是因为 `&String` 可以被 **强转**(*coerced*)成 `&str`。当 `add` 函数被调用时,Rust 使用了一个被称为 **解引用强制转换**(*deref coercion*)的技术,你可以将其理解为它把 `&s2` 变成了 `&s2[..]`。第十五章会更深入的讨论解引用强制转换。因为 `add` 没有获取参数的所有权,所以 `s2` 在这个操作后仍然是有效的 `String`。
|
||||||
|
|
||||||
其次,可以发现签名中 `add` 获取了 `self` 的所有权,因为 `self` **没有** 使用 `&`。这意味着示例 8-18 中的 `s1` 的所有权将被移动到 `add` 调用中,之后就不再有效。所以虽然 `let s3 = s1 + &s2;` 看起来就像它会复制两个字符串并创建一个新的字符串,而实际上这个语句会获取 `s1` 的所有权,附加上从 `s2` 中拷贝的内容,并返回结果的所有权。换句话说,它看起来好像生成了很多拷贝,不过实际上并没有:这个实现比拷贝要更高效。
|
其次,可以发现签名中 `add` 获取了 `self` 的所有权,因为 `self` **没有** 使用 `&`。这意味着示例 8-18 中的 `s1` 的所有权将被移动到 `add` 调用中,之后就不再有效。虽然 `let s3 = s1 + &s2;` 看起来就像它会复制两个字符串并创建一个新的字符串,而实际上这个语句会获取 `s1` 的所有权,附加上从 `s2` 中拷贝的内容,并返回结果的所有权。换句话说,它看起来好像生成了很多拷贝,不过实际上并没有:这个实现比拷贝要更高效。
|
||||||
|
|
||||||
如果想要级联多个字符串,`+` 的行为就显得笨重了:
|
如果想要级联多个字符串,`+` 的行为就显得笨重了:
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ let s3 = String::from("toe");
|
|||||||
let s = s1 + "-" + &s2 + "-" + &s3;
|
let s = s1 + "-" + &s2 + "-" + &s3;
|
||||||
```
|
```
|
||||||
|
|
||||||
这时 `s` 的内容会是 “tic-tac-toe”。在有这么多 `+` 和 `"` 字符的情况下,很难理解具体发生了什么。对于更为复杂的字符串链接,可以使用 `format!` 宏:
|
这时 `s` 的内容会是 `tic-tac-toe`。在有这么多 `+` 和 `"` 字符的情况下,很难理解具体发生了什么。对于更为复杂的字符串链接,可以使用 `format!` 宏:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let s1 = String::from("tic");
|
let s1 = String::from("tic");
|
||||||
|
Loading…
Reference in New Issue
Block a user