mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Update playground links to Rust 2024
The compile/run behavior is the same between editions 2018 and 2024.
This commit is contained in:
@@ -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.
|
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:
|
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
|
[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
|
error[E0597]: `z[_]` no vive lo suficiente
|
||||||
|
|||||||
@@ -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`変数を使う必要がありました。
|
上の例の場合、参照を返すことには意味がありませんが、変数に関数よりも長く生存して欲しいというケースは存在します。すでに私たちのカーネルでそのようなケースに遭遇しています。それは[割り込み記述子表 (IDT) を読み込][load an interrupt descriptor table]もうとしたときで、ライフタイムを延ばすために`static`変数を使う必要がありました。
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ println!("{}", x);
|
|||||||
ここでRustの所有権の出番です。所有権システムは、参照が有効なスコープを表す抽象[ライフタイム][lifetime]をそれぞれの参照に指定します。上の例では、参照`x`は配列`z`から取られているので、`z`がスコープ外に出ると無効になります。[上の例をplaygroundで実行する][playground-2]と、確かにRustコンパイラがエラーを投げるのが分かります:
|
ここでRustの所有権の出番です。所有権システムは、参照が有効なスコープを表す抽象[ライフタイム][lifetime]をそれぞれの参照に指定します。上の例では、参照`x`は配列`z`から取られているので、`z`がスコープ外に出ると無効になります。[上の例をplaygroundで実行する][playground-2]と、確かにRustコンパイラがエラーを投げるのが分かります:
|
||||||
|
|
||||||
[lifetime]: https://doc.rust-jp.rs/book-ja/ch10-03-lifetime-syntax.html
|
[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
|
error[E0597]: `z[_]` does not live long enough
|
||||||
|
|||||||
@@ -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.
|
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:
|
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
|
[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
|
error[E0597]: `z[_]` does not live long enough
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ fn inner(i: usize) -> &'static u32 {
|
|||||||
&z[i]
|
&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` 变量来延长生命周期。
|
在此示例中返回局部变量的引用没有意义,但在某些情况下,我们希望变量的生命周期超过函数。例如,在我们的内核中加载中断描述符表时,我们需要使用 `static` 变量来延长生命周期。
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ println!("{}", x);
|
|||||||
这就是 Rust 的所有权起作用的地方。它通过为每个引用分配一个抽象[生命周期][lifetime](引用有效的范围)解决此问题。在上述示例中,`x` 引用了 `z` 数组,因此在 `z` 超出作用域后失效。在 [playground][playground-2] 运行上述代码,Rust 编译器会报错:
|
这就是 Rust 的所有权起作用的地方。它通过为每个引用分配一个抽象[生命周期][lifetime](引用有效的范围)解决此问题。在上述示例中,`x` 引用了 `z` 数组,因此在 `z` 超出作用域后失效。在 [playground][playground-2] 运行上述代码,Rust 编译器会报错:
|
||||||
|
|
||||||
[lifetime]: https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html
|
[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
|
error[E0597]: `z[_]` does not live long enough
|
||||||
|
|||||||
@@ -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`.
|
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_.
|
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);
|
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.
|
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,7 +629,7 @@ 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.
|
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 a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||||
|
|||||||
@@ -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` の内容のみを返します。
|
ここでは、ファイル `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 の値を取得することができます。その結果、まるで通常の同期コードを書いているかのように非同期コードを書くことができます。
|
この関数は、[上記](#drawbacks)のコンビネータ関数を使った `example` 関数をそのまま翻訳したものです。 `.await` 演算子を使うことで、クロージャや `Either` 型を必要とせずに future の値を取得することができます。その結果、まるで通常の同期コードを書いているかのように非同期コードを書くことができます。
|
||||||
|
|
||||||
@@ -572,7 +572,7 @@ struct SelfReferential {
|
|||||||
|
|
||||||
([Try it on the playground][playground-self-ref])
|
([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`フィールドに代入して、構造体を自己参照にします。
|
`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);
|
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:"** の行には、たしかに異なるポインタが表示されていることがわかります。つまり、値をヒープに割り当てるだけでは、自己参照を安全にするには不十分なのです。
|
ここでは、[`mem::replace`]関数を使用して、ヒープに割り当てられた値を新しい構造体のインスタンスで置き換えています。これにより、元の `heap_value` をスタックに移動させることができますが、構造体の `self_ptr` フィールドは、古いヒープアドレスを指し示すダングリングポインタになっています。この例をplaygroundで実行してみると、出力された **"value at:"** と **"internal reference:"** の行には、たしかに異なるポインタが表示されていることがわかります。つまり、値をヒープに割り当てるだけでは、自己参照を安全にするには不十分なのです。
|
||||||
|
|
||||||
@@ -637,7 +637,7 @@ let mut heap_value = Box::pin(SelfReferential {
|
|||||||
|
|
||||||
`Box::new` を `Box::pin` に変更することに加えて、構造体を初期化するコード(イニシャライザ)に新しい `_pin` フィールドを追加する必要があります。`PhantomPinned` はゼロサイズの型なので、初期化に必要なのはその型名だけです。
|
`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 a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||||
@@ -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` フィールドを設定することができます。
|
[`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`.
|
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_.
|
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])
|
([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.
|
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);
|
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.
|
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,7 +631,7 @@ 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.
|
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 a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||||
@@ -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`.
|
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` 的内容。
|
这里我们读取 `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 的值。于是我们就可以像写普通的同步代码一样编写代码,只不过 _这实际上是异步代码_。
|
此函数直接转换自[上文](#drawbacks)中使用组合函数的 `example` 函数。通过使用 `.await` 运算符,我们无需任何闭包或者 `Either` 类型就可以直接获取 future 的值。于是我们就可以像写普通的同步代码一样编写代码,只不过 _这实际上是异步代码_。
|
||||||
|
|
||||||
@@ -581,7 +581,7 @@ struct SelfReferential {
|
|||||||
|
|
||||||
([Try it on the playground][playground-self-ref])
|
([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` 字段使结构体形成自引用。
|
我们创建了一个名为 `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);
|
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:"_ 行确实显示了不同的指针。因此仅对值进行堆分配并不足以确保自引用安全。
|
这里我们使用 [`mem::replace`] 函数将堆分配的值替换为一个新的结构体实例。 这样我们就可以将原始的 `heap_value` 移动到栈上,而结构体的 `self_ptr` 字段此时变成了一个悬垂指针,仍然指向旧的堆地址。当您尝试在 playground 上运行示例时,会看到打印的 _"value at:"_ and _"internal reference:"_ 行确实显示了不同的指针。因此仅对值进行堆分配并不足以确保自引用安全。
|
||||||
|
|
||||||
@@ -646,7 +646,7 @@ let mut heap_value = Box::pin(SelfReferential {
|
|||||||
|
|
||||||
除了将 `Box::new` 改为 `Box::pin` 外,我们还需要在结构体初始化器中添加新的 `_pin` 字段。由于 `PhantomPinned` 是零大小类型,我们只要有其类型名称即可完成初始化。
|
除了将 `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 a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||||
@@ -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` 字段。
|
`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。
|
這裏我們讀取文件 `foo.txt`,然後使用 [`then`] 組合器 來連接 基於文件內容的第二個 future。
|
||||||
如果內容的長度小於給定的 `min_len`,我們讀取一個不同的 `bar.txt` 文件並使用 [`map`] 組合器 將它附加到 `content` 上。
|
如果內容的長度小於給定的 `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` 函數的直接翻譯,它使用了組合器函數。
|
這個函數是對 [上面](#drawbacks) 的 `example` 函數的直接翻譯,它使用了組合器函數。
|
||||||
使用 `.await` 運算符,我們可以獲取 future 的值而不需要任何閉包或 `Either` 類型。
|
使用 `.await` 運算符,我們可以獲取 future 的值而不需要任何閉包或 `Either` 類型。
|
||||||
@@ -671,7 +671,7 @@ struct SelfReferential {
|
|||||||
|
|
||||||
([Try it on the playground][playground-self-ref])
|
([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` 字段使結構體成為自引用。
|
我們創建了一個名為 `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);
|
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`] 函數將堆分配的值替換為一個新的結構體實例。
|
這裏我們使用 [`mem::replace`] 函數將堆分配的值替換為一個新的結構體實例。
|
||||||
這允許我們將原始的 `heap_value` 移動到棧上,而結構體的 `self_ptr` 字段現在是一個懸空指針,它仍然指向舊的堆地址。
|
這允許我們將原始的 `heap_value` 移動到棧上,而結構體的 `self_ptr` 字段現在是一個懸空指針,它仍然指向舊的堆地址。
|
||||||
@@ -746,7 +746,7 @@ let mut heap_value = Box::pin(SelfReferential {
|
|||||||
|
|
||||||
除了將 `Box::new` 更改為 `Box::pin` 之外,我們還需要在結構體初始化程序中添加新的 `_pin` 字段。由於 `PhantomPinned` 是一個零大小的類型,我們只需要它的類型名稱來初始化它。
|
除了將 `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 a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||||
@@ -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`] 函數在 `Pin<&mut T>` 上工作,而不是在 `Pin<Box<T>>` 上,因此我們必須使用 [`Pin::as_mut`] 來轉換值。
|
||||||
然後我們可以使用 `get_unchecked_mut` 返回的 `&mut` 引用來設置 `self_ptr` 字段。
|
然後我們可以使用 `get_unchecked_mut` 返回的 `&mut` 引用來設置 `self_ptr` 字段。
|
||||||
|
|||||||
Reference in New Issue
Block a user