mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 06:17:49 +00:00
Compare commits
5 Commits
8fac34760c
...
b2e12433b9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2e12433b9 | ||
|
|
1ba06fe61c | ||
|
|
bae61dd786 | ||
|
|
13cdacd6df | ||
|
|
624f0b7663 |
@@ -58,12 +58,12 @@ translators = ["ZAAFHachemrachid"]
|
||||
[`no_std` attribute]: https://doc.rust-lang.org/1.30.0/book/first-edition/using-rust-without-the-standard-library.html
|
||||
|
||||
```
|
||||
cargo new blog_os --bin --edition 2018
|
||||
cargo new blog_os --bin --edition 2024
|
||||
```
|
||||
|
||||
لقد أطلقتُ على المشروع اسم ”Blog_os“، ولكن بالطبع يمكنك اختيار اسمك الخاص. تُحدّد علامة ”bin“ أننا نريد إنشاء نسخة binary قابلة للتنفيذ (على عكس المكتبة) وتحدّد علامة ”--- Edition 2018“ أننا نريد استخدام [2018 edition] من Rust لصندوقنا. عندما نُشغّل الأمر، تُنشئ لنا الشحنة بنية الدليل التالية:
|
||||
لقد أطلقتُ على المشروع اسم ”Blog_os“، ولكن بالطبع يمكنك اختيار اسمك الخاص. تُحدّد علامة ”bin“ أننا نريد إنشاء نسخة binary قابلة للتنفيذ (على عكس المكتبة) وتحدّد علامة ”--- Edition 2024“ أننا نريد استخدام [2024 edition] من Rust لصندوقنا. عندما نُشغّل الأمر، تُنشئ لنا الشحنة بنية الدليل التالية:
|
||||
|
||||
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[2024 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```
|
||||
blog_os
|
||||
|
||||
@@ -56,12 +56,12 @@ Comenzamos creando un nuevo proyecto de aplicación en Cargo. La forma más fác
|
||||
|
||||
|
||||
```
|
||||
cargo new blog_os --bin --edition 2018
|
||||
cargo new blog_os --bin --edition 2024
|
||||
```
|
||||
|
||||
Nombré el proyecto `blog_os`, pero, por supuesto, puedes elegir tu propio nombre. La bandera `--bin` especifica que queremos crear un binario ejecutable (en contraste con una biblioteca), y la bandera `--edition 2018` indica que queremos usar la [edición 2018] de Rust para nuestro crate. Al ejecutar el comando, Cargo crea la siguiente estructura de directorios para nosotros:
|
||||
Nombré el proyecto `blog_os`, pero, por supuesto, puedes elegir tu propio nombre. La bandera `--bin` especifica que queremos crear un binario ejecutable (en contraste con una biblioteca), y la bandera `--edition 2024` indica que queremos usar la [edición 2024] de Rust para nuestro crate. Al ejecutar el comando, Cargo crea la siguiente estructura de directorios para nosotros:
|
||||
|
||||
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[2024 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```
|
||||
blog_os
|
||||
|
||||
@@ -57,12 +57,12 @@ rtl = true
|
||||
با ساخت یک اپلیکیشن جدید کارگو شروع میکنیم. سادهترین راه برای انجام این کار از طریق خط فرمان است:
|
||||
|
||||
```
|
||||
cargo new blog_os --bin --edition 2018
|
||||
cargo new blog_os --bin --edition 2024
|
||||
```
|
||||
|
||||
نام پروژه را `blog_os` گذاشتم، اما شما میتوانید نام دلخواه خود را انتخاب کنید. پرچمِ (ترجمه: Flag) `bin--` مشخص میکند که ما میخواهیم یک فایل اجرایی ایجاد کنیم (به جای یک کتابخانه) و پرچمِ `edition 2018--` مشخص میکند که میخواهیم از [ویرایش 2018] زبان راست برای کریت خود استفاده کنیم. وقتی دستور را اجرا میکنیم، کارگو ساختار پوشههای زیر را برای ما ایجاد میکند:
|
||||
نام پروژه را `blog_os` گذاشتم، اما شما میتوانید نام دلخواه خود را انتخاب کنید. پرچمِ (ترجمه: Flag) `bin--` مشخص میکند که ما میخواهیم یک فایل اجرایی ایجاد کنیم (به جای یک کتابخانه) و پرچمِ `edition 2024--` مشخص میکند که میخواهیم از [ویرایش 2024] زبان راست برای کریت خود استفاده کنیم. وقتی دستور را اجرا میکنیم، کارگو ساختار پوشههای زیر را برای ما ایجاد میکند:
|
||||
|
||||
[ویرایش 2018]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[ویرایش 2024]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```
|
||||
blog_os
|
||||
|
||||
@@ -54,12 +54,12 @@ Par défaut, toutes les crates Rust sont liées à la bibliothèque standard, qu
|
||||
Nous commençons par créer un nouveau projet d'application cargo. La manière la plus simple de faire est avec la ligne de commande :
|
||||
|
||||
```
|
||||
cargo new blog_os --bin --edition 2018
|
||||
cargo new blog_os --bin --edition 2024
|
||||
```
|
||||
|
||||
J'ai nommé le projet `blog_os`, mais vous pouvez évidemment choisir le nom qu'il vous convient. Le flag `--bin` indique que nous voulons créer un exécutable (contrairement à une bibliothèque) et le flag `--edition 2018` indique que nous voulons utiliser l'[édition 2018] de Rust pour notre crate. Quand nous lançons la commande, cargo crée la structure de répertoire suivante pour nous :
|
||||
J'ai nommé le projet `blog_os`, mais vous pouvez évidemment choisir le nom qu'il vous convient. Le flag `--bin` indique que nous voulons créer un exécutable (contrairement à une bibliothèque) et le flag `--edition 2024` indique que nous voulons utiliser l'[édition 2024] de Rust pour notre crate. Quand nous lançons la commande, cargo crée la structure de répertoire suivante pour nous :
|
||||
|
||||
[édition 2018]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[édition 2024]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```
|
||||
blog_os
|
||||
|
||||
@@ -57,12 +57,12 @@ Rust で OS カーネルを書くには、基盤となる OS なしで動く実
|
||||
新しい Cargo プロジェクトをつくるところから始めましょう。もっとも簡単なやり方はコマンドラインで以下を実行することです。
|
||||
|
||||
```bash
|
||||
cargo new blog_os --bin --edition 2018
|
||||
cargo new blog_os --bin --edition 2024
|
||||
```
|
||||
|
||||
プロジェクト名を `blog_os` としましたが、もちろんお好きな名前をつけていただいても大丈夫です。`--bin`フラグは実行可能バイナリを作成することを、 `--edition 2018` は[2018エディション][2018 edition]を使用することを明示的に指定します。コマンドを実行すると、 Cargoは以下のようなディレクトリ構造を作成します:
|
||||
プロジェクト名を `blog_os` としましたが、もちろんお好きな名前をつけていただいても大丈夫です。`--bin`フラグは実行可能バイナリを作成することを、 `--edition 2024` は[2024エディション][2024 edition]を使用することを明示的に指定します。コマンドを実行すると、 Cargoは以下のようなディレクトリ構造を作成します:
|
||||
|
||||
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[2024 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```bash
|
||||
blog_os
|
||||
|
||||
@@ -58,13 +58,13 @@ Rust로 운영체제 커널을 작성하려면, 운영체제 없이도 실행가
|
||||
제일 먼저 아래의 명령어를 통해 새로운 cargo 애플리케이션 크레이트를 만듭니다.
|
||||
|
||||
```
|
||||
cargo new blog_os --bin --edition 2018
|
||||
cargo new blog_os --bin --edition 2024
|
||||
```
|
||||
|
||||
프로젝트 이름은 `blog_os` 또는 원하시는 이름으로 정해주세요. `--bin` 인자는 우리가 cargo에게 실행 파일 (라이브러리와 대조됨)을 만들겠다고 알려주고, `--edition 2018` 인자는 cargo에게 우리가 [Rust 2018 에디션][2018 edition]을 사용할 것이라고 알려줍니다.
|
||||
프로젝트 이름은 `blog_os` 또는 원하시는 이름으로 정해주세요. `--bin` 인자는 우리가 cargo에게 실행 파일 (라이브러리와 대조됨)을 만들겠다고 알려주고, `--edition 2024` 인자는 cargo에게 우리가 [Rust 2024 에디션][2024 edition]을 사용할 것이라고 알려줍니다.
|
||||
위 명령어를 실행하고 나면, cargo가 아래와 같은 크레이트 디렉토리를 만들어줍니다.
|
||||
|
||||
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[2024 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```
|
||||
blog_os
|
||||
|
||||
@@ -55,12 +55,12 @@ By default, all Rust crates link the [standard library], which depends on the op
|
||||
We start by creating a new cargo application project. The easiest way to do this is through the command line:
|
||||
|
||||
```
|
||||
cargo new blog_os --bin --edition 2018
|
||||
cargo new blog_os --bin --edition 2024
|
||||
```
|
||||
|
||||
I named the project `blog_os`, but of course you can choose your own name. The `--bin` flag specifies that we want to create an executable binary (in contrast to a library) and the `--edition 2018` flag specifies that we want to use the [2018 edition] of Rust for our crate. When we run the command, cargo creates the following directory structure for us:
|
||||
I named the project `blog_os`, but of course you can choose your own name. The `--bin` flag specifies that we want to create an executable binary (in contrast to a library) and the `--edition 2024` flag specifies that we want to use the [2024 edition] of Rust for our crate. When we run the command, cargo creates the following directory structure for us:
|
||||
|
||||
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[2024 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```
|
||||
blog_os
|
||||
|
||||
@@ -54,12 +54,12 @@ translators = ["MrZloHex"]
|
||||
Мы начнем с создания нового проекта cargo. Самый простой способ сделать это — через командную строку:
|
||||
|
||||
```
|
||||
cargo new blog_os --bin -- edition 2018
|
||||
cargo new blog_os --bin -- edition 2024
|
||||
```
|
||||
|
||||
Я назвал этот проект `blog_os`, но вы можете назвать как вам угодно. Флаг `--bin` указывает на то, что мы хотим создать исполняемый файл (а не библиотеку), а флаг `--edition 2018` указывает, что мы хотим использовать [редакцию Rust 2018][edition] для нашего крейта. После выполнения команды cargo создаст каталог со следующей структурой:
|
||||
Я назвал этот проект `blog_os`, но вы можете назвать как вам угодно. Флаг `--bin` указывает на то, что мы хотим создать исполняемый файл (а не библиотеку), а флаг `--edition 2024` указывает, что мы хотим использовать [редакцию Rust 2024][edition] для нашего крейта. После выполнения команды cargo создаст каталог со следующей структурой:
|
||||
|
||||
[edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```
|
||||
blog_os
|
||||
|
||||
@@ -45,12 +45,12 @@ translation_contributors = ["JiangengDong"]
|
||||
我们可以从创建一个新的 cargo 项目开始。最简单的办法是使用下面的命令:
|
||||
|
||||
```bash
|
||||
cargo new blog_os --bin --edition 2018
|
||||
cargo new blog_os --bin --edition 2024
|
||||
```
|
||||
|
||||
在这里我把项目命名为 `blog_os`,当然读者也可以选择自己的项目名称。默认情况下,即使不显式指定,cargo 也会为我们添加`--bin` 选项,说明我们将要创建一个可执行文件(而不是一个库); 另外 `--edition 2018` 参数指明了项目的包要使用 Rust 的 **2018 版次**([2018 edition]),但在默认情况下,该参数会指向本地安装的最新版本。当我们成功执行这行指令后,cargo 为我们创建的目录结构如下:
|
||||
在这里我把项目命名为 `blog_os`,当然读者也可以选择自己的项目名称。默认情况下,即使不显式指定,cargo 也会为我们添加`--bin` 选项,说明我们将要创建一个可执行文件(而不是一个库); 另外 `--edition 2024` 参数指明了项目的包要使用 Rust 的 **2024 版次**([2024 edition]),但在默认情况下,该参数会指向本地安装的最新版本。当我们成功执行这行指令后,cargo 为我们创建的目录结构如下:
|
||||
|
||||
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[2024 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```
|
||||
blog_os
|
||||
|
||||
@@ -58,12 +58,12 @@ Rust 所有的 crate 在預設情況下都會連結[標準函式庫][standard li
|
||||
我們先從建立一個新的 cargo 專案開始,最簡單的辦法是輸入下面的命令:
|
||||
|
||||
```
|
||||
cargo new blog_os --bin --edition 2018
|
||||
cargo new blog_os --bin --edition 2024
|
||||
```
|
||||
|
||||
我將專案命名為 `blog_os`,當然讀者也可以自己的名稱。`--bin` 選項說明我們將要建立一個執行檔(而不是一個函式庫),`--edition 2018` 選項指明我們的 crate 想使用 Rust [2018 版本][2018 edition]。當我們執行這行指令的時候,cargo 會為我們建立以下目錄結構:
|
||||
我將專案命名為 `blog_os`,當然讀者也可以自己的名稱。`--bin` 選項說明我們將要建立一個執行檔(而不是一個函式庫),`--edition 2024` 選項指明我們的 crate 想使用 Rust [2024 版本][2024 edition]。當我們執行這行指令的時候,cargo 會為我們建立以下目錄結構:
|
||||
|
||||
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
|
||||
[2024 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html
|
||||
|
||||
```
|
||||
blog_os
|
||||
|
||||
@@ -52,7 +52,7 @@ fn inner(i: usize) -> &'static u32 {
|
||||
}
|
||||
```
|
||||
|
||||
([ejecutar el ejemplo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6186a0f3a54f468e1de8894996d12819))
|
||||
([ejecutar el ejemplo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=6186a0f3a54f468e1de8894996d12819))
|
||||
|
||||
Si bien devolver una referencia no tiene sentido en este ejemplo, hay casos en los que queremos que una variable viva más que la función. Ya hemos visto tal caso en nuestro núcleo cuando intentamos [cargar una tabla de descriptores de interrupción] y tuvimos que usar una variable `static` para extender la duración.
|
||||
|
||||
@@ -158,7 +158,7 @@ println!("{}", x);
|
||||
Aquí es donde entra la propiedad de Rust. Asigna una [duración] abstracta a cada referencia, que es el ámbito en el que la referencia es válida. En el ejemplo anterior, la referencia `x` se toma del arreglo `z`, por lo que se vuelve inválida después de que `z` sale del alcance. Cuando [ejecutas el ejemplo anterior en el playground][playground-2], verás que el compilador de Rust efectivamente lanza un error:
|
||||
|
||||
[duración]: https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html
|
||||
[playground-2]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=28180d8de7b62c6b4a681a7b1f745a48
|
||||
[playground-2]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=28180d8de7b62c6b4a681a7b1f745a48
|
||||
|
||||
```
|
||||
error[E0597]: `z[_]` no vive lo suficiente
|
||||
@@ -443,7 +443,7 @@ La implementación se puede dividir en dos partes:
|
||||
[`None`]: https://doc.rust-lang.org/core/option/enum.Option.html#variant.None
|
||||
[`MapToError::FrameAllocationFailed`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/enum.MapToError.html#variant.FrameAllocationFailed
|
||||
[`Option::ok_or`]: https://doc.rust-lang.org/core/option/enum.Option.html#method.ok_or
|
||||
[operador de signo de interrogación]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html
|
||||
[operador de signo de interrogación]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
|
||||
[`MapperFlush`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/struct.MapperFlush.html
|
||||
[_buffer de traducción de direcciones_]: @/edition-2/posts/08-paging-introduction/index.md#the-translation-lookaside-buffer
|
||||
[`flush`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/struct.MapperFlush.html#method.flush
|
||||
|
||||
@@ -52,7 +52,7 @@ fn inner(i: usize) -> &'static u32 {
|
||||
}
|
||||
```
|
||||
|
||||
([この例をplaygroundで実行する](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6186a0f3a54f468e1de8894996d12819))
|
||||
([この例をplaygroundで実行する](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=6186a0f3a54f468e1de8894996d12819))
|
||||
|
||||
上の例の場合、参照を返すことには意味がありませんが、変数に関数よりも長く生存して欲しいというケースは存在します。すでに私たちのカーネルでそのようなケースに遭遇しています。それは[割り込み記述子表 (IDT) を読み込][load an interrupt descriptor table]もうとしたときで、ライフタイムを延ばすために`static`変数を使う必要がありました。
|
||||
|
||||
@@ -158,7 +158,7 @@ println!("{}", x);
|
||||
ここでRustの所有権の出番です。所有権システムは、参照が有効なスコープを表す抽象[ライフタイム][lifetime]をそれぞれの参照に指定します。上の例では、参照`x`は配列`z`から取られているので、`z`がスコープ外に出ると無効になります。[上の例をplaygroundで実行する][playground-2]と、確かにRustコンパイラがエラーを投げるのが分かります:
|
||||
|
||||
[lifetime]: https://doc.rust-jp.rs/book-ja/ch10-03-lifetime-syntax.html
|
||||
[playground-2]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=28180d8de7b62c6b4a681a7b1f745a48
|
||||
[playground-2]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=28180d8de7b62c6b4a681a7b1f745a48
|
||||
|
||||
```
|
||||
error[E0597]: `z[_]` does not live long enough
|
||||
@@ -167,6 +167,7 @@ error[E0597]: `z[_]` does not live long enough
|
||||
2 | let x = {
|
||||
| - borrow later stored here
|
||||
3 | let z = Box::new([1,2,3]);
|
||||
| - binding `z` declared here
|
||||
4 | &z[1]
|
||||
| ^^^^^ borrowed value does not live long enough
|
||||
5 | }; // z goes out of scope and `deallocate` is called
|
||||
|
||||
@@ -49,7 +49,7 @@ fn inner(i: usize) -> &'static u32 {
|
||||
}
|
||||
```
|
||||
|
||||
([run the example on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6186a0f3a54f468e1de8894996d12819))
|
||||
([run the example on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=6186a0f3a54f468e1de8894996d12819))
|
||||
|
||||
While returning a reference makes no sense in this example, there are cases where we want a variable to live longer than the function. We already saw such a case in our kernel when we tried to [load an interrupt descriptor table] and had to use a `static` variable to extend the lifetime.
|
||||
|
||||
@@ -155,7 +155,7 @@ println!("{}", x);
|
||||
This is where Rust's ownership comes in. It assigns an abstract [lifetime] to each reference, which is the scope in which the reference is valid. In the above example, the `x` reference is taken from the `z` array, so it becomes invalid after `z` goes out of scope. When you [run the above example on the playground][playground-2] you see that the Rust compiler indeed throws an error:
|
||||
|
||||
[lifetime]: https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html
|
||||
[playground-2]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=28180d8de7b62c6b4a681a7b1f745a48
|
||||
[playground-2]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=28180d8de7b62c6b4a681a7b1f745a48
|
||||
|
||||
```
|
||||
error[E0597]: `z[_]` does not live long enough
|
||||
@@ -164,6 +164,7 @@ error[E0597]: `z[_]` does not live long enough
|
||||
2 | let x = {
|
||||
| - borrow later stored here
|
||||
3 | let z = Box::new([1,2,3]);
|
||||
| - binding `z` declared here
|
||||
4 | &z[1]
|
||||
| ^^^^^ borrowed value does not live long enough
|
||||
5 | }; // z goes out of scope and `deallocate` is called
|
||||
@@ -442,7 +443,7 @@ The implementation can be broken down into two parts:
|
||||
[`None`]: https://doc.rust-lang.org/core/option/enum.Option.html#variant.None
|
||||
[`MapToError::FrameAllocationFailed`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/enum.MapToError.html#variant.FrameAllocationFailed
|
||||
[`Option::ok_or`]: https://doc.rust-lang.org/core/option/enum.Option.html#method.ok_or
|
||||
[question mark operator]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html
|
||||
[question mark operator]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
|
||||
[`MapperFlush`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/struct.MapperFlush.html
|
||||
[_translation lookaside buffer_]: @/edition-2/posts/08-paging-introduction/index.md#the-translation-lookaside-buffer
|
||||
[`flush`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/struct.MapperFlush.html#method.flush
|
||||
|
||||
@@ -54,7 +54,7 @@ fn inner(i: usize) -> &'static u32 {
|
||||
&z[i]
|
||||
}
|
||||
```
|
||||
[在 playground 上运行示例](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6186a0f3a54f468e1de8894996d12819)
|
||||
[在 playground 上运行示例](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=6186a0f3a54f468e1de8894996d12819)
|
||||
|
||||
在此示例中返回局部变量的引用没有意义,但在某些情况下,我们希望变量的生命周期超过函数。例如,在我们的内核中加载中断描述符表时,我们需要使用 `static` 变量来延长生命周期。
|
||||
|
||||
@@ -156,7 +156,7 @@ println!("{}", x);
|
||||
这就是 Rust 的所有权起作用的地方。它通过为每个引用分配一个抽象[生命周期][lifetime](引用有效的范围)解决此问题。在上述示例中,`x` 引用了 `z` 数组,因此在 `z` 超出作用域后失效。在 [playground][playground-2] 运行上述代码,Rust 编译器会报错:
|
||||
|
||||
[lifetime]: https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html
|
||||
[playground-2]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=28180d8de7b62c6b4a681a7b1f745a48
|
||||
[playground-2]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=28180d8de7b62c6b4a681a7b1f745a48
|
||||
|
||||
```
|
||||
error[E0597]: `z[_]` does not live long enough
|
||||
@@ -165,6 +165,7 @@ error[E0597]: `z[_]` does not live long enough
|
||||
2 | let x = {
|
||||
| - borrow later stored here
|
||||
3 | let z = Box::new([1,2,3]);
|
||||
| - binding `z` declared here
|
||||
4 | &z[1]
|
||||
| ^^^^^ borrowed value does not live long enough
|
||||
5 | }; // z goes out of scope and `deallocate` is called
|
||||
@@ -433,7 +434,7 @@ pub fn init_heap(
|
||||
[`None`]: https://doc.rust-lang.org/core/option/enum.Option.html#variant.None
|
||||
[`MapToError::FrameAllocationFailed`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/enum.MapToError.html#variant.FrameAllocationFailed
|
||||
[`Option::ok_or`]: https://doc.rust-lang.org/core/option/enum.Option.html#method.ok_or
|
||||
[question mark operator]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html
|
||||
[question mark operator]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
|
||||
[`MapperFlush`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/struct.MapperFlush.html
|
||||
[_translation lookaside buffer_]: @/edition-2/posts/08-paging-introduction/index.md#the-translation-lookaside-buffer
|
||||
[`flush`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/paging/mapper/struct.MapperFlush.html#method.flush
|
||||
|
||||
@@ -245,7 +245,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
Aquí leemos el archivo `foo.txt` y luego usamos el combinador [`then`] para encadenar un segundo futuro basado en el contenido del archivo. Si la longitud del contenido es menor que lo dado en `min_len`, leemos un archivo diferente `bar.txt` y se lo anexamos a `content` usando el combinador [`map`]. De lo contrario, solo devolvemos el contenido de `foo.txt`.
|
||||
|
||||
@@ -285,7 +285,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
Esta función es una traducción directa de la función `example` de [arriba](#desventajas) que usó funciones combinadoras. Usando el operador `.await`, podemos recuperar el valor de un futuro sin necesitar closures o tipos `Either`. Como resultado, podemos escribir nuestro código como escribimos código síncrono normal, con la diferencia de que _esto sigue siendo código asíncrono_.
|
||||
|
||||
@@ -580,7 +580,7 @@ println!("valor en: {:p}", &stack_value);
|
||||
println!("referencia interna: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
Aquí usamos la función [`mem::replace`] para reemplazar el valor asignado en el heap con una nueva instancia de estructura. Esto nos permite mover el valor original `heap_value` a la pila, mientras que el campo `self_ptr` de la estructura es ahora un puntero colgante que aún apunta a la antigua dirección del heap. Cuando intentas ejecutar el ejemplo en el playground, verás que las líneas impresas _"valor en:"_ y _"referencia interna:"_ muestran punteros diferentes. Por lo tanto, la asignación de un valor en el heap no es suficiente para hacer que las auto-referencias sean seguras.
|
||||
|
||||
@@ -629,24 +629,24 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
Además de cambiar `Box::new` a `Box::pin`, también necesitamos añadir el nuevo campo `_pin` en el inicializador de la estructura. Dado que `PhantomPinned` es un tipo de tamaño cero, solo necesitamos su nombre de tipo para inicializarlo.
|
||||
|
||||
Cuando [intentamos ejecutar nuestro ejemplo ajustado](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a) ahora, vemos que ya no funciona:
|
||||
Cuando [intentamos ejecutar nuestro ejemplo ajustado](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a) ahora, vemos que ya no funciona:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
Ambos errores ocurren porque el tipo `Pin<Box<SelfReferential>>` ya no implementa el trait `DerefMut`. Esto es exactamente lo que queremos porque el trait `DerefMut` devolvería una referencia `&mut`, que queremos prevenir. Esto solo ocurre porque ambos optamos por no implementar `Unpin` y cambiamos `Box::new` a `Box::pin`.
|
||||
|
||||
@@ -250,7 +250,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
ここでは、ファイル `foo.txt` を読み込んでから、[`then`] コンビネータを使って、ファイルの内容に基づいて 2 番目の future を連鎖させています。もしコンテンツの長さが与えられた `min_len` よりも小さければ、別の `bar.txt` ファイルを読み込んで、[`map`] コンビネータを使って `content` に追加します。それ以外の場合は、`foo.txt` の内容のみを返します。
|
||||
|
||||
@@ -290,7 +290,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
この関数は、[上記](#drawbacks)のコンビネータ関数を使った `example` 関数をそのまま翻訳したものです。 `.await` 演算子を使うことで、クロージャや `Either` 型を必要とせずに future の値を取得することができます。その結果、まるで通常の同期コードを書いているかのように非同期コードを書くことができます。
|
||||
|
||||
@@ -572,7 +572,7 @@ struct SelfReferential {
|
||||
|
||||
([Try it on the playground][playground-self-ref])
|
||||
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
|
||||
`SelfReferential` という名前のシンプルな構造体を作成します。この構造体には1つのポインタフィールドが含まれます。まず、この構造体をNULLポインタで初期化し、`Box::new`を使ってヒープ上に確保します。次に、ヒープに割り当てられた構造体のメモリアドレスを決定し、それを `ptr` 変数に格納します。最後に、`ptr`変数を`self_ptr`フィールドに代入して、構造体を自己参照にします。
|
||||
|
||||
@@ -588,7 +588,7 @@ println!("value at: {:p}", &stack_value);
|
||||
println!("internal reference: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
ここでは、[`mem::replace`]関数を使用して、ヒープに割り当てられた値を新しい構造体のインスタンスで置き換えています。これにより、元の `heap_value` をスタックに移動させることができますが、構造体の `self_ptr` フィールドは、古いヒープアドレスを指し示すダングリングポインタになっています。この例をplaygroundで実行してみると、出力された **"value at:"** と **"internal reference:"** の行には、たしかに異なるポインタが表示されていることがわかります。つまり、値をヒープに割り当てるだけでは、自己参照を安全にするには不十分なのです。
|
||||
|
||||
@@ -637,24 +637,24 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
`Box::new` を `Box::pin` に変更することに加えて、構造体を初期化するコード(イニシャライザ)に新しい `_pin` フィールドを追加する必要があります。`PhantomPinned` はゼロサイズの型なので、初期化に必要なのはその型名だけです。
|
||||
|
||||
今、[調整した例を実行してみると](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a)、動作しなくなっていることがわかります:
|
||||
今、[調整した例を実行してみると](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a)、動作しなくなっていることがわかります:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
どちらのエラーも、`Pin<Box<SelfReferential>>` 型が `DerefMut` trait を実装しなくなったために発生します。これはまさに求めていた結果であり、というのも、`DerefMut` trait は `&mut` 参照を返してしまうからで、私達はこれを防ぎたかったのです。これは、`Unpin` を使用しないようにして、`Box::new` を `Box::pin` に変更したからこそ起こる現象です。
|
||||
@@ -671,7 +671,7 @@ unsafe {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
|
||||
[`get_unchecked_mut`] 関数は `Pin<Box<T>>` ではなく `Pin<&mut T>` に対して動作するため、事前に [`Pin::as_mut`] を使用して値を変換する必要があります。その後、`get_unchecked_mut` が返す `&mut` 参照を使って、`self_ptr` フィールドを設定することができます。
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
Here we read the file `foo.txt` and then use the [`then`] combinator to chain a second future based on the file content. If the content length is smaller than the given `min_len`, we read a different `bar.txt` file and append it to `content` using the [`map`] combinator. Otherwise, we return only the content of `foo.txt`.
|
||||
|
||||
@@ -285,7 +285,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
This function is a direct translation of the `example` function from [above](#drawbacks) that used combinator functions. Using the `.await` operator, we can retrieve the value of a future without needing any closures or `Either` types. As a result, we can write our code like we write normal synchronous code, with the difference that _this is still asynchronous code_.
|
||||
|
||||
@@ -566,7 +566,7 @@ struct SelfReferential {
|
||||
|
||||
([Try it on the playground][playground-self-ref])
|
||||
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
|
||||
We create a simple struct named `SelfReferential` that contains a single pointer field. First, we initialize this struct with a null pointer and then allocate it on the heap using `Box::new`. We then determine the memory address of the heap-allocated struct and store it in a `ptr` variable. Finally, we make the struct self-referential by assigning the `ptr` variable to the `self_ptr` field.
|
||||
|
||||
@@ -582,7 +582,7 @@ println!("value at: {:p}", &stack_value);
|
||||
println!("internal reference: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
Here we use the [`mem::replace`] function to replace the heap-allocated value with a new struct instance. This allows us to move the original `heap_value` to the stack, while the `self_ptr` field of the struct is now a dangling pointer that still points to the old heap address. When you try to run the example on the playground, you see that the printed _"value at:"_ and _"internal reference:"_ lines indeed show different pointers. So heap allocating a value is not enough to make self-references safe.
|
||||
|
||||
@@ -631,24 +631,24 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
In addition to changing `Box::new` to `Box::pin`, we also need to add the new `_pin` field in the struct initializer. Since `PhantomPinned` is a zero-sized type, we only need its type name to initialize it.
|
||||
|
||||
When we [try to run our adjusted example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a) now, we see that it no longer works:
|
||||
When we [try to run our adjusted example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a) now, we see that it no longer works:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
Both errors occur because the `Pin<Box<SelfReferential>>` type no longer implements the `DerefMut` trait. This is exactly what we wanted because the `DerefMut` trait would return a `&mut` reference, which we wanted to prevent. This only happens because we both opted-out of `Unpin` and changed `Box::new` to `Box::pin`.
|
||||
@@ -665,7 +665,7 @@ unsafe {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
|
||||
The [`get_unchecked_mut`] function works on a `Pin<&mut T>` instead of a `Pin<Box<T>>`, so we have to use [`Pin::as_mut`] for converting the value. Then we can set the `self_ptr` field using the `&mut` reference returned by `get_unchecked_mut`.
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
这里我们读取 `foo.txt` 文件,然后使用 `then` 组合器根据文件内容链接第二个future。如果内容长度小于给定的 `min_len`,我们会读取另一个文件 `bar.txt` 并将其追加到 `content` ,否则仅返回 `foo.txt` 的内容。
|
||||
|
||||
@@ -298,7 +298,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
此函数直接转换自[上文](#drawbacks)中使用组合函数的 `example` 函数。通过使用 `.await` 运算符,我们无需任何闭包或者 `Either` 类型就可以直接获取 future 的值。于是我们就可以像写普通的同步代码一样编写代码,只不过 _这实际上是异步代码_。
|
||||
|
||||
@@ -581,7 +581,7 @@ struct SelfReferential {
|
||||
|
||||
([Try it on the playground][playground-self-ref])
|
||||
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
|
||||
我们创建了一个名为 `SelfReferential` 的简单结构体,它包含一个单独的指针字段。首先,我们使用空指针初始化此结构体,然后通过 `Box::new` 在堆上分配内存存储它。接下来尝试确定堆分配结构体的内存地址并将其存储在 `ptr` 变量中。最后,通过将 `ptr` 变量赋值给 `self_ptr` 字段使结构体形成自引用。
|
||||
|
||||
@@ -597,7 +597,7 @@ println!("value at: {:p}", &stack_value);
|
||||
println!("internal reference: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
这里我们使用 [`mem::replace`] 函数将堆分配的值替换为一个新的结构体实例。 这样我们就可以将原始的 `heap_value` 移动到栈上,而结构体的 `self_ptr` 字段此时变成了一个悬垂指针,仍然指向旧的堆地址。当您尝试在 playground 上运行示例时,会看到打印的 _"value at:"_ and _"internal reference:"_ 行确实显示了不同的指针。因此仅对值进行堆分配并不足以确保自引用安全。
|
||||
|
||||
@@ -646,24 +646,24 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
除了将 `Box::new` 改为 `Box::pin` 外,我们还需要在结构体初始化器中添加新的 `_pin` 字段。由于 `PhantomPinned` 是零大小类型,我们只要有其类型名称即可完成初始化。
|
||||
|
||||
当我们现在[尝试运行调整后的示例](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a)时,会发现它会报错:
|
||||
当我们现在[尝试运行调整后的示例](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a)时,会发现它会报错:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
这两个错误的发生是因为 `Pin<Box<SelfReferential>>` 类型不再实现 `DerefMut` trait。这正是我们想要的,因为 `DerefMut` trait 会返回一个 `&mut` 引用,而这正是我们想要避免的。这种情况之所以发生,仅仅是因为我们同时选择了不实现 `Unpin` 并将 `Box::new` 改为 `Box::pin`。
|
||||
@@ -680,7 +680,7 @@ unsafe {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
|
||||
`get_unchecked_mut` 函数工作于 `Pin<&mut T>` 之上,而非 `Pin<Box<T>>` ,因此我们必须使用 [`Pin::as_mut`] 转换值。然后我们可以通过 `get_unchecked_mut` 返回的 `&mut` 引用来设置 `self_ptr` 字段。
|
||||
|
||||
|
||||
@@ -301,7 +301,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
這裏我們讀取文件 `foo.txt`,然後使用 [`then`] 組合器 來連接 基於文件內容的第二個 future。
|
||||
如果內容的長度小於給定的 `min_len`,我們讀取一個不同的 `bar.txt` 文件並使用 [`map`] 組合器 將它附加到 `content` 上。
|
||||
@@ -348,7 +348,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
這個函數是對 [上面](#drawbacks) 的 `example` 函數的直接翻譯,它使用了組合器函數。
|
||||
使用 `.await` 運算符,我們可以獲取 future 的值而不需要任何閉包或 `Either` 類型。
|
||||
@@ -671,7 +671,7 @@ struct SelfReferential {
|
||||
|
||||
([Try it on the playground][playground-self-ref])
|
||||
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
|
||||
我們創建了一個名為 `SelfReferential` 的簡單結構體,它包含一個單指針字段。首先,我們使用空指針初始化這個結構體,然後使用 `Box::new` 在堆上分配它。然後,我們確定堆分配的結構體的內存地址並將其存儲在 `ptr` 變量中。最後,我們通過將 `ptr` 變量賦值給 `self_ptr` 字段使結構體成為自引用。
|
||||
|
||||
@@ -689,7 +689,7 @@ println!("value at: {:p}", &stack_value);
|
||||
println!("internal reference: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
這裏我們使用 [`mem::replace`] 函數將堆分配的值替換為一個新的結構體實例。
|
||||
這允許我們將原始的 `heap_value` 移動到棧上,而結構體的 `self_ptr` 字段現在是一個懸空指針,它仍然指向舊的堆地址。
|
||||
@@ -746,24 +746,24 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
除了將 `Box::new` 更改為 `Box::pin` 之外,我們還需要在結構體初始化程序中添加新的 `_pin` 字段。由於 `PhantomPinned` 是一個零大小的類型,我們只需要它的類型名稱來初始化它。
|
||||
|
||||
當我們 [嘗試運行我們調整後的例子](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a) 時,我們看到它不再工作:
|
||||
當我們 [嘗試運行我們調整後的例子](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a) 時,我們看到它不再工作:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
由於 `Pin<Box<SelfReferential>>` 類型不再實現 `DerefMut` 特型,所以這兩個錯誤都發生了。
|
||||
@@ -783,7 +783,7 @@ unsafe {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
|
||||
[`get_unchecked_mut`] 函數在 `Pin<&mut T>` 上工作,而不是在 `Pin<Box<T>>` 上,因此我們必須使用 [`Pin::as_mut`] 來轉換值。
|
||||
然後我們可以使用 `get_unchecked_mut` 返回的 `&mut` 引用來設置 `self_ptr` 字段。
|
||||
|
||||
Reference in New Issue
Block a user