From 499278e793f936e956a85fd59eef3a542cbefc89 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:01 +0900 Subject: [PATCH 01/22] =?UTF-8?q?ch00=20=E3=81=AF=E3=81=98=E3=82=81?= =?UTF-8?q?=E3=81=AB=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0?= =?UTF-8?q?=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- src/ch00-00-introduction.md | 98 +++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/src/ch00-00-introduction.md b/src/ch00-00-introduction.md index 327055d08..f690afb48 100644 --- a/src/ch00-00-introduction.md +++ b/src/ch00-00-introduction.md @@ -13,7 +13,7 @@ > 注釈: この本のこの版は、本として利用可能な[The Rust Programming Language][nsprust]と、 > [No Starch Press][nsp]のebook形式と同じです。 -[nsprust]: https://nostarch.com/rust +[nsprust]: https://nostarch.com/rust-programming-language-2nd-edition [nsp]: https://nostarch.com/ * Cargoは、付属の依存関係管理ツール兼ビルドツールで、依存関係の追加、コンパイル、管理を容易にし、Rustのエコシステム全体で一貫性を持たせます。 -* Rustfmtは開発者の間で一貫したコーディングスタイルを保証します。 +* Rustfmtフォーマットツールは開発者の間で一貫したコーディングスタイルを保証します。 * Rust言語サーバーは、IDE(統合開発環境)との統合により、コード補完やインラインエラーメッセージに対応しています。 @@ -161,17 +162,17 @@ Rustは、Rustプログラミング言語やコミュニティ、開発者ツー Rustは、スピードと安定性を言語に渇望する方向けです。ここでいうスピードとは、 -Rustで作れるプログラムのスピードとソースコードを書くスピードのことです。Rustコンパイラのチェックにより、 +Rustコードの実行速度とプログラムを書くスピードのことです。Rustコンパイラのチェックにより、 機能の追加とリファクタリングを通して安定性を保証してくれます。これはこのようなチェックがない言語の脆いレガシーコードとは対照的で、 その場合開発者はしばしば、変更するのを恐れてしまいます。ゼロコスト抽象化を志向し、 手で書いたコードと同等の速度を誇る低レベルコードにコンパイルされる高レベル機能により、 @@ -218,12 +219,12 @@ reading a book that specifically provides an introduction to programming. 一般的に、この本は、順番に読み進めていくことを前提にしています。後の章は、前の章の概念の上に成り立ち、 -前の章では、ある話題にさほど深入りしない可能性があります; 典型的に後ほどの章で同じ話題を再度しています。 +前の章では、特定の話題にさほど深入りしない可能性がありますが、後ほどの章で同じ話題を再検討するでしょう。 第1章はRustのインストール方法、“Hello, world!”プログラムの書き方、Rustのパッケージマネージャ兼、 -ビルドツールのCargoの使用方法を説明します。第2章は、Rust言語への実践的な導入です。ここでは概念をざっくりと講義し、後ほどの章で追加の詳細を提供します。 -今すぐRustの世界に飛び込みたいなら、第2章こそがそのためのものです。第3章は他のプログラミング言語の機能に似たRustの機能を講義していますが、 -最初その3章すら飛ばして、まっすぐに第4章に向かい、Rustの所有権システムについて学びたくなる可能性があります。 -しかしながら、あなたが次に進む前に全ての詳細を学ぶことを好む特別に几帳面な学習者なら、 +ビルドツールのCargoの使用方法を説明します。第2章は、数当てゲームを作りながら、実際にRustでのプログラミングをやってもらう導入です。 +ここでは概念をざっくりと講義し、後ほどの章で追加の詳細を提供します。 +今すぐRustの世界に飛び込みたいなら、第2章こそがそのためのものです。第3章は他のプログラミング言語の機能に似たRustの機能を講義し、 +第4章ではRustの所有権システムについて学びます。 +あなたが次に進む前に全ての詳細を学ぶことを好む特別に几帳面な学習者なら、 第2章を飛ばして真っ先に第3章に行き、学んだ詳細を適用するプロジェクトに取り組みたくなった時に第2章に戻りたくなる可能性があります。 最後に、言語についての有用な情報をよりリファレンスのような形式で含む付録があります。 付録AはRustのキーワードを講義し、付録Bは、Rustの演算子と記号、付録Cは、 標準ライブラリが提供する導出可能なトレイト、付録Dはいくつか便利な開発ツールを講義し、 -付録EではRustのエディションについて説明します。 - +付録EではRustのエディションについて説明します。付録Fではこの本の翻訳を見つけることができ、 +付録GではRustの作られ方、そしてnightly Rustとは何かについて講義します。 -| Ferris | Meaning | -|------------------------------------------------------------------------|--------------------------------------------------| -| | このコードはコンパイルできません! | -| | このコードはパニックします! | -| | このコードはアンセーフなコードを含みます。 | -| | このコードは求められている振る舞いをしません。 | +| Ferris | Meaning | +|------------------------------------------------------------------------------------------------------------------|--------------------------------------------------| +| Ferris with a question mark | このコードはコンパイルできません! | +| Ferris throwing up their hands | このコードはパニックします! | +| Ferris with one claw up, shrugging | このコードは求められている振る舞いをしません。 | -> 注釈: なんらかの理由で`rustup`を使用したくない場合、[Rustインストールページ][rust-installation-page]で、 +> 注釈: なんらかの理由で`rustup`を使用したくない場合、[Other Rust Installation Methods ページ][otherinstall]で、 > 他の選択肢をご覧になってください。 -> 訳注:日本語版のRustインストールページは[こちら][rust-installation-page-ja]です。 - -[rust-installation-page]: https://www.rust-lang.org/tools/install/ -[rust-installation-page-ja]: https://www.rust-lang.org/ja/tools/install/ - 以下の手順で最新の安定版のRustコンパイラをインストールします。 @@ -45,16 +40,17 @@ Rustは安定性 (stability) を保証しているので、現在この本の例 > > In this chapter and throughout the book, we’ll show some commands used in the > terminal. Lines that you should enter in a terminal all start with `$`. You -> don’t need to type in the `$` character; it indicates the start of each -> command. Lines that don’t start with `$` typically show the output of the -> previous command. Additionally, PowerShell-specific examples will use `>` -> rather than `$`. +> don’t need to type the `$` character; it’s the command line prompt shown to +> indicate the start of each command. Lines that don’t start with `$` typically +> show the output of the previous command. Additionally, PowerShell-specific +> examples will use `>` rather than `$`. --> > ### コマンドラインの記法 > > この章及び、本を通して、端末で使用するなんらかのコマンドを示すことがあります。読者が入力するべき行は、 -> 全て`$`で始まります。ただし、読者が`$`文字を入力する必要はありません; これは各コマンドの開始を示しているだけです。 +> 全て`$`で始まります。ただし、読者が`$`文字を入力する必要はありません; +> これは各コマンドの開始を示すために表示しているコマンドラインプロンプトです。 > `$`で始まらない行は、典型的には直前のコマンドの出力を示します。また、PowerShell限定の例には、 > `$`ではなく、`>`を使用します。 @@ -88,22 +84,37 @@ Rust is installed now. Great! ``` + +*リンカ*も必要になるでしょう。 +リンカは、コンパイルされた出力をひとつのファイルに合体させるためにRustが使用するプログラムです。 +リンカが既にインストールされている可能性は高いでしょう。 +リンカエラーが発生したときは、Cコンパイラは典型的にリンカを含んでいるでしょうから、Cコンパイラをインストールすべきです。 +一般的なRustパッケージの中には、Cコードに依存し、Cコンパイラが必要になるものもあるので、この理由からもCコンパイラは有用です。 + + + +macOSでは、以下を実行することでCコンパイラが手に入ります: + +```console +$ xcode-select --install +``` + + -これに加えて、なんらかのリンカが必要になるでしょう。既にインストールされている可能性は高いものの、 -Rustプログラムをコンパイルしようとした時、リンカが実行できないというエラーが出たら、 -システムにリンカがインストールされていないということなので、手動でインストールする必要があるでしょう。 -Cコンパイラは通常正しいリンカとセットになっています。 -自分のプラットフォームのドキュメンテーションを見てCコンパイラのインストール方法を確認してください。 -一般的なRustパッケージの中には、Cコードに依存し、Cコンパイラが必要になるものもあります。 -ですので、Cコンパイラは今のうちにインストールしておく価値があるかもしれません。 +Linuxユーザは、通常はディストリビューションのドキュメントに従って、GCCまたはClangをインストールするべきです。 +例えばUbuntuを使用している場合は、`build-essential`パッケージをインストールすれば大丈夫です。 Windowsでは、[https://www.rust-lang.org/tools/install][install]に行き、手順に従ってRustをインストールしてください。 -インストールの途中で、Visual Studio 2013以降用のC++ビルドツールも必要になるという旨のメッセージが出るでしょう。 -ビルドツールを取得する最も簡単な方法は、[Visual Studio 2019用のビルドツール][visualstudio]をインストールすることです。 -どのワークロード (workloads) をインストールするかと質問されたときは、"C++ build tools"が選択されており、Windows 10 SDKと英語の言語パック (English language pack) が含まれていることを確かめてください。 +インストールの途中で、Visual Studio 2013以降用のMSVCビルドツールも必要になるという旨のメッセージが出るでしょう。 -> 訳注:Windowsの言語を日本語にしている場合は言語パックのところで「日本語」が選択されており、そのままの設定でインストールしても基本的に問題ないはずです。しかし、サードパーティーのツールやライブラリの中には英語の言語パックを必要とするものがあるため、「日本語」に加えて「英語」も選択することをお勧めします。 + -[install]: https://www.rust-lang.org/tools/install -[visualstudio]: https://visualstudio.microsoft.com/visual-cpp-build-tools/ +ビルドツールを取得するには、[Visual Studio 2022][visualstudio]をインストールする必要があるでしょう。 +どのワークロード (workloads) をインストールするかと質問されたときは、以下を含めてください: + + + +* 「C++によるデスクトップ開発」(“Desktop Development with C++”) +* Windows 10または11のSDK +* 英語の言語パック (English language pack) コンポーネント (お好みで他の任意の言語パックも) + +> 訳注:Windowsの言語を日本語にしている場合は言語パックのところで「日本語」が選択されており、そのままの設定でインストールしても基本的に問題ないはずです。しかし、サードパーティーのツールやライブラリの中には英語の言語パックを必要とするものがあるため、「日本語」に加えて「英語」も選択することをお勧めします。 -### 更新及びアンインストール +### トラブルシューティング -`rustup`経由でRustをインストールしたなら、最新版へ更新するのは簡単です。 -シェルから以下の更新スクリプトを実行してください: +Rustが正常にインストールされているか確かめるには、シェルを開いて以下の行を入力してください: ```console -$ rustup update +$ rustc --version ``` -Rustと`rustup`をアンインストールするには、シェルから以下のアンインストールスクリプトを実行してください: +バージョンナンバー、コミットハッシュ、最新の安定版がリリースされたコミット日時が以下のフォーマットで表示されるのを目撃するはずです。 -```console -$ rustup self uninstall +```text +rustc x.y.z (abcabcabc yyyy-mm-dd) ``` -### トラブルシューティング +この情報が見られたなら、Rustのインストールに成功しています! +この情報が出ない場合は、次のようにしてRustが`%PATH%`システム環境変数にあることを確認してください。 -Rustが正常にインストールされているか確かめるには、シェルを開いて以下の行を入力してください: +Windows CMDでは: ```console -$ rustc --version +> echo %PATH% ``` -バージョンナンバー、コミットハッシュ、最新の安定版がリリースされたコミット日時が以下のフォーマットで表示されるのを目撃するはずです。 +PowerShellでは: -```text -rustc x.y.z (abcabcabc yyyy-mm-dd) +```powershell +> echo $env:Path ``` -この情報が見られたなら、Rustのインストールに成功しています!この情報が出ず、Windowsを使っているなら、 -Rustが`%PATH%`システム環境変数にあることを確認してください。これらが全て正常であるのに、それでもRustがうまく動かないなら、 -助力を得られる場所はたくさんあります。最も簡単なのが[Rustの公式Discord][discord]の#beginnersチャンネルです。そのアドレスで、助けてくれる他のRustacean (Rustユーザが自分たちのことを呼ぶ、冗談めいたニックネーム) たちとチャットできます。 -他にも、素晴らしいリソースとして[ユーザ・フォーラム][users]と[Stack Overflow][stackoverflow]が挙げられます。 +LinuxおよびmacOSでは: + +```console +$ echo $PATH +``` + + + +これらが全て正常であるのに、それでもRustがうまく動かないなら、助力を得られる場所はたくさんあります。 +他のRustacean(Rustユーザが自分たちのことを呼ぶ、冗談めいたニックネーム)たちと交流する方法を[コミュニティページ][community]で探してください。 > 訳注1:Rustaceanについて、いらないかもしれない補足です。[公式Twitter曰く、Rustaceanはcrustaceans(甲殻類)から来ている][twitter]そうです。 > そのため、Rustのマスコットは(非公式らしいですが)[カニ][mascott]。上の会話でCの欠点を削ぎ落としているからcを省いてるの?みたいなことを聞いていますが、 > 違うそうです。検索したら、堅牢性が高いから甲殻類という意見もありますが、真偽は不明です。 > 明日使えるかもしれないトリビアでした。 -> 訳注2:上にある公式Discordは英語話者のコミュニティです。日本語話者のためのコミュニティが[Zulip rust-lang-jpにあり][zulip_jp]、こちらでもRustaceanたちが活発に議論をしています。 +> 訳注2:上にあるコミュニティページはどれも英語話者のコミュニティへのリンク集です。日本語話者のためのコミュニティが[Zulip rust-lang-jpにあり][zulip_jp]、こちらでもRustaceanたちが活発に議論をしています。 > 公式Discord同様、初心者向けの#beginnersチャンネルが存在するので、気軽に質問してみてください。 -[discord]: https://discord.gg/rust-lang -[users]: https://users.rust-lang.org/ -[stackoverflow]: https://stackoverflow.com/questions/tagged/rust [twitter]: https://mobile.twitter.com/rustlang/status/916284650674323457 [mascott]: https://www.slideshare.net/wolf-dog/ss-64026540 [zulip_jp]: https://rust-lang-jp.zulipchat.com + + +### 更新及びアンインストール + + + +`rustup`経由でRustがインストールされたなら、新しくリリースされた版へ更新するのは簡単です。 +シェルから以下の更新スクリプトを実行してください: + +```console +$ rustup update +``` + + + +Rustと`rustup`をアンインストールするには、シェルから以下のアンインストールスクリプトを実行してください: + +```console +$ rustup self uninstall +``` + @@ -234,12 +286,12 @@ Rustが`%PATH%`システム環境変数にあることを確認してくださ ### ローカルのドキュメンテーション -インストールされたRustには、ローカルに複製されたドキュメンテーションのコピーが含まれているので、これをオフラインで閲覧することができます。 +インストールされたRustには、オフラインでドキュメンテーションを閲覧できるように、ドキュメンテーションのローカルコピーが含まれています。 ブラウザでローカルのドキュメンテーションを開くには、`rustup doc`を実行してください。 標準ライブラリにより提供される型や関数がなんなのかや、それをどう使えば良いのかがよくわからないときは、いつでもAPIのドキュメンテーションを検索してみてください! + + +[otherinstall]: https://forge.rust-lang.org/infra/other-installation-methods.html +[install]: https://www.rust-lang.org/tools/install +[visualstudio]: https://visualstudio.microsoft.com/downloads/ +[community]: https://www.rust-lang.org/community diff --git a/src/ch01-02-hello-world.md b/src/ch01-02-hello-world.md index d517eef33..686cbfdb5 100644 --- a/src/ch01-02-hello-world.md +++ b/src/ch01-02-hello-world.md @@ -5,9 +5,9 @@ ## Hello, World! Rustをインストールしたので、最初のRustプログラムを書きましょう。新しい言語を学ぶ際に、 @@ -19,16 +19,17 @@ Rustをインストールしたので、最初のRustプログラムを書きま > no specific demands about your editing or tooling or where your code lives, so > if you prefer to use an integrated development environment (IDE) instead of > the command line, feel free to use your favorite IDE. Many IDEs now have some -> degree of Rust support; check the IDE’s documentation for details. Recently, -> the Rust team has been focusing on enabling great IDE support, and progress -> has been made rapidly on that front! +> degree of Rust support; check the IDE’s documentation for details. The Rust +> team has been focusing on enabling great IDE support via `rust-analyzer`. See +> [Appendix D][devtools] for more details. --> > 注釈: この本は、コマンドラインに基礎的な馴染みがあることを前提にしています。Rustは、編集やツール、 > どこにコードがあるかについて特定の要求をしないので、コマンドラインではなくIDEを使用することを好むのなら、 > どうぞご自由にお気に入りのIDEを使用してください。今では、多くのIDEがなんらかの形でRustをサポートしています; -> 詳しくは、IDEのドキュメンテーションをご覧ください。最近、Rustチームは優れたIDEサポートを有効にすることに注力し、 -> その前線で急激に成果があがっています! +> 詳しくは、IDEのドキュメンテーションをご覧ください。 +> Rustチームは`rust-analyzer`を介して優れたIDEサポートを可能にすることに注力しています。 +> 詳しくは[付録D][devtools]をご覧ください。 端末を開いて以下のコマンドを入力し、*projects*ディレクトリと、 -*projects*ディレクトリ内にHello, world!プロジェクトのディレクトリを作成してください。 +*projects*ディレクトリ内に「Hello, world!」プロジェクトのディレクトリを作成してください。 -LinuxとmacOSなら、こう入力してください: +Linux、macOS、そしてWindows上のPowerShellなら、こう入力してください: -```text +```console $ mkdir ~/projects $ cd ~/projects $ mkdir hello_world @@ -80,19 +81,6 @@ Windowsのcmdなら、こう: > cd hello_world ``` - - -WindowsのPowerShellなら、こう: - -```powershell -> mkdir $env:USERPROFILE\projects -> cd $env:USERPROFILE\projects -> mkdir hello_world -> cd hello_world -``` - @@ -101,13 +89,13 @@ WindowsのPowerShellなら、こう: 次にソースファイルを作り、*main.rs*というファイル名にしてください。Rustのファイルは常に *.rs*という拡張子で終わります。 -ファイル名に2単語以上使っているなら、アンダースコアで区切ってください。例えば、*helloworld.rs*ではなく、 +ファイル名に2単語以上使っているなら、アンダースコアで区切るのが規約です。例えば、*helloworld.rs*ではなく、 *hello_world.rs*を使用してください。 -ファイルを保存し、端末ウィンドウに戻ってください。LinuxかmacOSなら、以下のコマンドを打ってファイルをコンパイルし、 -実行してください: +ファイルを保存し、*~/projects/hello_world*ディレクトリの端末ウィンドウに戻ってください。 +LinuxかmacOSなら、以下のコマンドを打ってファイルをコンパイルし、実行してください: -```text +```console $ rustc main.rs $ ./main Hello, world! @@ -163,16 +152,17 @@ Hello, world! OSに関わらず、`Hello, world!`という文字列が端末に出力されるはずです。この出力が見れないなら、 -「トラブルシューティング」節に立ち戻って、助けを得る方法を参照してください。 +インストールの節の[「トラブルシューティング」][troubleshooting]の部分に立ち戻って、助けを得る方法を参照してください。 `Hello, world!`が確かに出力されたら、おめでとうございます!正式にRustプログラムを書きました。 @@ -185,11 +175,11 @@ Rustプログラマになったのです!ようこそ! ### Rustプログラムの解剖 -Hello, world!プログラムでいま何が起こったのか詳しく確認しましょう。 +この「Hello, world!」プログラムを詳しく再確認しましょう。 こちらがパズルの最初のピースです: ```rust @@ -199,42 +189,41 @@ fn main() { ``` -これらの行でRustで関数を定義しています。`main`関数は特別です: 常に全ての実行可能なRustプログラムで走る最初のコードになります。 -1行目は、引数がなく、何も返さない`main`という関数を宣言しています。引数があるなら、かっこ(`()`)の内部に入ります。 +これらの行は`main`という名前の関数を定義しています。`main`関数は特別です: 常に全ての実行可能なRustプログラムで走る最初のコードになります。 +ここで、1行目は、引数がなく何も返さない`main`という関数を宣言しています。引数があるなら、かっこ(`()`)の内部に入ります。 -また、関数の本体が波括弧(`{}`)に包まれていることにも注目してください。Rustでは、全ての関数本体の周りにこれらが必要になります。 +関数の本体は`{}`に包まれます。Rustでは、全ての関数本体の周りに波括弧が必要になります。 スペースを1つあけて、開き波括弧を関数宣言と同じ行に配置するのがいいスタイルです。 -複数のRustプロジェクトに渡って標準的なスタイルにこだわりたいなら、`rustfmt`を使うことでコードを決まったスタイルに整形できるでしょう。 -Rustチームは、`rustc`のように標準的なRustの配布にこのツールを含んでいるため、既にコンピューターにインストールされているはずです! -詳細は、オンラインのドキュメンテーションを確認してください。 +> 注釈: 複数のRustプロジェクトに渡って標準的なスタイルにこだわりたいなら、`rustfmt`を使うことでコードを決まったスタイルに整形できるでしょう(`rustfmt`の詳細は[付録D][devtools]で)。 +> Rustチームは、`rustc`のように標準的なRustの配布にこのツールを含んでいるため、既にコンピューターにインストールされているはずです! -`main`関数内には、こんなコードがあります: +`main`関数の本体は、こんなコードを抱えています: ```rust println!("Hello, world!"); @@ -242,23 +231,29 @@ Inside the `main` function is the following code: この行が、この小さなプログラムの全作業をしています: テキストを画面に出力するのです。 -ここで気付くべき重要な詳細が4つあります。まず、Rustのスタイルは、タブではなく、4スペースでインデントするということです。 +ここで気付くべき重要な詳細が4つあります。 + +まず、Rustのスタイルは、タブではなく、4スペースでインデントするということです。 + + 2番目に`println!`はRustのマクロを呼び出すということです。代わりに関数を呼んでいたら、 `println`(`!`なし)と入力されているでしょう。Rustのマクロについて詳しくは、第19章で議論します。 -とりあえず、`!`を使用すると、普通の関数ではなくマクロを呼んでいるのだということを知っておくだけでいいでしょう。 +とりあえず、`!`を使用すると、普通の関数ではなくマクロを呼んでいるのだということと、マクロは関数と同じルールには必ずしも従わないということを知っておくだけでいいでしょう。 -Linux、macOS、WindowsのPowerShellなら、シェルで以下のように`ls`コマンドを入力することで実行可能ファイルを見られます: +Linux、macOS、WindowsのPowerShellなら、シェルで`ls`コマンドを入力することで実行可能ファイルを見られます: -```text +```console $ ls main main.rs ``` +LinuxとmacOSでは、2つのファイルが見えるでしょう。 +WindowsのPowerShellでは、CMDを使ったときに見ることになるのと同じ3つのファイルが見えるでしょう。 WindowsのCMDなら、以下のように入力するでしょう: ```cmd @@ -340,29 +339,25 @@ main.rs これは、*.rs*拡張子のソースコードファイル、実行可能ファイル(Windowsなら*main.exe*、他のプラットフォームでは、*main*)、 -そして、CMDを使用しているなら、*.pdb*拡張子のデバッグ情報を含むファイルを表示します。ここから、 +そして、Windowsを使用しているなら、*.pdb*拡張子のデバッグ情報を含むファイルを表示します。ここから、 *main*か*main.exe*を走らせます。このように: -```text +```console $ ./main # or .\main.exe on Windows # または、Widnowsなら.\main.exe ``` -*main.rs*がHello, world!プログラムなら、この行は`Hello, world!`と端末に出力するでしょう。 - - +*main.rs*がHello, world!プログラムなら、この行は`Hello, world!`と端末に出力します。 + +[troubleshooting]: ch01-01-installation.html#トラブルシューティング +[devtools]: appendix-04-useful-development-tools.html diff --git a/src/ch01-03-hello-cargo.md b/src/ch01-03-hello-cargo.md index 8b4284a65..6a9fe8884 100644 --- a/src/ch01-03-hello-cargo.md +++ b/src/ch01-03-hello-cargo.md @@ -19,14 +19,14 @@ CargoはRustのビルドシステム兼パッケージマネージャです。 いままでに書いたようなごく単純なRustプログラムには依存がありません。 -そのため「Hello, world!」プロジェクトをCargoでビルドしても、Cargoの中のコードをビルドする部分しか使わないでしょう。 +「Hello, world!」プロジェクトをCargoでビルドしても、Cargoの中のコードをビルドする部分しか使わないでしょう。 より複雑なRustプログラムを書くようになると依存を追加することになりますが、Cargoを使ってプロジェクトを開始したなら、依存の追加もずっと簡単になります。 Rustプロジェクトの大多数がCargoを使用しているので、これ以降、この本では、あなたもCargoを使用していると想定します。 @@ -63,9 +63,9 @@ determine how to install Cargo separately. Cargoを使って新しいプロジェクトを作成し、元の「Hello, world!」プロジェクトとの違いを見ていきましょう。 @@ -78,12 +78,12 @@ $ cd hello_cargo ``` -最初のコマンドは*hello_cargo*という名の新しいディレクトリを作成します。 +最初のコマンドは*hello_cargo*という名の新しいディレクトリとプロジェクトを作成します。 プロジェクトを*hello_cargo*と名付けたので、Cargoはそれに関連するいくつかのファイルを同名のディレクトリに作成します。 -このファイルは[TOML](https://toml.io)(*Tom's Obvious, Minimal Language*、トムの明確な最小限の言語)形式で、Cargoの設定フォーマットです。 +このファイルは[*TOML*][toml](*Tom's Obvious, Minimal Language*、トムの明確な最小限の言語)形式で、Cargoの設定フォーマットです。 Cargoはリスト1-1で書いたような「Hello, world!」プログラムを生成してくれています。 -これまでのところ、以前のプロジェクトとCargoが生成したプロジェクトの違いは、Cargoがコードを*src*ディレクトリに配置したことと、 +これまでのところ、私たちのプロジェクトとCargoが生成したプロジェクトの違いは、Cargoがコードを*src*ディレクトリに配置したことと、 最上位のディレクトリに*Cargo.toml*設定ファイルがあることです。 このコマンドは実行ファイルを現在のディレクトリではなく、*target/debug/hello_cargo*(Windowsでは*target/debug/hello_cargo.exe*)に作成します。 +デフォルトのビルドはデバッグビルドなので、Cargoはバイナリを*debug*という名前のディレクトリの中に入れます。 以下のコマンドで実行ファイルを実行できます。 ```console $ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows -$ # Windowsでは .\target\debug\hello_cargo.exe + # Windowsでは .\target\debug\hello_cargo.exe Hello, world! ``` @@ -290,7 +294,7 @@ Cargoがその内容を管理してくれます。 先ほどは`cargo build`でプロジェクトをビルドし、`./target/debug/hello_cargo`で実行しました。 @@ -303,15 +307,25 @@ $ cargo run Hello, world! ``` + + +`cargo run`を使ったほうが、`cargo build`を忘れずに実行した後バイナリへのパス全体を使わないといけないのと比較して便利なので、 +ほとんどの開発者は`cargo run`を使います。 + 今回はCargoが`hello_cargo`をコンパイルしていることを示す出力がないことに注目してください。 -Cargoはファイルが変更されていないことに気づいたので、単にバイナリを実行したのです。 +Cargoはファイルが変更されていないことに気づいたので、再ビルドせずに単にバイナリを実行したのです。 もしソースコードを変更していたら、Cargoは実行前にプロジェクトを再ビルドし、以下のような出力が表示されたことでしょう。 ```console @@ -338,16 +352,17 @@ $ cargo check なぜ実行可能ファイルが欲しくないのでしょうか? `cargo check`は実行ファイルを生成するステップを省くことができるので、多くの場合、`cargo build`よりもずっと高速です。 -もし、あなたがコードを書きながら継続的にチェックするのなら、`cargo check`を使えば、そのプロセスを高速化できます! +もし、あなたがコードを書きながら継続的にチェックするのなら、`cargo check`を使えば、プロジェクトのコンパイルがまだ通るか教えてくれるプロセスを高速化できます! そのため多くのRustaceanはプログラムを書きながら定期的に`cargo check`を実行し、コンパイルできるか確かめます。 そして、実行ファイルを使う準備ができたときに`cargo build`を走らせるのです。 @@ -418,13 +433,14 @@ the executable in *target/release*. 単純なプロジェクトでは、Cargoは単に`rustc`を使うことに対してあまり多くの価値を生みません。 しかし、プログラムが複雑になるにつれて、その価値を証明することになるでしょう。 -複数のクレートからなる複雑なプロジェクトでは、Cargoにビルドを調整させるほうがずっと簡単です。 +プログラムが複数のファイルに分かれるほど大きくなったり、依存が必要になってくると、 +Cargoにビルドを調整させるほうがずっと簡単です。 -Cargoの詳細については、[ドキュメント]を参照してください。 - -[ドキュメント]: https://doc.rust-lang.org/cargo/ +Cargoの詳細については、[ドキュメント][cargo]を参照してください。 [installation]: ch01-01-installation.html#インストール +[toml]: https://toml.io [appendix-e]: appendix-05-editions.html +[cargo]: https://doc.rust-lang.org/cargo/ From cc34c09dc4170731771a3b3ccf5d2ed922ec3ce5 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:01 +0900 Subject: [PATCH 03/22] =?UTF-8?q?ch02=20=E6=95=B0=E5=BD=93=E3=81=A6?= =?UTF-8?q?=E3=82=B2=E3=83=BC=E3=83=A0=E3=81=AE=E3=83=97=E3=83=AD=E3=82=B0?= =?UTF-8?q?=E3=83=A9=E3=83=9F=E3=83=B3=E3=82=B0=E3=81=AE=E5=92=8C=E8=A8=B3?= =?UTF-8?q?=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-02-01/src/main.rs | 2 +- .../listing-02-02/Cargo.lock | 40 +- .../listing-02-02/Cargo.toml | 2 +- .../listing-02-02/src/main.rs | 2 +- .../listing-02-03/Cargo.lock | 16 +- .../listing-02-03/Cargo.toml | 2 +- .../listing-02-03/src/main.rs | 6 +- .../listing-02-04/Cargo.lock | 16 +- .../listing-02-04/Cargo.toml | 2 +- .../listing-02-04/output.txt | 40 +- .../listing-02-04/src/main.rs | 6 +- .../listing-02-05/Cargo.lock | 16 +- .../listing-02-05/Cargo.toml | 2 +- .../listing-02-05/src/main.rs | 6 +- .../listing-02-06/Cargo.lock | 16 +- .../listing-02-06/Cargo.toml | 2 +- .../listing-02-06/src/main.rs | 4 +- .../no-listing-01-cargo-new/Cargo.lock | 3 +- .../no-listing-02-without-expect/output.txt | 11 +- .../no-listing-02-without-expect/src/main.rs | 2 +- .../Cargo.lock | 16 +- .../Cargo.toml | 2 +- .../src/main.rs | 9 +- .../no-listing-04-looping/Cargo.lock | 16 +- .../no-listing-04-looping/Cargo.toml | 2 +- .../no-listing-04-looping/src/main.rs | 6 +- .../no-listing-05-quitting/Cargo.lock | 16 +- .../no-listing-05-quitting/Cargo.toml | 2 +- .../no-listing-05-quitting/src/main.rs | 6 +- src/ch02-00-guessing-game-tutorial.md | 553 ++++++++++-------- src/ch09-02-recoverable-errors-with-result.md | 2 +- 31 files changed, 402 insertions(+), 424 deletions(-) diff --git a/listings/ch02-guessing-game-tutorial/listing-02-01/src/main.rs b/listings/ch02-guessing-game-tutorial/listing-02-01/src/main.rs index 9f38aa25c..453ce8506 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-01/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/listing-02-01/src/main.rs @@ -25,7 +25,7 @@ fn main() { // ANCHOR_END: expect // ANCHOR: print_guess - println!("You guessed: {}", guess); // 次のように予想しました: {} + println!("You guessed: {guess}"); // 次のように予想しました: {guess} // ANCHOR_END: print_guess } // ANCHOR: all diff --git a/listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.lock b/listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.lock index 0a2f222c2..0fb52b33c 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.lock +++ b/listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "cfg-if" version = "1.0.0" @@ -8,9 +10,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -26,33 +28,32 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.86" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -60,24 +61,15 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.toml b/listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.toml index cc63f6f02..7eda67aea 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.toml +++ b/listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.3" +rand = "0.8.5" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-02/src/main.rs b/listings/ch02-guessing-game-tutorial/listing-02-02/src/main.rs index 60fb2a8e5..b35ed0f2f 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-02/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/listing-02-02/src/main.rs @@ -11,5 +11,5 @@ fn main() { .read_line(&mut guess) .expect("Failed to read line"); - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); } diff --git a/listings/ch02-guessing-game-tutorial/listing-02-03/Cargo.lock b/listings/ch02-guessing-game-tutorial/listing-02-03/Cargo.lock index 0a2f222c2..2ae9e459e 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-03/Cargo.lock +++ b/listings/ch02-guessing-game-tutorial/listing-02-03/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "cfg-if" version = "1.0.0" @@ -38,14 +40,13 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -67,15 +68,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-03/Cargo.toml b/listings/ch02-guessing-game-tutorial/listing-02-03/Cargo.toml index cc63f6f02..7eda67aea 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-03/Cargo.toml +++ b/listings/ch02-guessing-game-tutorial/listing-02-03/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.3" +rand = "0.8.5" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-03/src/main.rs b/listings/ch02-guessing-game-tutorial/listing-02-03/src/main.rs index 164bd46e8..bdacf04b5 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-03/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/listing-02-03/src/main.rs @@ -8,10 +8,10 @@ fn main() { println!("Guess the number!"); // ANCHOR: ch07-04 - let secret_number = rand::thread_rng().gen_range(1..101); + let secret_number = rand::thread_rng().gen_range(1..=100); // ANCHOR_END: ch07-04 - println!("The secret number is: {}", secret_number); //秘密の数字は次の通り: {} + println!("The secret number is: {secret_number}"); //秘密の数字は次の通り: {secret_number} println!("Please input your guess."); @@ -21,7 +21,7 @@ fn main() { .read_line(&mut guess) .expect("Failed to read line"); - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); // ANCHOR: ch07-04 } // ANCHOR_END: ch07-04 diff --git a/listings/ch02-guessing-game-tutorial/listing-02-04/Cargo.lock b/listings/ch02-guessing-game-tutorial/listing-02-04/Cargo.lock index 0a2f222c2..2ae9e459e 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-04/Cargo.lock +++ b/listings/ch02-guessing-game-tutorial/listing-02-04/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "cfg-if" version = "1.0.0" @@ -38,14 +40,13 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -67,15 +68,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-04/Cargo.toml b/listings/ch02-guessing-game-tutorial/listing-02-04/Cargo.toml index cc63f6f02..7eda67aea 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-04/Cargo.toml +++ b/listings/ch02-guessing-game-tutorial/listing-02-04/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.3" +rand = "0.8.5" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-04/output.txt b/listings/ch02-guessing-game-tutorial/listing-02-04/output.txt index 0c4b6f929..91598470c 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-04/output.txt +++ b/listings/ch02-guessing-game-tutorial/listing-02-04/output.txt @@ -5,42 +5,22 @@ $ cargo build Compiling ppv-lite86 v0.2.10 Compiling rand_core v0.6.2 Compiling rand_chacha v0.3.0 - Compiling rand v0.8.3 + Compiling rand v0.8.5 Compiling guessing_game v0.1.0 (file:///projects/guessing_game) error[E0308]: mismatched types (型が合いません) --> src/main.rs:22:21 | 22 | match guess.cmp(&secret_number) { - | ^^^^^^^^^^^^^^ expected struct `String`, found integer - | (構造体`std::string::String`を予期したけど、整数型変数が見つかりました) + | --- ^^^^^^^^^^^^^^ expected `&String`, found `&{integer}` + | | (`&String`を予期したけど、`&{integer}`が見つかりました) + | | + | arguments to this method are incorrect + | (このメソッドへの引数が正しくありません) | = note: expected reference `&String` found reference `&{integer}` +note: method defined here + --> /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/cmp.rs:814:8 -error[E0283]: type annotations needed for `{integer}` - --> src/main.rs:8:44 - | -8 | let secret_number = rand::thread_rng().gen_range(1..101); - | ------------- ^^^^^^^^^ cannot infer type for type `{integer}` - | | - | consider giving `secret_number` a type - | - = note: multiple `impl`s satisfying `{integer}: SampleUniform` found in the `rand` crate: - - impl SampleUniform for i128; - - impl SampleUniform for i16; - - impl SampleUniform for i32; - - impl SampleUniform for i64; - and 8 more -note: required by a bound in `gen_range` - --> /Users/carolnichols/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.8.3/src/rng.rs:129:12 - | -129 | T: SampleUniform, - | ^^^^^^^^^^^^^ required by this bound in `gen_range` -help: consider specifying the type arguments in the function call - | -8 | let secret_number = rand::thread_rng().gen_range::(1..101); - | ++++++++ - -Some errors have detailed explanations: E0283, E0308. -For more information about an error, try `rustc --explain E0283`. -error: could not compile `guessing_game` due to 2 previous errors (先の2つのエラーのため、`guessing_game`をコンパイルできませんでした) +For more information about this error, try `rustc --explain E0308`. +error: could not compile `guessing_game` (bin "guessing_game") due to 1 previous error (先の1つのエラーのため、`guessing_game` (bin "guessing_game") をコンパイルできませんでした) diff --git a/listings/ch02-guessing-game-tutorial/listing-02-04/src/main.rs b/listings/ch02-guessing-game-tutorial/listing-02-04/src/main.rs index d22864972..eadbaf9f2 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-04/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/listing-02-04/src/main.rs @@ -8,9 +8,9 @@ fn main() { // ANCHOR_END: here println!("Guess the number!"); - let secret_number = rand::thread_rng().gen_range(1..101); + let secret_number = rand::thread_rng().gen_range(1..=100); - println!("The secret number is: {}", secret_number); + println!("The secret number is: {secret_number}"); println!("Please input your guess."); @@ -21,7 +21,7 @@ fn main() { .expect("Failed to read line"); // ANCHOR: here - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), //小さすぎ! diff --git a/listings/ch02-guessing-game-tutorial/listing-02-05/Cargo.lock b/listings/ch02-guessing-game-tutorial/listing-02-05/Cargo.lock index 0a2f222c2..2ae9e459e 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-05/Cargo.lock +++ b/listings/ch02-guessing-game-tutorial/listing-02-05/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "cfg-if" version = "1.0.0" @@ -38,14 +40,13 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -67,15 +68,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-05/Cargo.toml b/listings/ch02-guessing-game-tutorial/listing-02-05/Cargo.toml index cc63f6f02..7eda67aea 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-05/Cargo.toml +++ b/listings/ch02-guessing-game-tutorial/listing-02-05/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.3" +rand = "0.8.5" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-05/src/main.rs b/listings/ch02-guessing-game-tutorial/listing-02-05/src/main.rs index 41a4cdd14..12f497e18 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-05/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/listing-02-05/src/main.rs @@ -5,9 +5,9 @@ use std::io; fn main() { println!("Guess the number!"); - let secret_number = rand::thread_rng().gen_range(1..101); + let secret_number = rand::thread_rng().gen_range(1..=100); - println!("The secret number is: {}", secret_number); + println!("The secret number is: {secret_number}"); loop { println!("Please input your guess."); @@ -28,7 +28,7 @@ fn main() { }; // ANCHOR_END: ch19 - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); // --snip-- // ANCHOR_END: here diff --git a/listings/ch02-guessing-game-tutorial/listing-02-06/Cargo.lock b/listings/ch02-guessing-game-tutorial/listing-02-06/Cargo.lock index 0a2f222c2..2ae9e459e 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-06/Cargo.lock +++ b/listings/ch02-guessing-game-tutorial/listing-02-06/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "cfg-if" version = "1.0.0" @@ -38,14 +40,13 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -67,15 +68,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-06/Cargo.toml b/listings/ch02-guessing-game-tutorial/listing-02-06/Cargo.toml index cc63f6f02..7eda67aea 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-06/Cargo.toml +++ b/listings/ch02-guessing-game-tutorial/listing-02-06/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.3" +rand = "0.8.5" diff --git a/listings/ch02-guessing-game-tutorial/listing-02-06/src/main.rs b/listings/ch02-guessing-game-tutorial/listing-02-06/src/main.rs index 30859c70e..7fcbb99fb 100644 --- a/listings/ch02-guessing-game-tutorial/listing-02-06/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/listing-02-06/src/main.rs @@ -5,7 +5,7 @@ use std::io; fn main() { println!("Guess the number!"); - let secret_number = rand::thread_rng().gen_range(1..101); + let secret_number = rand::thread_rng().gen_range(1..=100); loop { println!("Please input your guess."); @@ -21,7 +21,7 @@ fn main() { Err(_) => continue, }; - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), diff --git a/listings/ch02-guessing-game-tutorial/no-listing-01-cargo-new/Cargo.lock b/listings/ch02-guessing-game-tutorial/no-listing-01-cargo-new/Cargo.lock index 5802b7dc9..ee5d79095 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-01-cargo-new/Cargo.lock +++ b/listings/ch02-guessing-game-tutorial/no-listing-01-cargo-new/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "guessing_game" version = "0.1.0" - diff --git a/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/output.txt b/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/output.txt index 0c102c8c7..0905fd9d1 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/output.txt +++ b/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/output.txt @@ -1,14 +1,19 @@ $ cargo build Compiling guessing_game v0.1.0 (file:///projects/guessing_game) warning: unused `Result` that must be used -(警告: 使用されなければならない`std::result::Result`が使用されていません) +(警告: 使用されなければならない`Result`が使用されていません) --> src/main.rs:10:5 | 10 | io::stdin().read_line(&mut guess); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[warn(unused_must_use)]` on by default = note: this `Result` may be an `Err` variant, which should be handled + = note: `#[warn(unused_must_use)]` on by default +help: use `let _ = ...` to ignore the resulting value +(ヘルプ: 結果の値を無視するには `let _ = ...` を使用してください) + | +10 | let _ = io::stdin().read_line(&mut guess); + | +++++++ warning: `guessing_game` (bin "guessing_game") generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 0.59s diff --git a/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/src/main.rs b/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/src/main.rs index aaf90bd65..51046016f 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/src/main.rs @@ -9,5 +9,5 @@ fn main() { io::stdin().read_line(&mut guess); - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); } diff --git a/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/Cargo.lock b/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/Cargo.lock index 0a2f222c2..2ae9e459e 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/Cargo.lock +++ b/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "cfg-if" version = "1.0.0" @@ -38,14 +40,13 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -67,15 +68,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/Cargo.toml b/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/Cargo.toml index cc63f6f02..7eda67aea 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/Cargo.toml +++ b/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.3" +rand = "0.8.5" diff --git a/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/src/main.rs b/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/src/main.rs index cd0962ce9..a4af2240f 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/no-listing-03-convert-string-to-number/src/main.rs @@ -5,9 +5,9 @@ use std::io; fn main() { println!("Guess the number!"); - let secret_number = rand::thread_rng().gen_range(1..101); + let secret_number = rand::thread_rng().gen_range(1..=100); - println!("The secret number is: {}", secret_number); + println!("The secret number is: {secret_number}"); println!("Please input your guess."); @@ -20,10 +20,9 @@ fn main() { .read_line(&mut guess) .expect("Failed to read line"); - let guess: u32 = guess.trim().parse() - .expect("Please type a number!"); //数値を入力してください! + let guess: u32 = guess.trim().parse().expect("Please type a number!"); //数値を入力してください! - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), diff --git a/listings/ch02-guessing-game-tutorial/no-listing-04-looping/Cargo.lock b/listings/ch02-guessing-game-tutorial/no-listing-04-looping/Cargo.lock index 0a2f222c2..2ae9e459e 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-04-looping/Cargo.lock +++ b/listings/ch02-guessing-game-tutorial/no-listing-04-looping/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "cfg-if" version = "1.0.0" @@ -38,14 +40,13 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -67,15 +68,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/listings/ch02-guessing-game-tutorial/no-listing-04-looping/Cargo.toml b/listings/ch02-guessing-game-tutorial/no-listing-04-looping/Cargo.toml index cc63f6f02..7eda67aea 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-04-looping/Cargo.toml +++ b/listings/ch02-guessing-game-tutorial/no-listing-04-looping/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.3" +rand = "0.8.5" diff --git a/listings/ch02-guessing-game-tutorial/no-listing-04-looping/src/main.rs b/listings/ch02-guessing-game-tutorial/no-listing-04-looping/src/main.rs index 61a5dc018..f97d1c58c 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-04-looping/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/no-listing-04-looping/src/main.rs @@ -5,12 +5,12 @@ use std::io; fn main() { println!("Guess the number!"); - let secret_number = rand::thread_rng().gen_range(1..101); + let secret_number = rand::thread_rng().gen_range(1..=100); // ANCHOR: here // --snip-- - println!("The secret number is: {}", secret_number); + println!("The secret number is: {secret_number}"); loop { println!("Please input your guess."); @@ -27,7 +27,7 @@ fn main() { let guess: u32 = guess.trim().parse().expect("Please type a number!"); - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); // ANCHOR: here match guess.cmp(&secret_number) { diff --git a/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/Cargo.lock b/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/Cargo.lock index 0a2f222c2..2ae9e459e 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/Cargo.lock +++ b/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "cfg-if" version = "1.0.0" @@ -38,14 +40,13 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -67,15 +68,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/Cargo.toml b/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/Cargo.toml index cc63f6f02..7eda67aea 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/Cargo.toml +++ b/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.3" +rand = "0.8.5" diff --git a/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/src/main.rs b/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/src/main.rs index 3f8e8b771..def0a0e7e 100644 --- a/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/src/main.rs +++ b/listings/ch02-guessing-game-tutorial/no-listing-05-quitting/src/main.rs @@ -5,9 +5,9 @@ use std::io; fn main() { println!("Guess the number!"); - let secret_number = rand::thread_rng().gen_range(1..101); + let secret_number = rand::thread_rng().gen_range(1..=100); - println!("The secret number is: {}", secret_number); + println!("The secret number is: {secret_number}"); loop { println!("Please input your guess."); @@ -20,7 +20,7 @@ fn main() { let guess: u32 = guess.trim().parse().expect("Please type a number!"); - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); // ANCHOR: here // --snip-- diff --git a/src/ch02-00-guessing-game-tutorial.md b/src/ch02-00-guessing-game-tutorial.md index b90da438d..ed1a080f9 100644 --- a/src/ch02-00-guessing-game-tutorial.md +++ b/src/ch02-00-guessing-game-tutorial.md @@ -8,15 +8,15 @@ Let’s jump into Rust by working through a hands-on project together! This chapter introduces you to a few common Rust concepts by showing you how to use them in a real program. You’ll learn about `let`, `match`, methods, associated -functions, using external crates, and more! In the following chapters, we’ll -explore these ideas in more detail. In this chapter, you’ll practice the +functions, external crates, and more! In the following chapters, we’ll explore +these ideas in more detail. In this chapter, you’ll just practice the fundamentals. --> ハンズオン形式のプロジェクトに一緒に取り組むことで、Rustの世界に飛び込んでみましょう!  この章ではRustの一般的な概念を、実際のプログラムでの使い方を示しながら紹介します。 -`let`、`match`、メソッド、関連関数、外部クレートの使いかたなどについて学びます!  -これらについての詳細は後続の章で取り上げますので、この章では基本的なところを練習します。 +`let`、`match`、メソッド、関連関数、外部クレートなどについて学びます!  +これらについての詳細は後続の章で取り上げますので、この章では基本的なところだけを練習します。 + @@ -166,8 +175,8 @@ prints it このコードには多くの情報が詰め込まれています。 @@ -180,9 +189,9 @@ standard library, known as `std`: ``` Rustはデフォルトで、標準ライブラリで定義されているアイテムの中のいくつかを、すべてのプログラムのスコープに取り込みます。 @@ -198,8 +207,6 @@ user input. 使いたい型がpreludeにない場合は、その型を`use`文で明示的にスコープに入れる必要があります。 `std::io`ライブラリを`use`すると、ユーザ入力を受け付ける機能など(入出力に関する)多くの便利な機能が利用できるようになります。 -[prelude]: https://doc.rust-lang.org/std/prelude/index.html - `fn`構文は関数を新しく宣言し、かっこの`()`は引数がないことを示し、波括弧の`{`は関数の本体を開始します。 @@ -270,13 +277,15 @@ let apples = 5; この行では`apples`という名前の新しい変数を作成し`5`という値に束縛しています。 -Rustでは変数はデフォルトで不変(immutable)になります。 +Rustでは変数はデフォルトで不変(immutable)で、これは一度変数に値を与えたらその値は変わらないという意味です。 この概念については第3章の[「変数と可変性」][variables-and-mutability]の節で詳しく説明します。 変数を可変(mutable)にするには、変数名の前に`mut`をつけます。 @@ -299,7 +308,7 @@ let mut bananas = 5; // mutable @@ -359,20 +366,19 @@ input: ``` -もし、プログラムの最初に`use std::io`と書いて`io`ライブラリをインポートしていなかったとしても、`std::io::stdin`のように呼び出せば、この関数を利用できます。 +もし、プログラムの最初に`use std::io;`と書いて`io`ライブラリをインポートしていなかったとしても、`std::io::stdin`のように呼び出せば、この関数を利用できます。 `stdin`関数はターミナルの標準入力へのハンドルを表す型である[`std::io::Stdin`][iostdin]のインスタンスを返します。 -[iostdin]: https://doc.rust-lang.org/std/io/struct.Stdin.html - + + + この`&`は、この引数が*参照*であることを示し、これによりコードの複数の部分が同じデータにアクセスしても、そのデータを何度もメモリにコピーしなくて済みます。 参照は複雑な機能(訳注:一部のプログラム言語では正しく使うのが難しい機能)ですが、Rustの大きな利点の一つは参照を安全かつ簡単に使用できることです。 このプログラムを完成させるのに、そのような詳細を知る必要はないでしょう。 @@ -408,15 +417,15 @@ thoroughly.) (参照については第4章でより詳しく説明します) -### `Result`型で失敗の可能性を扱う +### `Result`で失敗の可能性を扱う まだ、このコードの行は終わってません。 @@ -450,44 +459,30 @@ discuss what this line does. -前述したように、`read_line`メソッドは渡された文字列にユーザが入力したものを入れます。 -しかし、同時に値(この場合は[`io::Result`][ioresult])も返します。 -Rustの標準ライブラリには`Result`という名前の型がいくつかあります。 -汎用の[`Result`][result]と、`io::Result`といったサブモジュール用の特殊な型などです。 -これらの`Result`型は[*列挙型*][enums]になります。 -列挙型は*enum*とも呼ばれ、取りうる値として決まった数の*列挙子*(variant)を持ちます。 -列挙型はよく`match`と一緒に使われます。 -これは条件式の一種で、評価時に、列挙型の値がどの列挙子であるかに基づいて異なるコードを実行できるという便利なものです。 - -[ioresult]: https://doc.rust-lang.org/std/io/type.Result.html -[result]: https://doc.rust-lang.org/std/result/enum.Result.html +前述したように、`read_line`メソッドは渡された文字列にユーザが入力したものを入れますが、同時に`Result`値も返します。 +`Result`は[*列挙型*][enums]、または*enum*ともよく呼ばれるもののひとつです。 +列挙型は、複数の取りうる状態の中からどれか一つになることができる型です。 +私たちはこのそれぞれの取りうる状態のことを*列挙子* (variant) と呼びます。 -enumについては第6章で詳しく説明します。 +enumについては[第6章][enums]で詳しく説明します。 これらの`Result`型の目的は、エラー処理に関わる情報を符号化(エンコード)することです。 -[enums]: ch06-00-enums.html - `Result`の列挙子は`Ok`か`Err`です。 @@ -496,25 +491,24 @@ why the operation failed. `Result`型の値にも、他の型と同様にメソッドが定義されています。 -`io::Result`のインスタンスには[`expect`メソッド][expect]がありますので、これを呼び出せます。 -この`io::Result`インスタンスが`Err`の値の場合、`expect`メソッドはプログラムをクラッシュさせ、引数として渡されたメッセージを表示します。 +`Result`のインスタンスには[`expect`メソッド][expect]がありますので、これを呼び出せます。 +この`Result`インスタンスが`Err`の値の場合、`expect`メソッドはプログラムをクラッシュさせ、引数として渡されたメッセージを表示します。 `read_line`メソッドが`Err`を返したら、それはおそらく基礎となるオペレーティング・システムに起因するものでしょう。 -もしこの`io::Result`オブジェクトが`Ok`値の場合、`expect`メソッドは`Ok`列挙子が保持する戻り値を取り出して、その値だけを返してくれます。 +もしこの`Result`オブジェクトが`Ok`値の場合、`expect`メソッドは`Ok`列挙子が保持する戻り値を取り出して、その値だけを返してくれます。 こうして私たちはその値を使うことができるわけです。 今回の場合、その値はユーザ入力のバイト数になります。 -[expect]: https://doc.rust-lang.org/std/result/enum.Result.html#method.expect - @@ -533,13 +527,13 @@ indicating that the program hasn’t handled a possible error. Rustは私たちが`read_line`から返された`Result`値を使用していないことを警告し、これはプログラムがエラーの可能性に対処していないことを示します。 -警告を抑制する正しい方法は実際にエラー処理を書くことです。 +警告を抑制する正しい方法は実際にエラー処理コードを書くことです。 しかし、現時点では問題が起きたときにこのプログラムをクラッシュさせたいだけなので、`expect`が使えるわけです。 エラーからの回復については第9章で学びます。 @@ -563,31 +557,33 @@ the code so far: この行はユーザの入力を現在保持している文字列を表示します。 一組の波括弧の`{}`はプレースホルダーです。 `{}`は値を所定の場所に保持する小さなカニのはさみだと考えてください。 -波括弧をいくつか使えば複数の値を表示できます。 -最初の波括弧の組はフォーマット文字列のあとに並んだ最初の値に対応し、2組目は2番目の値、というように続いていきます。 -一回の`println!`の呼び出しで複数の値を表示するなら次のようになります。 +変数の値を表示するときは、変数名を波括弧の中に入れればよいです。 +式の評価結果を表示するときは、フォーマット文字列の中に空の波括弧を置き、それぞれの空の波括弧プレースホルダに表示する式を同じ順で、カンマ区切りリストにして続けてください。 +一回の`println!`の呼び出しで変数と式の結果を表示するなら次のようになります。 ```rust let x = 5; let y = 10; -println!("x = {} and y = {}", x, y); +println!("x = {x} and y + 2 = {}", y + 2); ``` -このコードは`x = 5 and y = 10`と表示するでしょう。 +このコードは`x = 5 and y + 2 = 12`と表示するでしょう。 ```console $ cargo run @@ -642,8 +643,6 @@ said functionality. Rustの標準ライブラリには、まだ乱数の機能は含まれていません。 ですが、Rustの開発チームがこの機能を持つ[`rand`クレート][randcrate]を提供してくれています。 -[randcrate]: https://crates.io/crates/rand - @@ -653,8 +652,8 @@ Rustの標準ライブラリには、まだ乱数の機能は含まれていま クレートはRustソースコードを集めたものであることを思い出してください。 @@ -666,17 +665,22 @@ programs, and can’t be executed on its own. Cargo’s coordination of external crates is where Cargo really shines. Before we can write code that uses `rand`, we need to modify the *Cargo.toml* file to include the `rand` crate as a dependency. Open that file now and add the -following line to the bottom beneath the `[dependencies]` section header that +following line to the bottom, beneath the `[dependencies]` section header that Cargo created for you. Be sure to specify `rand` exactly as we have here, with -this version number, or the code examples in this tutorial may not work. +this version number, or the code examples in this tutorial may not work: --> Cargoがその力を発揮するのは外部クレートと連携するときです。 `rand`を使ったコードを書く前に、*Cargo.toml*ファイルを編集して`rand`クレートを依存関係に含める必要があります。 そのファイルを開いて、Cargoが作ってくれた`[dependencies]`セクションヘッダの下に次の行を追加してください。 バージョンナンバーを含め、ここに書かれている通り正確に`rand`を指定してください。 -そうしないと、このチュートリアルのコード例が動作しないかもしれません。 +そうしないと、このチュートリアルのコード例が動作しないかもしれません: + *Cargo.toml*ファイルでは、ヘッダに続くものはすべて、他のセクションが始まるまで続くセクションの一部になります。 (訳注:Cargo.tomlファイル内には複数のセクションがあり、各セクションは`[ ]`で囲まれたヘッダ行から始まります) `[dependecies]`はプロジェクトが依存する外部クレートと必要とするバージョンをCargoに伝えます。 -今回は`rand`クレートを`0.8.3`というセマンティックバージョン指定子で指定します。 +今回は`rand`クレートを`0.8.5`というセマンティックバージョン指定子で指定します。 Cargoは[セマンティックバージョニング][semver](*SemVer*と呼ばれることもあります)を理解しており、これはバージョンナンバーを記述するための標準です。 -`0.8.3`という数字は実際には`^0.8.3`の省略記法で、`0.8.3`以上`0.9.0`未満の任意のバージョンを意味します。 -Cargoはこれらのバージョンを、バージョン`0.8.3`と互換性のある公開APIを持つものとみなします。 +`0.8.5`という指定子は実際には`^0.8.5`の省略記法で、0.8.5以上0.9.0未満の任意のバージョンを意味します。 + + + +Cargoはこれらのバージョンを、バージョン0.8.5と互換性のある公開APIを持つものとみなします。 この仕様により、この章のコードが引き続きコンパイルできるようにしつつ、最新のパッチリリースを取得できるようになります。 0.9.0以降のバージョンは、以下の例で使用しているものと同じAPIを持つことを保証しません。 -[semver]: http://semver.org - + ```console $ cargo build Updating crates.io index (crates.ioインデックスを更新しています) - Downloaded rand v0.8.3 - (rand v0.8.3をダウンロードしています) - Downloaded libc v0.2.86 - Downloaded getrandom v0.2.2 + Downloaded rand v0.8.5 + (rand v0.8.5をダウンロードしています) + Downloaded libc v0.2.127 + Downloaded getrandom v0.2.7 Downloaded cfg-if v1.0.0 - Downloaded ppv-lite86 v0.2.10 - Downloaded rand_chacha v0.3.0 - Downloaded rand_core v0.6.2 - Compiling rand_core v0.6.2 - (rand_core v0.6.2をコンパイルしています) - Compiling libc v0.2.86 - Compiling getrandom v0.2.2 + Downloaded ppv-lite86 v0.2.16 + Downloaded rand_chacha v0.3.1 + Downloaded rand_core v0.6.3 + Compiling libc v0.2.127 + (libc v0.2.127をコンパイルしています) + Compiling getrandom v0.2.7 Compiling cfg-if v1.0.0 - Compiling ppv-lite86 v0.2.10 - Compiling rand_chacha v0.3.0 - Compiling rand v0.8.3 + Compiling ppv-lite86 v0.2.16 + Compiling rand_core v0.6.3 + Compiling rand_chacha v0.3.1 + Compiling rand v0.8.5 Compiling guessing_game v0.1.0 (file:///projects/guessing_game) (guessing_game v0.1.0をコンパイルしています) Finished dev [unoptimized + debuginfo] target(s) in 2.53s @@ -758,8 +770,8 @@ adding the rand crate as a dependency もしかしたら異なるバージョンナンバー(とはいえ、SemVerのおかげですべてのコードに互換性があります)や、 @@ -777,8 +789,6 @@ post their open source Rust projects for others to use. レジストリとは[Crates.io][cratesio]のデータのコピーです。 Crates.ioは、Rustのエコシステムにいる人たちがオープンソースのRustプロジェクトを投稿し、他の人が使えるようにする場所です。 -[cratesio]: https://crates.io - *src/main.rs*ファイルを開いて些細な変更を加え、それを保存して再度ビルドすると2行しか表示されません。 + + ```console $ cargo build Compiling guessing_game v0.1.0 (file:///projects/guessing_game) @@ -819,7 +834,7 @@ $ cargo build ``` @@ -837,7 +852,7 @@ reuse what it has already downloaded and compiled for those. Cargo has a mechanism that ensures you can rebuild the same artifact every time you or anyone else builds your code: Cargo will use only the versions of the dependencies you specified until you indicate otherwise. For example, say that -next week version 0.8.4 of the `rand` crate comes out, and that version +next week version 0.8.6 of the `rand` crate comes out, and that version contains an important bug fix, but it also contains a regression that will break your code. To handle this, Rust creates the *Cargo.lock* file the first time you run `cargo build`, so we now have this in the *guessing_game* @@ -846,25 +861,27 @@ directory. Cargoはあなたや他の人があなたのコードをビルドするたびに、同じ生成物をリビルドできるようにするしくみを備えています。 Cargoは何も指示されない限り、指定したバージョンの依存のみを使用します。 -たとえば来週`rand`クレートのバージョン0.8.4が出て、そのバージョンには重要なバグ修正が含まれていますが、同時にあなたのコードを破壊するリグレッションも含まれているとします。 +たとえば来週`rand`クレートのバージョン0.8.6が出て、そのバージョンには重要なバグ修正が含まれていますが、同時にあなたのコードを破壊するリグレッションも含まれているとします。 これに対応するため、Rustは`cargo build`を最初に実行したときに*Cargo.lock*ファイルを作成します。 (いまの*guessing_game*ディレクトリにもあるはずです) プロジェクトを初めてビルドするとき、Cargoは条件に合うすべての依存関係のバージョンを計算し*Cargo.lock*ファイルに書き込みます。 -次にプロジェクトをビルドすると、Cargoは*Cargo.lock*ファイルが存在することを確認し、バージョンを把握するすべての作業を再び行う代わりに、そこで指定されているバージョンを使います。 +次にプロジェクトをビルドすると、Cargoは*Cargo.lock*ファイルが存在することを確認し、バージョンを把握するすべての作業を再び行う代わりに、そこで指定されているバージョンを使うでしょう。 これにより再現性のあるビルドを自動的に行えます。 -言い換えれば、*Cargo.lock*ファイルのおかげで、あなたが明示的にアップグレードするまで、プロジェクトは`0.8.3`を使い続けます。 +言い換えれば、*Cargo.lock*ファイルのおかげで、あなたが明示的にアップグレードするまで、プロジェクトは0.8.5を使い続けます。 +*Cargo.lock*ファイルは再現性のあるビルドのために重要なので、プロジェクトの残りのコードとともにソース管理にチェックインされることが多いです。 クレートを*本当に*アップグレードしたくなったときのために、Cargoは`update`コマンドを提供します。 このコマンドは*Cargo.lock*ファイルを無視して、*Cargo.toml*ファイル内の全ての指定に適合する最新バージョンを算出します。 成功したらCargoはそれらのバージョンを*Cargo.lock*ファイルに記録します。 -ただし、デフォルトでCargoは`0.8.3`以上、`0.9.0`未満のバージョンのみを検索します。 -もし`rand`クレートの新しいバージョンとして`0.8.4`と`0.9.0`の二つがリリースされていたなら、`cargo update`を実行したときに以下のようなメッセージが表示されるでしょう。 +ただし、デフォルトでCargoは0.8.5以上、0.9.0未満のバージョンのみを検索します。 +もし`rand`クレートの新しいバージョンとして0.8.6と0.9.0の二つがリリースされていたなら、`cargo update`を実行したときに以下のようなメッセージが表示されるでしょう。 + + ```console $ cargo update Updating crates.io index (crates.ioインデックスを更新しています) - Updating rand v0.8.3 -> v0.8.4 - (randクレートをv0.8.3 -> v0.8.4に更新しています) + Updating rand v0.8.5 -> v0.8.6 + (randクレートをv0.8.5 -> v0.8.6に更新しています) ``` -Cargoは`0.9.0`リリースを無視します。 -またそのとき、*Cargo.lock*ファイルが変更され、`rand`クレートの現在使用中のバージョンが`0.8.4`になったことにも気づくでしょう。 -そうではなく、`rand`のバージョン`0.9.0`か、`0.9.x`系のどれかを使用するには、*Cargo.toml*ファイルを以下のように変更する必要があります。 +Cargoは0.9.0リリースを無視します。 +またそのとき、*Cargo.lock*ファイルが変更され、`rand`クレートの現在使用中のバージョンが0.8.6になったことにも気づくでしょう。 +そうではなく、`rand`のバージョン0.9.0か、0.9.*x*系のどれかを使用するには、*Cargo.toml*ファイルを以下のように変更する必要があります。 ```toml [dependencies] - rand = "0.9.0" ``` @@ -934,9 +955,6 @@ from a number of packages. いまのところは、これだけ知っていれば十分です。 Cargoはライブラリの再利用をとても簡単にしてくれるので、Rustaceanが数多くのパッケージから構成された小さなプロジェクトを書くことが可能になっています。 -[doccargo]: http://doc.crates.io -[doccratesio]: http://doc.crates.io/crates-io.html - @@ -969,44 +987,42 @@ number リスト2-3:乱数を生成するコードの追加 -まず`use rand::Rng`という行を追加します。 +まず`use rand::Rng;`という行を追加します。 `Rng`トレイトは乱数生成器が実装すべきメソッドを定義しており、それらのメソッドを使用するには、このトレイトがスコープ内になければなりません。 トレイトについて詳しくは第10章で解説します。 次に、途中に2行を追加しています。 最初の行では`rand::thread_rng`関数を呼び出して、これから使う、ある特定の乱数生成器を取得しています。 なお、この乱数生成器は現在のスレッドに固有で、オペレーティングシステムからシード値を得ています。 そして、この乱数生成器の`gen_range`メソッドを呼び出しています。 -このメソッドは`use rand::Rng`文でスコープに導入した`Rng`トレイトで定義されています。 +このメソッドは`use rand::Rng;`文でスコープに導入した`Rng`トレイトで定義されています。 `gen_range`メソッドは範囲式を引数にとり、その範囲内の乱数を生成してくれます。 -ここで使っている範囲式の種類は`開始..終了`という形式で、下限値は含みますが上限値は含みません。 +ここで使っている範囲式の種類は`開始..=終了`という形式で、下限値と上限値をともに含みます。 そのため、1から100までの数をリクエストするには`1..101`と指定する必要があります。 -あるいは、これと同等の`1..=100`という範囲を渡すこともできます。 + ```console $ cargo run Compiling guessing_game v0.1.0 (file:///projects/guessing_game) @@ -1070,8 +1094,8 @@ You should get different random numbers, and they should all be numbers between さて、ユーザ入力と乱数が揃ったので両者を比較してみましょう。 @@ -1106,19 +1130,11 @@ the three outcomes that are possible when you compare two values. `Ordering`もenumの一つで`Less`、`Greater`、`Equal`という列挙子を持っています。 これらは二つの値を比較したときに得られる3種類の結果です。 -```rust,ignore -match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), -} -``` - `match`式は複数の*アーム*(腕)で構成されます。 各アームはマッチさせる*パターン*と、`match`に与えられた値がそのアームのパターンにマッチしたときに実行されるコードで構成されます。 Rustは`match`に与えられた値を受け取って、各アームのパターンを順に照合していきます。 -パターンと`match`式はRustの強力な機能で、コードか遭遇する可能性のあるさまざまな状況を表現し、それらすべてを確実に処理できるようにします。 +パターンと`match`式はRustの強力な機能です: コードか遭遇する可能性のあるさまざまな状況を表現し、それらすべてを確実に処理できるようにします。 これらの機能については、それぞれ第6章と第18章で詳しく説明します。 + +ここで使われている`match`式に対して、例を通して順に見ていきましょう。 +たとえばユーザが50と予想し、今回ランダムに生成された秘密の数字は38だったとしましょう。 + + -ここで使われている`match`式に対して、例を通して順に見ていきましょう。 -たとえばユーザが50と予想し、今回ランダムに生成された秘密の数字は38だったとしましょう。 コードが50と38を比較すると、50は38よりも大きいので`cmp`メソッドは`Ordering::Greater`を返します。 `match`式は`Ordering::Greater`の値を取得し、各アームのパターンを吟味し始めます。 まず最初のアームのパターンである`Ordering::Less`を見て、`Ordering::Greater`の値と`Ordering::Less`がマッチしないことがわかります。 そのため、このアームのコードは無視して、次のアームに移ります。 次のアームのパターンは`Ordering::Greater`で、これは`Ordering::Greater`と*マッチ*します!  このアームに関連するコードが実行され、画面に`Too big!`と表示されます。 -このシナリオでは最後のアームと照合する必要がないため`match`式(の評価)は終了します。 +このシナリオでは最初に成功したマッチで`match`式(の評価)は終了し、最後のアームとは照合されません。 + ```console {{#include ../listings/ch02-guessing-game-tutorial/listing-02-04/output.txt}} ``` @@ -1207,8 +1232,8 @@ Rustのデフォルトは`i32`型で、型情報をどこかに追加してRust 最終的にはプログラムが入力として読み込んだ`String`を実数型に変換し、秘密の数字と数値として比較できるようにしたいわけです。 @@ -1236,19 +1261,19 @@ let guess: u32 = guess.trim().parse().expect("Please type a number!"); `guess`という名前の変数を作成しています。 しかし待ってください、このプログラムには既に`guess`という名前の変数がありませんでしたか?  -たしかにありますが、Rustでは`guess`の前の値を新しい値で*覆い隠す*(shadowする)ことが許されているのです。 -シャドーイング(shadowing)は、`guess_str`と`guess`のような重複しない変数を二つ作る代わりに、`guess`という変数名を再利用させてくれるのです。 -これについては第3章で詳しく説明しますが、今のところ、この機能はある型から別の型に値を変換するときによく使われることを知っておいてください。 +たしかにありますが、Rustでは`guess`の前の値を新しい値で覆い隠す(shadowする)ことが許されているのです。 +*シャドーイング*(shadowing)は、`guess_str`と`guess`のような重複しない変数を二つ作る代わりに、`guess`という変数名を再利用させてくれるのです。 +これについては[第3章][shadowing]で詳しく説明しますが、今のところ、この機能はある型から別の型に値を変換するときによく使われることを知っておいてください。 この新しい変数を`guess.trim().parse()`という式に束縛しています。 @@ -1271,60 +1296,71 @@ class="keystroke">enter results in a carriage return and a newline, これは数値データのみを表現できる`u32`型とこの文字列を比較するために(準備として)行う必要があります。 ユーザは予想を入力したあと`read_line`の処理を終えるためにEnterキーを押す必要がありますが、これにより文字列に改行文字が追加されます。 たとえばユーザが5と入力してEnterキーを押すと、`guess`は`5\n`になります。 -この`\n`は「改行」を表しています。(WindowsではEnterキーを押すとキャリッジリターンと改行が入り`\r\n`となります) +この`\n`は「改行」を表しています。(WindowsではEnterキーを押すとキャリッジリターンと改行が入り`\r\n`となります。) `trim`メソッドは`\n`や`\r\n`を削除するので、その結果`5`だけになります。 -[文字列の`parse`メソッド][parse]は文字列をパース(解析)して何らかの数値にします。 -このメソッドは(文字列を)さまざまな数値型へとパースできるので、`let guess: u32`としてRustに正確な数値型を伝える必要があります。 +[文字列の`parse`メソッド][parse]は文字列を別の型に変換します。 +ここでは、私たちは文字列を数値に変換するために使います。 +`let guess: u32`として、Rustに欲しい数値の正確な型を伝える必要があります。 `guess`の後にコロン(`:`)を付けることで変数の型に注釈をつけることをRustに伝えています。 Rustには組み込みの数値型がいくつかあります。 ここにある`u32`は符号なし32ビット整数で、小さな正の数を表すデフォルトの型に適しています。 -他の数値型については第3章で学びます。 +他の数値型については[第3章][integers]で学びます。 + + + さらに、このサンプルプログラムでは、`u32`という注釈と`secret_number`変数との比較していることから、Rustは`secret_number`変数も`u32`型であるべきだと推論しています。 つまり、いまでは二つの同じ型の値を比較することになるわけです! -[parse]: https://doc.rust-lang.org/std/primitive.str.html#method.parse - `parse`メソッドは論理的に数値に変換できる文字にしか使えないので、よくエラーになります。 たとえば文字列に`A👍%`が含まれていたら数値に変換する術はありません。 解析に失敗する可能性があるため、`parse`メソッドは`read_line`メソッドと同様に`Result`型を返します -([「`Result`型で失敗の可能性を扱う」](#result型で失敗の可能性を扱う)で説明しました)  +([「`Result`で失敗の可能性を扱う」](#resultで失敗の可能性を扱う)で説明しました)  今回も`expect`メソッドを使用して`Result`型を同じように扱います。 `parse`メソッドが文字列から数値を作成できなかったために`Result`型の`Err`列挙子を返したら、`expect`の呼び出しはゲームをクラッシュさせ、私たちが与えたメッセージを表示します。 `parse`が文字列をうまく数値へ変換できたときは`Result`型の`Ok`列挙子を返し、`expect`は`Ok`値から欲しい数値を返してくれます。 -さあ、プログラムを走らせましょう! +さあ、プログラムを走らせましょう: + + ```console $ cargo run @@ -1398,7 +1434,8 @@ which actually introduces a new problem. It doesn’t seem like the user can qui The user could always interrupt the program by using the keyboard shortcut ctrl-c. But there’s another way to escape this insatiable monster, as mentioned in the `parse` discussion in [“Comparing the -Guess to the Secret Number”](#comparing-the-guess-to-the-secret-number): if the user enters a non-number answer, the program will crash. We +Guess to the Secret Number”](#comparing-the-guess-to-the-secret-number) +: if the user enters a non-number answer, the program will crash. We can take advantage of that to allow the user to quit, as shown here: --> @@ -1407,6 +1444,15 @@ can take advantage of that to allow the user to quit, as shown here: ユーザが数字以外の答えを入力すればプログラムはクラッシュします。 それを利用して以下のようにすれば終了できます。 + + ```console $ cargo run Compiling guessing_game v0.1.0 (file:///projects/guessing_game) @@ -1435,8 +1481,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` @@ -1511,8 +1557,8 @@ another guess instead of crashing the program @@ -1522,7 +1568,7 @@ method. + ```console $ cargo run Compiling guessing_game v0.1.0 (file:///projects/guessing_game) @@ -1614,17 +1669,17 @@ secret number. Listing 2-6 shows the final code. リスト2-6:数当てゲームの完全なコード -## まとめ +数当てゲームを無事に作り上げることができました。 +おめでとうございます! -数当てゲームを無事に作り上げることができました。 -おめでとうございます! +## まとめ [prelude]: https://doc.rust-lang.org/stable/std/prelude/index.html @@ -1669,7 +1725,6 @@ discusses structs and method syntax, and Chapter 6 explains how enums work. [string]: https://doc.rust-lang.org/stable/std/string/struct.String.html [iostdin]: https://doc.rust-lang.org/stable/std/io/struct.Stdin.html [read_line]: https://doc.rust-lang.org/stable/std/io/struct.Stdin.html#method.read_line -[ioresult]: https://doc.rust-lang.org/stable/std/io/type.Result.html [result]: https://doc.rust-lang.org/stable/std/result/enum.Result.html [enums]: ch06-00-enums.html [expect]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.expect @@ -1677,7 +1732,9 @@ discusses structs and method syntax, and Chapter 6 explains how enums work. [randcrate]: https://crates.io/crates/rand [semver]: http://semver.org [cratesio]: https://crates.io/ -[doccargo]: http://doc.crates.io -[doccratesio]: http://doc.crates.io/crates-io.html +[doccargo]: https://doc.rust-lang.org/cargo/ +[doccratesio]: https://doc.rust-lang.org/cargo/reference/publishing.html [match]: ch06-02-match.html +[shadowing]: ch03-01-variables-and-mutability.html#シャドーイング [parse]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.parse +[integers]: ch03-02-data-types.html#整数型 diff --git a/src/ch09-02-recoverable-errors-with-result.md b/src/ch09-02-recoverable-errors-with-result.md index 65be5fb61..489e7aef7 100644 --- a/src/ch09-02-recoverable-errors-with-result.md +++ b/src/ch09-02-recoverable-errors-with-result.md @@ -25,7 +25,7 @@ defined as having two variants, `Ok` and `Err`, as follows: 第2章の[「`Result`型で失敗する可能性に対処する」][handle_failure]で`Result` enumが以下のように、 `Ok`と`Err`の2列挙子からなるよう定義されていることを思い出してください: -[handle_failure]: ch02-00-guessing-game-tutorial.html#result型で失敗の可能性を扱う +[handle_failure]: ch02-00-guessing-game-tutorial.html#resultで失敗の可能性を扱う ```rust enum Result { From 49f93be9e6f17dac7142d502b9f9937bb454fa88 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:02 +0900 Subject: [PATCH 04/22] =?UTF-8?q?ch03=20=E4=B8=80=E8=88=AC=E7=9A=84?= =?UTF-8?q?=E3=81=AA=E3=83=97=E3=83=AD=E3=82=B0=E3=83=A9=E3=83=9F=E3=83=B3?= =?UTF-8?q?=E3=82=B0=E3=81=AE=E6=A6=82=E5=BF=B5=E3=81=AE=E5=92=8C=E8=A8=B3?= =?UTF-8?q?=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-03-02/src/main.rs | 4 +- .../listing-03-03/src/main.rs | 2 +- .../listing-03-05/src/main.rs | 2 +- .../output.txt | 4 +- .../src/main.rs | 4 +- .../no-listing-02-adding-mut/src/main.rs | 4 +- .../no-listing-03-shadowing/src/main.rs | 4 +- .../output.txt | 8 +- .../src/main.rs | 4 +- .../no-listing-09-char/src/main.rs | 3 +- .../src/main.rs | 2 +- .../src/main.rs | 7 +- .../src/main.rs | 2 +- .../src/main.rs | 2 +- .../output.txt | 24 +- .../src/main.rs | 2 +- .../src/main.rs | 2 +- .../src/main.rs | 2 +- .../output.txt | 4 +- .../src/main.rs | 2 +- .../output.txt | 2 +- .../output.txt | 2 +- .../src/main.rs | 2 +- .../no-listing-32-5-loop-labels/src/main.rs | 6 +- .../src/main.rs | 2 +- .../no-listing-34-for-range/src/main.rs | 2 +- .../output.txt | 18 +- src/ch03-00-common-programming-concepts.md | 14 +- src/ch03-01-variables-and-mutability.md | 280 ++++++------ src/ch03-02-data-types.md | 411 +++++++++++------- src/ch03-03-how-functions-work.md | 196 ++++----- src/ch03-04-comments.md | 33 +- src/ch03-05-control-flow.md | 320 ++++++++------ 33 files changed, 787 insertions(+), 589 deletions(-) diff --git a/listings/ch03-common-programming-concepts/listing-03-02/src/main.rs b/listings/ch03-common-programming-concepts/listing-03-02/src/main.rs index bd5b900c4..9386ad697 100644 --- a/listings/ch03-common-programming-concepts/listing-03-02/src/main.rs +++ b/listings/ch03-common-programming-concepts/listing-03-02/src/main.rs @@ -2,6 +2,6 @@ fn main() { let condition = true; let number = if condition { 5 } else { 6 }; - // numberの値は、{}です - println!("The value of number is: {}", number); + // numberの値は、{number}です + println!("The value of number is: {number}"); } diff --git a/listings/ch03-common-programming-concepts/listing-03-03/src/main.rs b/listings/ch03-common-programming-concepts/listing-03-03/src/main.rs index 568f2bc8e..64720815c 100644 --- a/listings/ch03-common-programming-concepts/listing-03-03/src/main.rs +++ b/listings/ch03-common-programming-concepts/listing-03-03/src/main.rs @@ -2,7 +2,7 @@ fn main() { let mut number = 3; while number != 0 { - println!("{}!", number); + println!("{number}!"); number -= 1; } diff --git a/listings/ch03-common-programming-concepts/listing-03-05/src/main.rs b/listings/ch03-common-programming-concepts/listing-03-05/src/main.rs index 5eaa7a09e..b44e6b7aa 100644 --- a/listings/ch03-common-programming-concepts/listing-03-05/src/main.rs +++ b/listings/ch03-common-programming-concepts/listing-03-05/src/main.rs @@ -2,6 +2,6 @@ fn main() { let a = [10, 20, 30, 40, 50]; for element in a { - println!("the value is: {}", element); + println!("the value is: {element}"); } } diff --git a/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt b/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt index 127a0b902..4e76fa360 100644 --- a/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt +++ b/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt @@ -10,9 +10,9 @@ error[E0384]: cannot assign twice to immutable variable `x` | first assignment to `x` | (`x`への最初の代入) | help: consider making this binding mutable: `mut x` -3 | println!("The value of x is: {}", x); +3 | println!("The value of x is: {x}"); 4 | x = 6; | ^^^^^ cannot assign twice to immutable variable For more information about this error, try `rustc --explain E0384`. -error: could not compile `variables` due to previous error +error: could not compile `variables` (bin "variables") due to 1 previous error diff --git a/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/src/main.rs index 84d0ad8d9..046fbb406 100644 --- a/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/src/main.rs @@ -1,6 +1,6 @@ fn main() { let x = 5; - println!("The value of x is: {}", x); // xの値は{}です + println!("The value of x is: {x}"); // xの値は{x}です x = 6; - println!("The value of x is: {}", x); + println!("The value of x is: {x}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-02-adding-mut/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-02-adding-mut/src/main.rs index c4e4a1953..a57709ccf 100644 --- a/listings/ch03-common-programming-concepts/no-listing-02-adding-mut/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-02-adding-mut/src/main.rs @@ -1,6 +1,6 @@ fn main() { let mut x = 5; - println!("The value of x is: {}", x); + println!("The value of x is: {x}"); x = 6; - println!("The value of x is: {}", x); + println!("The value of x is: {x}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-03-shadowing/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-03-shadowing/src/main.rs index 606ee68a0..03924fe1c 100644 --- a/listings/ch03-common-programming-concepts/no-listing-03-shadowing/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-03-shadowing/src/main.rs @@ -5,8 +5,8 @@ fn main() { { let x = x * 2; - println!("The value of x in the inner scope is: {}", x); + println!("The value of x in the inner scope is: {x}"); } - println!("The value of x is: {}", x); + println!("The value of x is: {x}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt b/listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt index 0bf395c6e..271ed387c 100644 --- a/listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt +++ b/listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt @@ -8,6 +8,12 @@ error[E0308]: mismatched types (型が合いません) 3 | spaces = spaces.len(); | ^^^^^^^^^^^^ expected `&str`, found `usize` | (&str型を予期しましたが、usizeが見つかりました) + | +help: try removing the method call + | +3 - spaces = spaces.len(); +3 + spaces = spaces; + | For more information about this error, try `rustc --explain E0308`. -error: could not compile `variables` due to previous error +error: could not compile `variables` (bin "variables") due to 1 previous error diff --git a/listings/ch03-common-programming-concepts/no-listing-07-numeric-operations/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-07-numeric-operations/src/main.rs index 2bd8f9204..df79eb4f1 100644 --- a/listings/ch03-common-programming-concepts/no-listing-07-numeric-operations/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-07-numeric-operations/src/main.rs @@ -14,8 +14,8 @@ fn main() { // division // 割り算 let quotient = 56.7 / 32.2; - let floored = 2 / 3; // Results in 0 - // 結果は0 + let truncated = -5 / 3; // Results in -1 + // 結果は-1 // remainder // 余り diff --git a/listings/ch03-common-programming-concepts/no-listing-09-char/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-09-char/src/main.rs index b52bd7f5c..1043f3990 100644 --- a/listings/ch03-common-programming-concepts/no-listing-09-char/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-09-char/src/main.rs @@ -1,5 +1,6 @@ fn main() { let c = 'z'; - let z = 'ℤ'; + let z: char = 'ℤ'; // with explicit type annotation + // 明示的型注釈付きで let heart_eyed_cat = '😻'; //ハート目の猫 } diff --git a/listings/ch03-common-programming-concepts/no-listing-11-destructuring-tuples/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-11-destructuring-tuples/src/main.rs index 35dcb442e..3002bdde4 100644 --- a/listings/ch03-common-programming-concepts/no-listing-11-destructuring-tuples/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-11-destructuring-tuples/src/main.rs @@ -3,5 +3,5 @@ fn main() { let (x, y, z) = tup; - println!("The value of y is: {}", y); + println!("The value of y is: {y}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/src/main.rs index a7b70697b..9d1cfcd55 100644 --- a/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/src/main.rs @@ -21,9 +21,6 @@ fn main() { let element = a[index]; - println!( - "The value of the element at index {} is: {}", - // {}番目の要素の値は{}です - index, element - ); + println!("The value of the element at index {index} is: {element}"); + // {index}番目の要素の値は{element}です } diff --git a/listings/ch03-common-programming-concepts/no-listing-17-functions-with-parameters/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-17-functions-with-parameters/src/main.rs index 47655ec8b..e13d54d2e 100644 --- a/listings/ch03-common-programming-concepts/no-listing-17-functions-with-parameters/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-17-functions-with-parameters/src/main.rs @@ -3,5 +3,5 @@ fn main() { } fn another_function(x: i32) { - println!("The value of x is: {}", x); // xの値は{}です + println!("The value of x is: {x}"); // xの値は{x}です } diff --git a/listings/ch03-common-programming-concepts/no-listing-18-functions-with-multiple-parameters/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-18-functions-with-multiple-parameters/src/main.rs index 543c2ea45..b070ccb23 100644 --- a/listings/ch03-common-programming-concepts/no-listing-18-functions-with-multiple-parameters/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-18-functions-with-multiple-parameters/src/main.rs @@ -3,5 +3,5 @@ fn main() { } fn print_labeled_measurement(value: i32, unit_label: char) { - println!("The measurement is: {}{}", value, unit_label); + println!("The measurement is: {value}{unit_label}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt b/listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt index 4cf947530..2f99beed6 100644 --- a/listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt +++ b/listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt @@ -1,23 +1,14 @@ $ cargo run Compiling functions v0.1.0 (file:///projects/functions) -error: expected expression, found statement (`let`) -(エラー: 式を予期しましたが、文が見つかりました (`let`)) +error: expected expression, found `let` statement +(エラー: 式を予期しましたが、`let`文が見つかりました) --> src/main.rs:2:14 | 2 | let x = (let y = 6); - | ^^^^^^^^^ + | ^^^ | - = note: variable declaration using `let` is a statement - (注釈: `let`を使う変数宣言は、文です) - -error[E0658]: `let` expressions in this position are experimental - --> src/main.rs:2:14 - | -2 | let x = (let y = 6); - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: you can write `matches!(, )` instead of `let = ` + = note: only supported directly in conditions of `if` and `while` expressions + (注釈: `if` および `while` 式の条件部直下でのみ対応しています warning: unnecessary parentheses around assigned value --> src/main.rs:2:13 @@ -30,8 +21,7 @@ help: remove these parentheses | 2 - let x = (let y = 6); 2 + let x = let y = 6; - | + | -For more information about this error, try `rustc --explain E0658`. warning: `functions` (bin "functions") generated 1 warning -error: could not compile `functions` due to 2 previous errors; 1 warning emitted +error: could not compile `functions` (bin "functions") due to 1 previous error; 1 warning emitted diff --git a/listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs index 0be7fcbf3..64b873297 100644 --- a/listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs @@ -4,5 +4,5 @@ fn main() { x + 1 }; - println!("The value of y is: {}", y); + println!("The value of y is: {y}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-21-function-return-values/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-21-function-return-values/src/main.rs index 5303b1082..a11af7ec7 100644 --- a/listings/ch03-common-programming-concepts/no-listing-21-function-return-values/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-21-function-return-values/src/main.rs @@ -5,5 +5,5 @@ fn five() -> i32 { fn main() { let x = five(); - println!("The value of x is: {}", x); + println!("The value of x is: {x}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-22-function-parameter-and-return/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-22-function-parameter-and-return/src/main.rs index b4c84437a..da9d0ddb3 100644 --- a/listings/ch03-common-programming-concepts/no-listing-22-function-parameter-and-return/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-22-function-parameter-and-return/src/main.rs @@ -1,7 +1,7 @@ fn main() { let x = plus_one(5); - println!("The value of x is: {}", x); + println!("The value of x is: {x}"); } fn plus_one(x: i32) -> i32 { diff --git a/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt b/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt index 7a684650a..d13b1c891 100644 --- a/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt +++ b/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt @@ -9,7 +9,7 @@ error[E0308]: mismatched types | | | implicitly returns `()` as its body has no tail or `return` expression 8 | x + 1; - | - help: consider removing this semicolon + | - help: remove this semicolon to return this value For more information about this error, try `rustc --explain E0308`. -error: could not compile `functions` due to previous error +error: could not compile `functions` (bin "functions") due to 1 previous error diff --git a/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/src/main.rs index c9c4edc19..1cec800b6 100644 --- a/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/src/main.rs @@ -1,7 +1,7 @@ fn main() { let x = plus_one(5); - println!("The value of x is: {}", x); + println!("The value of x is: {x}"); } fn plus_one(x: i32) -> i32 { diff --git a/listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt b/listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt index 3a43db713..e8f033d36 100644 --- a/listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt +++ b/listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt @@ -9,4 +9,4 @@ error[E0308]: mismatched types | (bool型を予期したのに、整数変数が見つかりました) For more information about this error, try `rustc --explain E0308`. -error: could not compile `branches` due to previous error +error: could not compile `branches` (bin "branches") due to 1 previous error diff --git a/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt b/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt index a236054af..7e11035d3 100644 --- a/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt +++ b/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt @@ -11,4 +11,4 @@ error[E0308]: `if` and `else` have incompatible types | expected because of this For more information about this error, try `rustc --explain E0308`. -error: could not compile `branches` due to previous error +error: could not compile `branches` (bin "branches") due to 1 previous error diff --git a/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/src/main.rs index 440b286f5..df7068bcf 100644 --- a/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/src/main.rs @@ -3,5 +3,5 @@ fn main() { let number = if condition { 5 } else { "six" }; - println!("The value of number is: {}", number); + println!("The value of number is: {number}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/src/main.rs index b855d7576..dd8856403 100644 --- a/listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/src/main.rs @@ -1,11 +1,11 @@ fn main() { let mut count = 0; 'counting_up: loop { - println!("count = {}", count); + println!("count = {count}"); let mut remaining = 10; loop { - println!("remaining = {}", remaining); + println!("remaining = {remaining}"); if remaining == 9 { break; } @@ -17,5 +17,5 @@ fn main() { count += 1; } - println!("End count = {}", count); + println!("End count = {count}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-33-return-value-from-loop/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-33-return-value-from-loop/src/main.rs index 6ffdab5a4..683d18bc1 100644 --- a/listings/ch03-common-programming-concepts/no-listing-33-return-value-from-loop/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-33-return-value-from-loop/src/main.rs @@ -9,5 +9,5 @@ fn main() { } }; - println!("The result is {}", result); + println!("The result is {result}"); } diff --git a/listings/ch03-common-programming-concepts/no-listing-34-for-range/src/main.rs b/listings/ch03-common-programming-concepts/no-listing-34-for-range/src/main.rs index e7286a84e..df5b305bc 100644 --- a/listings/ch03-common-programming-concepts/no-listing-34-for-range/src/main.rs +++ b/listings/ch03-common-programming-concepts/no-listing-34-for-range/src/main.rs @@ -1,6 +1,6 @@ fn main() { for number in (1..4).rev() { - println!("{}!", number); + println!("{number}!"); } println!("LIFTOFF!!!"); } diff --git a/listings/ch03-common-programming-concepts/output-only-01-no-type-annotations/output.txt b/listings/ch03-common-programming-concepts/output-only-01-no-type-annotations/output.txt index 8072cd10f..ded0312d5 100644 --- a/listings/ch03-common-programming-concepts/output-only-01-no-type-annotations/output.txt +++ b/listings/ch03-common-programming-concepts/output-only-01-no-type-annotations/output.txt @@ -1,12 +1,20 @@ $ cargo build Compiling no_type_annotations v0.1.0 (file:///projects/no_type_annotations) -error[E0282]: type annotations needed +error[E0284]: type annotations needed (型注釈が必要です) --> src/main.rs:2:9 | 2 | let guess = "42".parse().expect("Not a number!"); - | ^^^^^ consider giving `guess` a type - | (`guess`に型を与えることを検討してください) + | ^^^^^ ----- type must be known at this point + | (型はこの時点で既知でなくてはなりません) + | + = note: cannot satisfy `<_ as FromStr>::Err == _` + (`<_ as FromStr>::Err == _`を満たすことができません) +help: consider giving `guess` an explicit type + | (`guess`に型を与えることを検討してください) + | +2 | let guess: /* Type */ = "42".parse().expect("Not a number!"); + | ++++++++++++ -For more information about this error, try `rustc --explain E0282`. -error: could not compile `no_type_annotations` due to previous error +For more information about this error, try `rustc --explain E0284`. +error: could not compile `no_type_annotations` (bin "no_type_annotations") due to 1 previous error diff --git a/src/ch03-00-common-programming-concepts.md b/src/ch03-00-common-programming-concepts.md index 6b9f54805..9477e66ed 100644 --- a/src/ch03-00-common-programming-concepts.md +++ b/src/ch03-00-common-programming-concepts.md @@ -27,21 +27,23 @@ them early will give you a strong core to start from. これらの基礎は全てのRustプログラムに存在するものであり、それらを早期に学ぶことにより、強力な基礎を築くことになるでしょう。 -> ### キーワード +> #### キーワード > > Rust言語にも他の言語同様、キーワードが存在し、これらは言語だけが使用できるようになっています。 > これらの単語は、変数や関数名には使えないことを弁えておいてください。ほとんどのキーワードは、特別な意味を持っており、 > 自らのRustプログラムにおいて、様々な作業をこなすために使用することができます; > いくつかは、紐付けられた機能がないものの、将来Rustに追加されるかもしれない機能用に予約されています。 > キーワードの一覧は、付録Aで確認できます。 + +[appendix_a]: appendix-01-keywords.md diff --git a/src/ch03-01-variables-and-mutability.md b/src/ch03-01-variables-and-mutability.md index 77fd81a7d..0172e9a56 100644 --- a/src/ch03-01-variables-and-mutability.md +++ b/src/ch03-01-variables-and-mutability.md @@ -5,32 +5,33 @@ ## 変数と可変性 -第2章で触れた通り、変数は標準で不変になります。これは、 +[「値を変数に保持する」][storing-values-with-variables]の節で触れた通り、変数は標準で不変になります。これは、 Rustが提供する安全性や簡便な並行性の利点を享受する形でコードを書くための選択の1つです。 ところが、まだ変数を可変にするという選択肢も残されています。 どのように、そしてなぜRustは不変性を推奨するのか、さらには、なぜそれとは違う道を選びたくなることがあるのか見ていきましょう。 変数が不変であると、値が一旦名前に束縛されたら、その値を変えることができません。 -これを具体的に説明するために、*projects*ディレクトリに`cargo new --bin variables`コマンドを使って、 -*variables*という名前のプロジェクトを生成しましょう。 +これを具体的に説明するために、*projects*ディレクトリに`cargo new variables`コマンドを使って、 +*variables*という名前のプロジェクトを生成してください。 それから、新規作成した*variables*ディレクトリで、*src/main.rs*ファイルを開き、 @@ -47,11 +48,12 @@ code with the following code that won't compile just yet: ``` -これを保存し、`cargo run`コマンドでプログラムを走らせてください。次の出力に示されているようなエラーメッセージを受け取るはずです: +これを保存し、`cargo run`コマンドでプログラムを走らせてください。 +次の出力に示されているような、不変性に関するエラーメッセージを受け取るはずです: ```console {{#include ../listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt}} @@ -59,68 +61,66 @@ message, as shown in this output: この例では、コンパイラがプログラムに潜むエラーを見つけ出す手助けをしてくれることが示されています。 -コンパイルエラーは、イライラすることもあるものですが、まだプログラムにしてほしいことを安全に行えていないだけということなのです。 +コンパイルエラーは、イライラすることもあるものですが、本当はまだプログラムにしてほしいことを安全に行えていないだけということなのです。 エラーが出るからといって、あなたがいいプログラマではないという意味ではあり*ません*! 経験豊富なRustaceanでも、コンパイルエラーを出すことはあります。 -このエラーは、エラーの原因が`不変変数xに2回代入できない`であると示しています。不変な`x`という変数に別の値を代入しようとしたからです。 +``不変変数`x`に2回代入できません``というエラーメッセージを受け取りました。 +不変な`x`という変数に別の値を代入しようとしたからです。 -以前に不変と指定された値を変えようとした時に、コンパイルエラーが出るのは重要なことです。 +不変と指定された値を変えようとした時に、コンパイルエラーが出るのは重要なことです。 なぜなら、この状況はまさしく、バグに繋がるからです。コードのある部分は、 値が変わることはないという前提のもとに処理を行い、別の部分がその値を変更していたら、 最初の部分が目論見通りに動いていない可能性があるのです。このようなバグは、発生してしまってからでは原因が追いかけづらいものです。 特に第2のコード片が、値を*時々*しか変えない場合、尚更です。 - - - -Rustでは、値が不変であると宣言したら、本当に変わらないことをコンパイラが担保してくれます。 -つまり、コードを読み書きする際に、どこでどうやって値が変化しているかを追いかける必要がなくなります。 +Rustコンパイラは、値が不変であると宣言したら、本当に変わらないことを担保してくれるので、変更を自分で追いかける必要がなくなります。 故にコードを通して正しいことを確認するのが簡単になるのです。 -しかし、可変性は時として非常に有益なこともあります。変数は、標準でのみ、不変です。つまり、 -第2章のように変数名の前に`mut`キーワードを付けることで、可変にできるわけです。この値が変化できるようにするとともに、 -`mut`により、未来の読者に対してコードの別の部分がこの変数の値を変える可能性を示すことで、その意図を汲ませることができるのです。 +しかし可変性は非常に有用で、よりコードを書きやすくしてくれることもあります。 +変数は標準では不変ですが、[第2章][storing-values-with-variables]でやったように、 +変数名の前に`mut`キーワードを付けることで、可変にできるわけです。 +また`mut`を付けることで、コードの別の部分がこの変数の値を変えるだろうと示すことによって、 +未来の読者に対してその意図を汲ませることができるのです。 -例として、*src/main.rs*ファイルを以下のように書き換えてください: +例として、*src/main.rs*ファイルを以下のように書き換えましょう: -`mut`キーワードが使われると、`x`が束縛している値を`5`から`6`に変更できます。 -変数を可変にする方が、不変変数だけがあるよりも書きやすくなるので、変数を可変にしたくなることもあるでしょう。 +`mut`キーワードが使われると、`x`に束縛されている値を`5`から`6`に変更できます。 +可変性を使うかどうかは最終的にはプログラマに任せられており、どちらがより明白と思えるかは個別の状況によるでしょう。 -考えるべきトレードオフはバグの予防以外にも、いくつかあります。例えば、大きなデータ構造を使う場合などです。 -インスタンスを可変にして変更できるようにする方が、いちいちインスタンスをコピーして新しくメモリ割り当てされたインスタンスを返すよりも速くなります。 -小規模なデータ構造なら、新規インスタンスを生成して、もっと関数型っぽいコードを書く方が通して考えやすくなるため、 -低パフォーマンスは、その簡潔性を得るのに足りうるペナルティになるかもしれません。 +### 定数 -### 変数と定数(constants)の違い - - - -変数の値を変更できないようにするといえば、他の多くの言語も持っている別のプログラミング概念を思い浮かべるかもしれません: -*定数*です。不変変数のように、定数は名前に束縛され、変更することが叶わない値のことですが、 +不変変数のように、*定数*(constants)は名前に束縛され、変更することが叶わない値のことですが、 定数と変数の間にはいくつかの違いがあります。 まず、定数には`mut`キーワードは使えません: 定数は標準で不変であるだけでなく、常に不変なのです。 - - - 定数は`let`キーワードの代わりに、`const`キーワードで宣言し、値の型は*必ず*注釈しなければなりません。 -型と型注釈については次のセクション、「データ型」で講義しますので、その詳細について気にする必要はありません。 +型と型注釈については次のセクション、[「データ型」][data-types]で講義しますので、その詳細について気にする必要はありません。 ただ単に型は常に注釈しなければならないのだと思っていてください。 -最後の違いは、定数は定数式にしかセットできないことです。関数呼び出し結果や、実行時に評価される値にはセットできません。 +最後の違いは、定数は定数式にしかセットできないことです。実行時に評価される値にはセットできません。 -定数の名前が`MAX_POINTS`で、値が100,000にセットされた定数定義の例をご覧ください。(Rustの定数の命名規則は、 -全て大文字でアンダースコアで単語区切りすることです): +これが定数定義の例です: ```rust -const MAX_POINTS: u32 = 100_000; +const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3; ``` -定数は、プログラムが走る期間、定義されたスコープ内でずっと有効です。従って、 -プログラムのいろんなところで使用される可能性のあるアプリケーション空間の値を定義するのに有益な選択肢になります。 +定数の名前は`THREE_HOURS_IN_SECONDS`で、その値は60(1分あたりの秒数)×60(1時間あたりの分数)×3(このプログラムで数えたい時間数)の結果にセットされています。 +Rustの定数の命名規則は、全て大文字でアンダースコアで単語区切りすることです。 +コンパイラはコンパイル時に一部の演算を評価することができるので、この定数に10,800という値を設定する代わりに、理解し検証しやすい方法でこの値を書き出すことを選択できます。 +定数宣言内でどの演算が使用できるかについてのさらなる情報は、[Rust Referenceのconstant evaluationの節][const-eval]をお読みください。 + + + +定数は、プログラムが走る期間、定義されたスコープ内でずっと有効です。 +この性質のおかげで、定数はプログラムのいろんなところで使用される可能性のあるアプリケーション空間の値を定義するのに有用です。 例えば、ゲームでプレイヤーが取得可能なポイントの最高値や、光速度などですね。 -第2章の数当てゲームのチュートリアル、「予想と秘密の数字を比較する」節で見たように、前に定義した変数と同じ名前の変数を新しく宣言でき、 -新しい変数は、前の変数を覆い隠します。Rustaceanはこれを最初の変数は、 -2番目の変数に*覆い隠さ*れたと言い、この変数を使用した際に、2番目の変数の値が現れるということです。 +[第2章][comparing-the-guess-to-the-secret-number]の数当てゲームのチュートリアルで見たように、 +前に定義した変数と同じ名前の変数を新しく宣言できます。 +Rustaceanはこれを、最初の変数は2番目の変数に*覆い隠さ*れたと言います。 +これはその変数名を使用した際に、コンパイラは2番目の変数を見るという意味です。 +2番目の変数は実質的に、最初の変数にその影を投げかけ、自身が覆い隠されるかスコープが終了するまで、 +変数名の使用を自身へのものとして扱います。 以下のようにして、同じ変数名を用いて変数を覆い隠し、`let`キーワードの使用を繰り返します: -このプログラムはまず、`x`を`5`という値に束縛します。それから`let x =`を繰り返すことで`x`を覆い隠し、 +このプログラムはまず、`x`を`5`という値に束縛します。それから`let x =`を繰り返すことで新しい変数`x`を作り、 元の値に`1`を加えることになるので、`x`の値は`6`になります。 -3番目の`let`文も`x`を覆い隠し、以前の値に`2`をかけることになるので、`x`の最終的な値は`12`になります。 -括弧を抜けるとシャドーイングは終了し、`x`の値は元の`6`に戻ります。 +次に波括弧によって作られた内側のスコープの中で、3番目の`let`文も`x`を覆い隠して新しい変数を作り、 +以前の値に`2`をかけることになるので、`x`の最終的な値は`12`になります。 +スコープが終わるとシャドーイングは終了し、`x`の値は元の`6`に戻ります。 このプログラムを走らせたら、以下のように出力するでしょう: ```console @@ -304,7 +305,7 @@ When we run this program, it will output the following: ``` `mut`と上書きのもう一つの違いは、再度`let`キーワードを使用したら、実効的には新しい変数を生成していることになるので、 値の型を変えつつ、同じ変数名を使いまわせることです。例えば、 -プログラムがユーザに何らかのテキストに対して空白文字を入力することで何個分のスペースを表示したいかを尋ねますが、 -ただ、実際にはこの入力を数値として保持したいとしましょう: +プログラムがユーザに何らかのテキストに対して空白文字を入力することで何個分のスペースを表示したいかを尋ねて、 +そうしたらこの入力を数値として保持したいとしましょう: ```rust {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-04-shadowing-can-change-types/src/main.rs:here}} ``` -この文法要素は、容認されます。というのも、最初の`spaces`変数は文字列型であり、2番目の`spaces`変数は、 -たまたま最初の変数と同じ名前になったまっさらな変数のわけですが、数値型になるからです。故に、シャドーイングのおかげで、 +最初の`spaces`変数は文字列型であり、2番目の`spaces`変数は数値型です。故に、シャドーイングのおかげで、 異なる名前を思いつく必要がなくなるわけです。`spaces_str`と`spaces_num`などですね; 代わりに、 よりシンプルな`spaces`という名前を再利用できるわけです。一方で、この場合に`mut`を使おうとすると、 以下に示した通りですが、コンパイルエラーになるわけです: @@ -352,8 +351,7 @@ try to use `mut` for this, as shown here, we'll get a compile-time error: ``` 変数の型を可変にすることは許されていないと言われているわけです: @@ -368,3 +366,17 @@ can have. --> さあ、変数が動作する方法を見てきたので、今度は変数が取りうるデータ型について見ていきましょう。 + + + +[comparing-the-guess-to-the-secret-number]: +ch02-00-guessing-game-tutorial.html#予想と秘密の数字を比較する +[data-types]: ch03-02-data-types.html#データ型 +[storing-values-with-variables]: ch02-00-guessing-game-tutorial.html#値を変数に保持する +[const-eval]: https://doc.rust-lang.org/reference/const_eval.html diff --git a/src/ch03-02-data-types.md b/src/ch03-02-data-types.md index eb7486ce5..7d8f93849 100644 --- a/src/ch03-02-data-types.md +++ b/src/ch03-02-data-types.md @@ -6,7 +6,7 @@ @@ -18,14 +18,15 @@ Keep in mind that Rust is a *statically typed* language, which means that it must know the types of all variables at compile time. The compiler can usually infer what type we want to use based on the value and how we use it. In cases when many types are possible, such as when we converted a `String` to a numeric -type using `parse` in the “Comparing the Guess to the Secret Number” section in +type using `parse` in the [“Comparing the Guess to the Secret +Number”][comparing-the-guess-to-the-secret-number] section in Chapter 2, we must add a type annotation, like this: --> Rustは*静的型付き*言語であることを弁えておいてください。つまり、 コンパイル時に全ての変数の型が判明している必要があるということです。コンパイラは通常、値と使用方法に基づいて、 使用したい型を推論してくれます。複数の型が推論される可能性がある場合、例えば、 -第2章の「予想と秘密の数字を比較する」節で`parse`メソッドを使って`String`型を数値型に変換した時のように、 +第2章の[「予想と秘密の数字を比較する」][comparing-the-guess-to-the-secret-number]節で`parse`メソッドを使って`String`型を数値型に変換した時のように、 複数の型が可能な場合には、型注釈をつけなければいけません。以下のようにですね: ```rust @@ -33,12 +34,12 @@ let guess: u32 = "42".parse().expect("Not a number!"); // 数字ではあり ``` -ここで型注釈を付けなければ、コンパイラは以下のエラーを表示し、これは可能性のある型のうち、 +上のコード中に示す`: u32`型注釈を付けなければ、コンパイラは以下のエラーを表示し、これは可能性のある型のうち、 どの型を使用したいのかを知るのに、コンパイラがプログラマからもっと情報を得る必要があることを意味します: ```console @@ -63,7 +64,7 @@ integers, floating-point numbers, Booleans, and characters. You may recognize these from other programming languages. Let’s jump into how they work in Rust. --> -スカラー型は、単独の値を表します。Rustには主に4つのスカラー型があります: +*スカラー*型は、単独の値を表します。Rustには主に4つのスカラー型があります: 整数、浮動小数点数、論理値、最後に文字です。他のプログラミング言語でも、これらの型を見かけたことはあるでしょう。 Rustでの動作方法に飛び込みましょう。 @@ -78,15 +79,14 @@ An *integer* is a number without a fractional component. We used one integer type in Chapter 2, the `u32` type. This type declaration indicates that the value it’s associated with should be an unsigned integer (signed integer types start with `i` instead of `u`) that takes up 32 bits of space. Table 3-1 shows -the built-in integer types in Rust. Each variant in the Signed and Unsigned -columns (for example, `i16`) can be used to declare the type of an integer -value. +the built-in integer types in Rust. We can use any of these variants to declare +the type of an integer value. --> -整数とは、小数部分のない数値のことです。第2章で一つの整数型を使用しましたね。`u32`型です。 +*整数*とは、小数部分のない数値のことです。第2章で一つの整数型を使用しましたね。`u32`型です。 この型定義は、紐付けられる値が、符号なし整数(符号付き整数は`u`ではなく、`i`で始まります)になり、 これは、32ビット分のサイズを取ります。表3-1は、Rustの組み込み整数型を表示しています。 -符号付きと符号なし欄の各バリアント(例: `i16`)を使用して、整数値の型を宣言することができます。 +これらのバリアントを使用して、整数値の型を宣言することができます。 | 大きさ | 符号付き | 符号なし | -|--------|---------|---------| -| 8-bit | `i8` | `u8` | -| 16-bit | `i16` | `u16` | -| 32-bit | `i32` | `u32` | -| 64-bit | `i64` | `u64` | -| arch | `isize` | `usize` | +|---------|----------|----------| +| 8-bit | `i8` | `u8` | +| 16-bit | `i16` | `u16` | +| 32-bit | `i32` | `u32` | +| 64-bit | `i64` | `u64` | +| 128-bit | `i128` | `u128` | +| arch | `isize` | `usize` | 各バリアントは、符号付きか符号なしかを選べ、明示的なサイズを持ちます。*符号付き*と*符号なし*は、 -数値が正負を持つかどうかを示します。つまり、数値が符号を持つ必要があるかどうか(符号付き)、または、 +数値が負の数になり得るかどうかを示します。つまり、数値が符号を持つ必要があるかどうか(符号付き)、または、 絶対に正数にしかならず符号なしで表現できるかどうか(符号なし)です。これは、数値を紙に書き下すのと似ています: 符号が問題になるなら、数値はプラス記号、またはマイナス記号とともに表示されます; しかしながら、 その数値が正数であると仮定することが安全なら、符号なしで表示できるわけです。符号付き数値は、 -2の補数表現で保持されます(これが何なのか確信を持てないのであれば、ネットで検索することができます。 -まあ要するに、この解説は、この本の範疇外というわけです)。 +[2の補数][twos-complement]表現で保持されます。 -加えて、`isize`と`usize`型は、プログラムが動作しているコンピュータの種類に依存します: +加えて、`isize`と`usize`型は、表では「arch」と表記していますが、プログラムが動作しているコンピュータのアーキテクチャに依存します: 64ビットアーキテクチャなら、64ビットですし、32ビットアーキテクチャなら、32ビットになります。 整数リテラル(`訳注`: リテラルとは、見たままの値ということ)は、表3-2に示すどの形式でも記述することができます。 -バイトリテラルを除く数値リテラルは全て、 -型接尾辞(例えば、`57u8`)と`_`を見た目の区切り記号(例えば、`1_000`)に付加することができます。 +複数の数値型になることができる数値リテラルは、型を指示するために型接尾辞をつけて、`57u8`のように書くことができます。 +数値リテラルはさらに、数値を読みやすくするために見た目の区切り記号として`_`をつけて、`1_000`のように書くこともできます。 +これは`1000`と指定した場合とまったく同じ値となるでしょう。 -| 数値リテラル | 例 | -|------------------|---------------| +| 数値リテラル | 例 | +|-------------------|---------------| | 10進数 | `98_222` | | 16進数 | `0xff` | | 8進数 | `0o77` | | 2進数 | `0b1111_0000` | -| バイト (`u8`だけ) | `b'A'` | +| バイト (`u8`だけ) | `b'A'` | では、どの整数型を使うべきかはどう把握すればいいのでしょうか?もし確信が持てないのならば、 -Rustの基準型は一般的にいい選択肢になります。整数型の基準は`i32`型です: 64ビットシステム上でも、 -この型が普通最速になります。`isize`と`usize`を使う主な状況は、何らかのコレクションにアクセスすることです。 +Rustの基準型は一般的にいい開始地点になります: 整数型の基準は`i32`型です。 +`isize`と`usize`を使う主な状況は、何らかのコレクションにアクセスすることです。 + + + +> ##### 整数オーバーフロー +> +> `u8`型の変数があるとしましょう。`u8`は0から255までの間の値を取ることができます。 +> この変数を範囲外の値、例えば256に変更しようとすると、*整数オーバーフロー (integer overflow)* が発生し、次の2つのうちのどちらかの挙動になります。 +> デバッグモードでコンパイルしているときは、もしこの挙動が発生したときは実行時にプログラムを*パニック (panic)* させるような、整数オーバーフローのチェックをコンパイラが入れ込みます。 +> プログラムがエラーとともに終了するとき、Rustは*パニック*という用語を使用します; +> パニックについては第9章の[「`panic!`で回復不能なエラー」][unrecoverable-errors-with-panic]でより深く議論します。 +> +> `--release`フラグを付けてリリースモードでコンパイルしているときは、コンパイラはパニックを引き起こす整数オーバーフローチェックを入れ込み*ません*。 +> 代わりに、オーバーフローが起きたときは、プログラムは*2の補数ラップアラウンド (two's complement wrapping)* を行います。 +> 一言で言うと、その型が取ることができる最大値よりも大きい値は、その型が取ることができる最小値に「回り込む」 (“wrap around”) のです。 +> `u8`の場合は、値256は0になり、値257は1になり、という感じです。 +> プログラムはパニックはしなくなるでしょうが、変数が持っている値はおそらくプログラマが期待していたものではないでしょう。 +> 整数オーバーフローのラップアラウンドの挙動に依存するのは、エラーと考えられます。 +> +> オーバーフローが発生する可能性を明示的に取り扱うためには、プリミティブ数値型に関して標準ライブラリが提供する、以下のメソッド群を使うことができます: +> +> * `wrapping_*`メソッド(`wrapping_add`等)で、モードを問わずラップアラウンドさせる。 +> * `checked_*`メソッドで、オーバーフローが発生する場合には`None`値を返す。 +> * `overflowing_*`メソッドで、値と、オーバーフローが発生したかどうかを示す論理値を返す。 +> * `saturating_*`メソッドで、値の最小値または最大値で飽和させる。(訳注: 結果が最大値を上回る場合は最大値に、最小値を下回る場合は最小値にするという意味です) Rustにはさらに、*浮動小数点数*に対しても、2種類の基本型があり、浮動小数点数とは数値に小数点がついたもののことです。 Rustの浮動小数点型は、`f32`と`f64`で、それぞれ32ビットと64ビットサイズです。基準型は`f64`です。 なぜなら、現代のCPUでは、`f32`とほぼ同スピードにもかかわらず、より精度が高くなるからです。 +すべての浮動小数点型は符号付きです。 Rustにも全数値型に期待されうる標準的な数学演算が用意されています: 足し算、引き算、掛け算、割り算、余りです。 -以下の例では、`let`文での各演算の使用方法をご覧になれます: +整数の割り算では、0に近い方の最も近い整数に切り捨てられます。 +以下の例では、`let`文での各数学演算の使用方法をご覧になれます: これらの文の各式は、数学演算子を使用しており、一つの値に評価され、そして、変数に束縛されます。 -付録BにRustで使える演算子の一覧が載っています。 +[付録B][appendix_b]にRustで使える演算子の一覧が載っています。 他の多くの言語同様、Rustの論理値型も取りうる値は二つしかありません: `true`と`false`です。 +論理値のサイズは1バイトです。 Rustの論理値型は、`bool`と指定されます。 例です: @@ -304,12 +368,12 @@ Rustの論理値型は、`bool`と指定されます。 論理値を使う主な手段は、条件式です。例えば、`if`式などですね。`if`式のRustでの動作方法については、 -「制御フロー」節で講義します。 +[「制御フロー」][control-flow]節で講義します。 -ここまで、数値型のみ扱ってきましたが、Rustには文字も用意されています。Rustの`char`型は、 -言語の最も基本的なアルファベット型であり、以下のコードでその使用方法の一例を見ることができます。 -(`char`は、ダブルクォーテーションマークを使用する文字列に対して、シングルクォートで指定されることに注意してください。) +Rustの`char`型は、言語の最も基本的なアルファベット型です。以下は`char`値を宣言するいくつかの例です: -Rustの`char`型は、ユニコードのスカラー値を表します。これはつまり、アスキーよりもずっとたくさんのものを表せるということです。 -アクセント文字; 中国語、日本語、韓国語文字; -絵文字; ゼロ幅スペースは、全てRustでは、有効な`char`型になります。ユニコードスカラー値は、 +`char`リテラルは、ダブルクォーテーションマークを使用する文字列リテラルに対して、シングルクォートで指定することに注意してください。 +Rustの`char`型は4バイトのサイズを持ち、ユニコードのスカラー値を表します。これはつまり、アスキーよりもずっとたくさんのものを表せるということです。 +アクセント記号付き文字; 中国語、日本語、韓国語の文字; +絵文字; ゼロ幅スペースはすべて、Rustでは有効な`char`値です。ユニコードスカラー値は、 `U+0000`から`U+D7FF`までと`U+E000`から`U+10FFFF`までの範囲になります。 ところが、「文字」は実はユニコードの概念ではないので、文字とは何かという人間としての直観は、 -Rustにおける`char`値が何かとは合致しない可能性があります。この話題については、第8章の「文字列」で詳しく議論しましょう。 +Rustにおける`char`値が何かとは合致しない可能性があります。この話題については、第8章の[「文字列でUTF-8でエンコードされたテキストを保持する」][strings]で詳しく議論しましょう。 #### タプル型 -タプルは、複数の型の何らかの値を一つの複合型にまとめ上げる一般的な手段です。 +*タプル*は、様々な型の複数の値を一つの複合型にまとめ上げる汎用的な手段です。 +タプルの長さは固定です: 一度宣言されたらサイズは伸縮できません。 @@ -424,7 +490,7 @@ use pattern matching to destructure a tuple value, like this: @@ -435,13 +501,11 @@ the single tuple into three parts. Finally, the program prints the value of プログラムは`y`変数の値を出力し、`6.4`と表示されます。 -パターンマッチングを通しての分配の他にも、アクセスしたい値の番号をピリオド(`.`)に続けて書くことで、 -タプルの要素に直接アクセスすることもできます。例です: +アクセスしたい値の番号をピリオド(`.`)に続けて書くことで、タプルの要素に直接アクセスすることもできます。例です: -このプログラムは、新しいタプル`x`を作成し、添え字アクセスで各要素に対して新しい変数も作成しています。 +このプログラムは、新しいタプル`x`を作成し、タプルの各要素にそれぞれの添え字を使ってアクセスしています。 多くのプログラミング言語同様、タプルの最初の添え字は0です。 + + +値をひとつも持たないタプルは*ユニット*という特別な名前を持っています。 +この値と、それに対応する型はともに`()`と書き表され、空の値や空の戻り値型を表現します。 +式は、特に値を返さなければ、暗黙的にユニット値を返します。 + @@ -470,21 +545,19 @@ index in a tuple is 0. *配列*によっても、複数の値のコレクションを得ることができます。タプルと異なり、配列の全要素は、 -同じ型でなければなりません。Rustの配列は、他の言語と異なっています。Rustの配列は、 -固定長なのです: 一度宣言されたら、サイズを伸ばすことも縮めることもできません。 +同じ型でなければなりません。一部の他の言語の配列と異なり、Rustの配列は固定長です。 -Rustでは、配列に入れる要素は、角かっこ内にカンマ区切りリストとして記述します: +配列内の要素は、角かっこ内にカンマ区切りリストとして記述します: -配列は、ヒープよりもスタック(スタックとヒープについては第4章で(つまび)らかに議論します)にデータのメモリを確保したい時、 +配列は、ヒープよりもスタック(スタックとヒープについては[第4章][stack-and-heap]で(つまび)らかに議論します)にデータのメモリを確保したい時、 または、常に固定長の要素があることを確認したい時に有効です。 -ただ、配列は、ベクタ型ほど柔軟ではありません。ベクタは、標準ライブラリによって提供されている配列と似たようなコレクション型で、 +ただ、配列は、ベクタ型ほど柔軟ではありません。*ベクタ*は、標準ライブラリによって提供されている配列と似たようなコレクション型で、 こちらは、サイズを伸縮させることが*できます*。配列とベクタ型、どちらを使うべきか確信が持てない時は、 -おそらくベクタ型を使うべきです。第8章でベクタについて詳細に議論します。 +おそらくベクタ型を使うべきです。[第8章][vectors]でベクタについて詳細に議論します。 -ベクタ型よりも配列を使いたくなるかもしれない例は、1年の月の名前を扱うプログラムです。そのようなプログラムで、 -月を追加したり削除したりすることまずないので、配列を使用できます。常に12個要素があることもわかってますからね: +しかしながら、要素数を変えられる必要はないだろうと分かっている場合は、配列のほうが便利です。 +例えば、プログラム中で月の名前を使おうとしているなら、おそらくベクタよりも配列を使うのが良いでしょう。 +常に12個要素があることもわかってますからね: ```rust let months = ["January", "February", "March", "April", "May", "June", "July", @@ -572,12 +647,13 @@ more concise way. ##### 配列の要素にアクセスする -配列は、スタック上に確保される一塊のメモリです。添え字によって、 -配列の要素にこのようにアクセスすることができます: +配列は、あらかじめ知られた固定サイズを持ち、スタック上に確保することができる一塊のメモリです。 +添え字によって、配列の要素にこのようにアクセスすることができます: この例では、`first`という名前の変数には`1`という値が格納されます。配列の`[0]`番目にある値が、 @@ -605,13 +681,13 @@ get the value `2` from index `[1]` in the array. ##### 配列要素への無効なアクセス -配列の終端を越えて要素にアクセスしようとしたら、どうなるでしょうか? -先ほどの例を以下のように変えたとすると、コンパイルは通りますが、実行するとエラーで終了します: +配列の終端を越えて要素にアクセスしようとしたらどうなるか、見てみましょう。 +第2章の数当てゲームと同じようにユーザから配列の添え字を受け取る、次のコードを実行する場合を考えてみてください: -このコードはコンパイルされます。`cargo run`で走らせ、0, 1, 2, 3, または4をこのプログラムに入力すると配列の対応する値を出力します。もし配列の末尾を超えるような、例えば10などの数字を与えると、次のような出力が表示されます。 +このコードはコンパイルされます。`cargo run`で走らせ、`0`, `1`, `2`, `3`, または`4`をこのプログラムに入力すると配列の対応する値を出力します。 +もし配列の末尾を超えるような、例えば`10`などの数字を与えると、次のような出力が表示されます。 ```console -thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:19:19 -スレッド'main'は'範囲外アクセス: 長さは5ですが、添え字は10でした', src/main.rs:19:19 -でパニックしました +thread 'main' panicked at src/main.rs:19:19: +index out of bounds: the len is 5 but the index is 10 +(スレッド'main'はsrc/main.rs:19:19でパニックしました: +範囲外アクセス: 長さは5ですが、添え字は10でした) note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` -コンパイルでは何もエラーが出なかったものの、プログラムは*実行時*エラーに陥り、 -正常終了しませんでした。要素に添え字アクセスを試みると、言語は、 -指定されたその添え字が配列長よりも小さいかを確認してくれます。添え字が配列長よりも大きければ、言語は*パニック*します。 -パニックとは、プログラムがエラーで終了したことを表すRust用語です。 +プログラムは、添え字アクセスで無効な値を使用した時点で*実行時*エラーに陥りました。 +プログラムはエラーメッセージとともに終了し、最後の`println!`文を実行しませんでした。 +要素に添え字アクセスを試みると、言語は、指定されたその添え字が配列長よりも小さいかを確認してくれます。 +添え字が配列長と等しいかより大きければ、言語は*パニック*します。 +この例の場合は特にそうですが、このチェックは実行時に行われなくてはなりません。 +なぜならコンパイラは、ユーザが後でコードを実行したときに、ユーザがどんな値を入力するか知りようがないからです。 -これは、実際に稼働しているRustの安全機構の最初の例になります。低レベル言語の多くでは、 +これは、実際に稼働しているRustのメモリ安全機構の例のひとつになります。低レベル言語の多くでは、 この種のチェックは行われないため、間違った添え字を与えると、無効なメモリにアクセスできてしまいます。 Rustでは、メモリアクセスを許可し、処理を継続する代わりに即座にプログラムを終了することで、 -この種のエラーからプログラマを保護しています。Rustのエラー処理については、第9章でもっと議論します。 +この種のエラーからプログラマを保護しています。第9章ではRustのエラー処理について、そして、 +可読性が高く安全で、パニックもしなければ不正なメモリアクセスも許さないコードをどうすれば書けるのか、もっと議論します。 + + + +[comparing-the-guess-to-the-secret-number]: +ch02-00-guessing-game-tutorial.html#予想と秘密の数字を比較する +[twos-complement]: https://ja.wikipedia.org/wiki/2の補数 +[control-flow]: ch03-05-control-flow.html#制御フロー +[strings]: ch08-02-strings.html#文字列でutf-8でエンコードされたテキストを保持する +[stack-and-heap]: ch04-01-what-is-ownership.html#スタックとヒープ +[vectors]: ch08-01-vectors.html +[unrecoverable-errors-with-panic]: ch09-01-unrecoverable-errors-with-panic.html +[appendix_b]: appendix-02-operators.md diff --git a/src/ch03-03-how-functions-work.md b/src/ch03-03-how-functions-work.md index 8c16385ff..a15a56588 100644 --- a/src/ch03-03-how-functions-work.md +++ b/src/ch03-03-how-functions-work.md @@ -5,7 +5,7 @@ ## 関数 @@ -36,12 +36,12 @@ Rustの関数と変数の命名規則は、*スネークケース*(`訳注`: som ``` -Rustにおいて関数定義は、`fn`キーワードで始まり、関数名の後に丸かっこの組が続きます。 +Rustでは、`fn`に続けて関数名と丸かっこの組を入力して関数を定義します。 波かっこが、コンパイラに関数本体の開始と終了の位置を伝えます。 定義した関数は、名前に丸かっこの組を続けることで呼び出すことができます。 `another_function`関数がプログラム内で定義されているので、`main`関数内から呼び出すことができるわけです。 ソースコード中で`another_function`を`main`関数の*後*に定義していることに注目してください; 勿論、main関数の前に定義することもできます。コンパイラは、関数がどこで定義されているかは気にしません。 -どこかで定義されていることのみ気にします。 +呼び出し元から見えるスコープ内のどこかで定義されていることのみ気にします。 行出力は、`main`関数内に書かれた順序で実行されています。最初に"Hello, world"メッセージが出て、 それから`another_function`が呼ばれて、こちらのメッセージが出力されています。 -### 関数の引数 +### 引数 -関数は、引数を持つようにも定義できます。引数とは、関数シグニチャの一部になる特別な変数のことです。 -関数に引数があると、引数の位置に実際の値を与えることができます。技術的にはこの実際の値は -*実引数*と呼ばれますが、普段の会話では、仮引数("parameter")と実引数("argument")を関数定義の変数と関数呼び出し時に渡す実際の値、 -両方の意味に区別なく使います(`訳注`: 日本語では、特別区別する意図がない限り、どちらも単に引数と呼ぶことが多いでしょう)。 +関数は、*仮引数 (parameter)* を持つよう定義することもできます。仮引数とは、関数シグニチャの一部になる特別な変数のことです。 +関数に仮引数があると、仮引数に対して具体的な値を与えることができます。 +厳密にはこの具体的な値は*実引数 (argument)* と呼ばれますが、普段の会話では、関数定義内の変数と関数呼び出し時に渡す実際の値の両方の意味で、 +*parameter*と*argument*を区別なく使う傾向にあります (`訳注`: 日本語では、特別区別する意図がない限り、どちらも単に*引数*と呼ぶことが多いでしょう)。 -以下の書き直した`another_function`では、Rustの仮引数がどのようなものかを示しています: +次の版の`another_function`では、仮引数を追加しています: `another_function`の宣言には、`x`という名前の仮引数があります。`x`の型は、 -`i32`と指定されています。値`5`が`another_function`に渡されると、`println!`マクロにより、 -フォーマット文字列中の1組の波かっこがあった位置に値`5`が出力されます。 +`i32`と指定されています。値`5`を`another_function`に渡すと、`println!`マクロにより、 +フォーマット文字列中の`x`を含む1組の波かっこがあった位置に値`5`が出力されます。 関数シグニチャにおいて、各仮引数の型を宣言しなければ*なりません*。これは、Rustの設計において、 -意図的な判断です: 関数定義で型注釈が必要不可欠ということは、コンパイラがその意図するところを推し量るのに、 +意図的な判断です: 関数定義で型注釈が必要不可欠ということは、コンパイラがその意図する型を推し量るのに、 プログラマがコードの他の箇所で使用する必要がないということを意味します。 +コンパイラも、関数が期待する型を知っていれば、より役に立つエラーメッセージを与えることができます。 -関数に複数の仮引数を持たせたいときは、仮引数定義をカンマで区切ってください。 +関数に複数の仮引数を定義したいときは、仮引数定義をカンマで区切ってください。 こんな感じです: -この例では、2引数の関数を生成しています。そして、引数はどちらも`i32`型です。それからこの関数は、 -仮引数の値を両方出力します。関数引数は、全てが同じ型である必要はありません。今回は、 -偶然同じになっただけです。 +この例では、`print_labeled_measurement`という名前の2引数の関数を生成しています。 +第1引数は`value`という名前で`i32`です。第2引数は`unit_label`という名前で`char`型です。 +この関数は`value`と`unit_label`の両方を含むテキストを出力します。 -`x`に対して値`5`、`y`に対して値`6`を渡して関数を呼び出したので、この二つの文字列は、 -この値で出力されました。 +`value`に対して値`5`、`unit_label`に対して値`'h'`を渡して関数を呼び出したので、 +プログラムの出力にはこれらの値が含まれます。 - - -### 関数本体は、文と式を含む +### 文と式 -関数本体は、文が並び、最後に式を置くか文を置くという形で形成されます。現在までには、 -式で終わらない関数だけを見てきたわけですが、式が文の一部になっているものなら見かけましたね。Rustは、式指向言語なので、 +関数本体は、文が並び、最後に式を置くか文を置くという形で形成されます。今のところ、 +私たちが見てきた関数は式で終わることはありませんでしたが、式が文の一部になっているものなら見かけましたね。Rustは、式指向言語なので、 これは理解しておくべき重要な差異になります。他の言語にこの差異はありませんので、文と式がなんなのかと、 その違いが関数本体にどんな影響を与えるかを見ていきましょう。 -実のところ、もう文と式は使っています。*文*とは、なんらかの動作をして値を返さない命令です。 -*式*は結果値に評価されます。ちょっと例を眺めてみましょう。 +* *文 (statement)* はなんらかの動作をして値を返さない命令です。 +* *式 (expression)* は結果値に評価されます。ちょっと例を眺めてみましょう。 +実のところ、もう文と式は使っています。 `let`キーワードを使用して変数を生成し、値を代入することは文になります。 リスト3-1で`let y = 6;`は文です。 @@ -273,7 +272,7 @@ asは前の文にかかるべきだが、大して意味が変わらないので 文は値を返しません。故に、`let`文を他の変数に代入することはできません。 @@ -314,19 +313,19 @@ CやRubyなどの言語とは異なる動作です。CやRubyでは、代入は そうは問屋が卸さないわけです。 -式は何かに評価され、これからあなたが書くRustコードの多くを構成します。 -簡単な数学演算(`5 + 6`など)を思い浮かべましょう。この例は、値`11`に評価される式です。式は文の一部になりえます: +式は値に評価され、これからあなたが書くRustコードの多くを構成します。 +数学演算(`5 + 6`など)を思い浮かべましょう。この例は、値`11`に評価される式です。式は文の一部になりえます: リスト3-1において、`let y = 6`という文の`6`は値`6`に評価される式です。関数呼び出しも式です。マクロ呼び出しも式です。 -新しいスコープを作る際に使用するブロック(`{}`)も式です: +波括弧で作られる新しいスコープも式です: は今回の場合、`4`に評価されるブロックです。その値が、`let`文の一部として`y`に束縛されます。 -今まで見かけてきた行と異なり、文末にセミコロンがついていない`x + 1`の行に気をつけてください。 +今まで見かけてきた行と異なり、`x + 1`の行には文末にセミコロンがついていないことに気をつけてください。 式は終端にセミコロンを含みません。式の終端にセミコロンを付けたら、文に変えてしまいます。そして、文は値を返しません。 次に関数の戻り値や式を見ていく際にこのことを肝に銘じておいてください。 @@ -373,16 +373,16 @@ Keep this in mind as you explore function return values and expressions next. 関数は、それを呼び出したコードに値を返すことができます。戻り値に名前を付けはしませんが、 -矢印(`->`)の後に型を書いて確かに宣言します。Rustでは、関数の戻り値は、関数本体ブロックの最後の式の値と同義です。 +矢印(`->`)の後に型を書いて宣言する必要があります。Rustでは、関数の戻り値は、関数本体ブロックの最後の式の値と同義です。 `return`キーワードで関数から早期リターンし、値を指定することもできますが、多くの関数は最後の式を暗黙的に返します。 こちらが、値を返す関数の例です: @@ -399,7 +399,7 @@ returns a value: @@ -437,7 +437,7 @@ because it’s an expression whose value we want to return. なぜなら、これが返したい値になる式だからです。 もう一つ別の例を見ましょう: @@ -455,7 +455,7 @@ Let's look at another example: このコードを走らせると、`The value of x is: 6`と出力されるでしょう。しかし、 @@ -472,27 +472,27 @@ expression to a statement, we'll get an error: ``` -このコードを実行すると、以下のようにエラーが出ます: +このコードをコンパイルすると、以下のようにエラーが出ます: ```console {{#include ../listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt}} ``` -メインのエラーメッセージである「型が合いません」でこのコードの根本的な問題が明らかになるでしょう。 +メインのエラーメッセージである`mismatched types (型が合いません)`でこのコードの根本的な問題が明らかになるでしょう。 関数`plus_one`の定義では、`i32`型を返すと言っているのに、文は値に評価されないからです。このことは、 -`()`、つまり空のタプルとして表現されています。それゆえに、何も戻り値がなく、これが関数定義と矛盾するので、 +`()`、つまりユニット型として表現されています。それゆえに、何も戻り値がなく、これが関数定義と矛盾するので、 結果としてエラーになるわけです。この出力内で、コンパイラは問題を修正する手助けになりそうなメッセージも出していますね: セミコロンを削除するよう提言しています。そして、そうすれば、エラーは直るわけです。 diff --git a/src/ch03-04-comments.md b/src/ch03-04-comments.md index c3d0ad086..22a08329c 100644 --- a/src/ch03-04-comments.md +++ b/src/ch03-04-comments.md @@ -6,13 +6,13 @@ 全プログラマは、自分のコードがわかりやすくなるよう努めますが、時として追加の説明が許されることもあります。 -このような場合、プログラマは注釈または*コメント*をソースコードに残し、コメントをコンパイラは無視しますが、 +このような場合、プログラマは*コメント*をソースコードに残し、コメントをコンパイラは無視しますが、 ソースコードを読む人間には有益なものと思えるでしょう。 -Rustでは、コメントは2連スラッシュで始め、行の終わりまで続きます。コメントが複数行にまたがる場合、 +Rustの慣用的なコメントスタイルでは、コメントは2連スラッシュで始め、行の終わりまで続きます。コメントが複数行にまたがる場合、 各行に`//`を含める必要があります。こんな感じに: ```rust @@ -48,7 +48,11 @@ Comments can also be placed at the end of lines containing code: コメントは、コードが書かれた行の末尾にも配置することができます: + + +ファイル名: src/main.rs ```rust {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-24-comments-end-of-line/src/main.rs}} @@ -56,11 +60,15 @@ Comments can also be placed at the end of lines containing code: しかし、こちらの形式のコメントの方が見かける機会は多いでしょう。注釈しようとしているコードの1行上に書く形式です: + + ファイル名: src/main.rs ```rust @@ -69,7 +77,10 @@ separate line above the code it's annotating: -Rustには他の種類のコメント、ドキュメントコメントもあり、それについては第14章で議論します。 +Rustには他の種類のコメント、ドキュメントコメントもあり、それについては第14章の[「Crates.ioにクレートを公開する」][publishing]節で議論します。 + +[publishing]: ch14-02-publishing-to-crates-io.html diff --git a/src/ch03-05-control-flow.md b/src/ch03-05-control-flow.md index 71397a24c..aed7faa7b 100644 --- a/src/ch03-05-control-flow.md +++ b/src/ch03-05-control-flow.md @@ -5,15 +5,14 @@ ## 制御フロー -条件が真かどうかによってコードを走らせるかどうかを決定したり、 -条件が真の間繰り返しコードを走らせるか決定したりすることは、多くのプログラミング言語において、基本的な構成ブロックです。 +条件が`true`かどうかによってコードを走らせたり、 +条件が`true`の間繰り返しコードを走らせたりできることは、多くのプログラミング言語において、基本的な構成ブロックです。 Rustコードの実行フローを制御する最も一般的な文法要素は、`if`式とループです。 @@ -50,31 +49,27 @@ the `if` expression. In the *src/main.rs* file, input the following: ``` - - `if`式は全て、キーワードの`if`から始め、条件式を続けます。今回の場合、 条件式は変数`number`が5未満の値になっているかどうかをチェックします。 -条件が真の時に実行したい一連のコードを条件式の直後に波かっこで包んで配置します。`if`式の条件式と紐付けられる一連のコードは、 +条件が`true`の時に実行する一連のコードを条件式の直後に波かっこで包んで配置します。`if`式の条件式と紐付けられる一連のコードは、 時として*アーム*と呼ばれることがあります。 -第2章の「予想と秘密の数字を比較する」の節で議論した`match`式のアームと同じです。 +第2章の[「予想と秘密の数字を比較する」][comparing-the-guess-to-the-secret-number]の節で議論した`match`式のアームと同じです。 @@ -180,11 +175,11 @@ Running this code will print `number was something other than zero`. #### `else if`で複数の条件を扱う -`if`と`else`を組み合わせて`else if`式にすることで複数の条件を持たせることもできます。例です: +`if`と`else`を組み合わせて`else if`式にすることで複数の条件を使うこともできます。例です: -このプログラムを実行すると、`if`式が順番に吟味され、最初に条件が真になった本体が実行されます。 +このプログラムを実行すると、`if`式が順番に吟味され、最初に条件が`true`に評価された本体が実行されます。 6は2で割り切れるものの、`number is devisible by 2`や、 `else`ブロックの`number is not divisible by 4, 3, or 2`という出力はされないことに注目してください。 -それは、Rustが最初の真条件のブロックのみを実行し、 +それは、Rustが最初の`true`な条件のブロックのみを実行し、 条件に合ったものが見つかったら、残りはチェックすらしないからです。 -`if`は式なので、`let`文の右辺に持ってくることができます。リスト3-2のようにですね。 +`if`は式なので、`let`文の右辺に持ってきて結果を変数に代入することができます。リスト3-2のようにですね。 + リスト3-2: `if`式の結果を変数に代入する @@ -278,7 +275,7 @@ whole `if` expression depends on which block of code executes. This means the values that have the potential to be results from each arm of the `if` must be the same type; in Listing 3-2, the results of both the `if` arm and the `else` arm were `i32` integers. If the types are mismatched, as in the following -example, we'll get an error: +example, we’ll get an error: --> 一連のコードは、そのうちの最後の式に評価され、数値はそれ単独でも式になることを思い出してください。 @@ -313,17 +310,17 @@ find the problem in the program: `if`ブロックの式は整数に評価され、`else`ブロックの式は文字列に評価されます。これでは動作しません。 -変数は単独の型でなければならないからです。コンパイラは、コンパイル時に`number`変数の型を確実に把握する必要があるため、 -コンパイル時に`number`が使われている箇所全部で型が有効かどうか検査することができるのです。 +変数は単独の型でなければならず、コンパイラは、コンパイル時に`number`変数の型を確実に把握する必要があるからです。 +`number`の型を把握していることで、コンパイラは、コンパイル時に`number`が使われている箇所全部で型が有効であるか検証できるのです。 `number`の型が実行時にしか決まらないのであれば、コンパイラはそれを実行することができなくなってしまいます; どの変数に対しても、架空の複数の型があることを追いかけなければならないのであれば、コンパイラはより複雑になり、 コードに対して行える保証が少なくなってしまうでしょう。 @@ -336,9 +333,9 @@ multiple hypothetical types for any variable. 一連のコードを1回以上実行できると、しばしば役に立ちます。この作業用に、 @@ -384,19 +381,25 @@ like this: このプログラムを実行すると、プログラムを手動で止めるまで、何度も何度も続けて`again!`と出力するでしょう。 ほとんどの端末でctrl-cというショートカットが使え、 -永久ループに囚われてしまったプログラムを終了させられます。試しにやってみましょう: +永久ループに囚われてしまったプログラムに割り込むことができます。試しにやってみましょう: + + ```console $ cargo run Compiling loops v0.1.0 (file:///projects/loops) - Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs + Finished dev [unoptimized + debuginfo] target(s) in 0.29s Running `target/debug/loops` again! again! @@ -406,25 +409,27 @@ again! ``` `^C`という記号が出た場所が、ctrl-cを押した場所です。`^C`の後には`again!`と表示されたり、 -されなかったりします。ストップシグナルをコードが受け取った時にループのどこにいたかによります。 +されなかったりします。割り込みシグナルをコードが受け取った時にループのどこにいたかによります。 -幸いなことに、Rustにはループを抜け出す別のより信頼できる手段があります。 +幸いなことに、Rustにはコードによってループを抜け出す手段もあります。 ループ内に`break`キーワードを配置することで、プログラムに実行を終了すべきタイミングを教えることができます。 -第2章の「正しい予想をした後に終了する」節の数当てゲーム内でこれをして、ユーザが予想を的中させ、 +第2章の[「正しい予想をした後に終了する」][quitting-after-a-correct-guess]節の数当てゲーム内でこれをして、ユーザが予想を的中させ、 ゲームに勝った時にプログラムを終了させたことを思い出してください。 + +#### ループから値を返す + + + +`loop`の使用法のひとつとして、失敗するかもしれないと分かっている操作、 +例えばスレッドがそのジョブを完了したかを確認する操作などを、リトライするというのがあります。 +さらに、コードの他の部分で使うために、ループの外に操作の結果を渡す必要があるかもしれません。 +これを行うには、ループを止めるために使っている`break`式の後ろに、返したい値を付け加えてください; +その値はループを抜けて返され、使うことができます。このように: + +```rust +{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-33-return-value-from-loop/src/main.rs}} +``` + + + +ループの前で`counter`という変数を宣言し、`0`に初期化しています。 +次に、ループから返された値を保持するために、`result`という変数を宣言しています。 +ループの繰り返しごとに、`counter`変数に`1`を追加し、`counter`が`10`に等しいかチェックします。 +等しい場合は、値`counter * 2`とともに`break`キーワードを使用しています。 +ループの後には、値を`result`に代入する文を終了するためのセミコロンが使われています。 +最後に、`result`の値を出力していて、この場合は`20`です。 + + + +#### 複数のループを区別するループラベル + ループ内にループがある場合、`break`と`continue`は最も内側のループに適用されます。 *ループラベル*を使用することで、`break`や`continue`が適用されるループを指定することができます。 +ループラベルはシングルクオートで始める必要があります。 以下に例を示します。 @@ -477,28 +531,23 @@ doesn’t specify a label will exit the inner loop only. The `break #### `while`で条件付きループ -プログラムにとってループ内で条件式を評価できると、有益なことがしばしばあります。条件が真の間、 -ループが走るわけです。条件が真でなくなった時にプログラムは`break`を呼び出し、ループを終了します。 -このタイプのループは、`loop`、`if`、`else`、`break`を組み合わせることでも実装できます; +プログラムは、ループ内で条件式を評価することがよく必要になるでしょう。条件が`true`の間、 +ループが走るわけです。条件が`true`でなくなった時にプログラムは`break`を呼び出し、ループを終了します。 +このような挙動は、`loop`、`if`、`else`、`break`を組み合わせることでも実装できます; お望みなら、プログラムで今、試してみるのもいいでしょう。 - - - しかし、このパターンは頻出するので、Rustにはそれ用の文法要素が用意されていて、`while`ループと呼ばれます。 -リスト3-3は、`while`を使用しています: プログラムは3回ループし、それぞれカウントダウンします。 -それから、ループ後に別のメッセージを表示して終了します: +リスト3-3では、プログラムを3回ループさせるために`while`を使用しています。 +繰り返しごとにカウントダウンして、ループ後にメッセージを表示して終了します。 この文法要素により、`loop`、`if`、`else`、`break`を使った時に必要になるネストがなくなり、 -より明確になります。条件が真の間、コードは実行されます; そうでなければ、ループを抜けます. +より明確になります。条件が`true`に評価される間、コードは実行されます; そうでなければ、ループを抜けます. -`while`要素を使って配列などのコレクションの要素を覗き見ることができます。例えば、リスト3-4を見ましょう。 +配列などのコレクションの要素を覗き見るために、`while`要素を使うこともできます。 +例えば、リスト3-4のループは配列`a`の各要素を出力します。 ここで、コードは配列の要素を順番にカウントアップして覗いています。番号0から始まり、 -配列の最終番号に到達するまでループします(つまり、`index < 5`が真でなくなる時です)。 +配列の最終番号に到達するまでループします(つまり、`index < 5`が`true`でなくなる時です)。 このコードを走らせると、配列内の全要素が出力されます: ```console @@ -581,23 +632,26 @@ to fetch a sixth value from the array. 配列から6番目の値を拾おうとする前にループは実行を終了します。 -しかし、このアプローチは間違いが発生しやすいです; 添え字の長さが間違っていれば、 -プログラムはパニックしてしまいます。また遅いです。 -コンパイラが実行時にループの各回ごとに境界値チェックを行うようなコードを追加するからです。 +しかし、このアプローチは間違いが発生しやすいです; 添え字の値や判定条件が間違っていれば、 +プログラムはパニックしてしまいます。例えば、`a`配列の定義を4要素を持つように変更したのに、 +条件を`while index < 4`に更新し忘れた場合、コードはパニックするでしょう。また遅いです。 +実行時にループの各回ごとに添字が配列の境界内にあるかチェックするコードを、コンパイラが追加するからです。 -より効率的な対立案として、`for`ループを使ってコレクションの各アイテムに対してコードを実行することができます。 -`for`ループはリスト3-5のこんな見た目です。 +より簡潔な対立案として、`for`ループを使ってコレクションの各アイテムに対してコードを実行することができます。 +`for`ループはリスト3-5のコードのようになります。 -例えば、リスト3-4のコードで、`a`配列からアイテムを1つ削除したのに、条件式を`while index < 4`にするのを忘れていたら、 -コードはパニックします。`for`ループを使っていれば、配列の要素数を変えても、 -他のコードをいじることを覚えておく必要はなくなるわけです。 +`for`ループを使っていれば、配列の要素数を変えても、 +リスト3-4で使った方法のように他のコードをいじることを覚えておく必要はなくなるわけです。 `for`ループのこの安全性と簡潔性により、Rustで使用頻度の最も高いループになっています。 リスト3-3で`while`ループを使ったカウントダウンサンプルのように、一定の回数、同じコードを実行したいような状況であっても、 多くのRustaceanは、`for`ループを使うでしょう。どうやってやるかといえば、 -`Range`型を使うのです。Range型は、標準ライブラリで提供される片方の数字から始まって、 +標準ライブラリで提供される`Range`型を使うのです。`Range`型は、片方の数字から始まって、 もう片方の数字未満の数値を順番に生成する型です。 やりましたね!結構長い章でした: 変数、スカラー値と複合データ型、関数、コメント、`if`式、そして、ループについて学びました! -この章で議論した概念について経験を積みたいのであれば、以下のことをするプログラムを組んでみてください: +この章で議論した概念について経験を積むために、以下のことをするプログラムを組んでみてください: * 温度を華氏と摂氏で変換する。 -* フィボナッチ数列のn番目を生成する。 +* フィボナッチ数列の*n*番目を生成する。 * クリスマスキャロルの定番、"The Twelve Days of Christmas"の歌詞を、 曲の反復性を利用して出力する。 @@ -711,3 +763,15 @@ commonly exist in other programming languages: ownership. --> 次に進む準備ができたら、他の言語にはあまり存在*しない*Rustの概念について話しましょう: 所有権です。 + + + +[comparing-the-guess-to-the-secret-number]: +ch02-00-guessing-game-tutorial.html#予想と秘密の数字を比較する +[quitting-after-a-correct-guess]: +ch02-00-guessing-game-tutorial.html#正しい予想をした後に終了する From 005ab5777b01993e54341aadb424b6293c66e2ad Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:02 +0900 Subject: [PATCH 05/22] =?UTF-8?q?ch04=20=E6=89=80=E6=9C=89=E6=A8=A9?= =?UTF-8?q?=E3=82=92=E7=90=86=E8=A7=A3=E3=81=99=E3=82=8B=E3=81=AE=E5=92=8C?= =?UTF-8?q?=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-04-01/Cargo.toml | 3 +- .../listing-04-01/src/main.rs | 8 +- .../listing-04-02/Cargo.toml | 3 +- .../listing-04-03/Cargo.toml | 3 +- .../listing-04-03/src/main.rs | 28 +- .../listing-04-04/Cargo.toml | 3 +- .../listing-04-04/src/main.rs | 34 +- .../listing-04-05/Cargo.toml | 3 +- .../listing-04-05/src/main.rs | 3 +- .../listing-04-06/Cargo.toml | 3 +- .../listing-04-06/output.txt | 16 +- .../listing-04-07/Cargo.toml | 3 +- .../listing-04-08/Cargo.toml | 3 +- .../listing-04-09/Cargo.toml | 3 +- .../listing-04-09/src/main.rs | 15 +- .../Cargo.toml | 3 +- .../src/main.rs | 4 +- .../no-listing-02-string-scope/Cargo.toml | 3 +- .../no-listing-02-string-scope/src/main.rs | 10 +- .../no-listing-03-string-move/Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../output.txt | 20 +- .../no-listing-05-clone/Cargo.toml | 3 +- .../no-listing-06-copy/Cargo.toml | 3 +- .../no-listing-07-reference/Cargo.toml | 3 +- .../no-listing-07-reference/src/main.rs | 1 + .../Cargo.toml | 3 +- .../src/main.rs | 6 +- .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../output.txt | 12 +- .../Cargo.toml | 3 +- .../src/main.rs | 2 +- .../Cargo.toml | 3 +- .../output.txt | 18 +- .../src/main.rs | 6 +- .../Cargo.toml | 3 +- .../src/main.rs | 8 +- .../Cargo.toml | 3 +- .../output.txt | 22 +- .../Cargo.toml | 3 +- .../src/main.rs | 10 +- .../no-listing-16-no-dangle/Cargo.toml | 3 +- .../no-listing-17-slice/Cargo.toml | 3 +- .../no-listing-18-first-word-slice/Cargo.toml | 3 +- .../no-listing-19-slice-error/Cargo.toml | 3 +- .../no-listing-19-slice-error/output.txt | 10 +- src/ch04-00-understanding-ownership.md | 15 +- src/ch04-01-what-is-ownership.md | 860 +++++++----------- src/ch04-02-references-and-borrowing.md | 422 +++------ src/ch04-03-slices.md | 180 ++-- 51 files changed, 749 insertions(+), 1045 deletions(-) diff --git a/listings/ch04-understanding-ownership/listing-04-01/Cargo.toml b/listings/ch04-understanding-ownership/listing-04-01/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/listing-04-01/Cargo.toml +++ b/listings/ch04-understanding-ownership/listing-04-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/listing-04-01/src/main.rs b/listings/ch04-understanding-ownership/listing-04-01/src/main.rs index 148ad84c9..baee5d9ab 100644 --- a/listings/ch04-understanding-ownership/listing-04-01/src/main.rs +++ b/listings/ch04-understanding-ownership/listing-04-01/src/main.rs @@ -1,9 +1,9 @@ fn main() { // ANCHOR: here - { // s is not valid here, it’s not yet declared - let s = "hello"; // s is valid from this point forward + { // sは、ここでは有効ではない。まだ宣言されていない + let s = "hello"; // sは、ここから有効になる - // do stuff with s - } // this scope is now over, and s is no longer valid + // sで作業をする + } // このスコープは終わり。もうsは有効ではない // ANCHOR_END: here } \ No newline at end of file diff --git a/listings/ch04-understanding-ownership/listing-04-02/Cargo.toml b/listings/ch04-understanding-ownership/listing-04-02/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/listing-04-02/Cargo.toml +++ b/listings/ch04-understanding-ownership/listing-04-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/listing-04-03/Cargo.toml b/listings/ch04-understanding-ownership/listing-04-03/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/listing-04-03/Cargo.toml +++ b/listings/ch04-understanding-ownership/listing-04-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/listing-04-03/src/main.rs b/listings/ch04-understanding-ownership/listing-04-03/src/main.rs index 23906b430..221679d95 100644 --- a/listings/ch04-understanding-ownership/listing-04-03/src/main.rs +++ b/listings/ch04-understanding-ownership/listing-04-03/src/main.rs @@ -1,23 +1,23 @@ fn main() { - let s = String::from("hello"); // s comes into scope + let s = String::from("hello"); // sがスコープに入る - takes_ownership(s); // s's value moves into the function... - // ... and so is no longer valid here + takes_ownership(s); // sの値が関数にムーブされ... + // ... ここではもう有効ではない - let x = 5; // x comes into scope + let x = 5; // xがスコープに入る - makes_copy(x); // x would move into the function, - // but i32 is Copy, so it’s okay to still - // use x afterward + makes_copy(x); // xも関数にムーブされるが、 + // i32はCopyなので、この後にxを使っても + // 大丈夫 -} // Here, x goes out of scope, then s. But because s's value was moved, nothing - // special happens. +} // ここでxがスコープを抜け、sもスコープを抜ける。ただし、sの値はムーブされているので、 + // 何も特別なことは起こらない。 -fn takes_ownership(some_string: String) { // some_string comes into scope +fn takes_ownership(some_string: String) { // some_stringがスコープに入る。 println!("{}", some_string); -} // Here, some_string goes out of scope and `drop` is called. The backing - // memory is freed. +} // ここでsome_stringがスコープを抜け、`drop`が呼ばれる。後ろ盾してたメモリが解放される。 + // 後ろ盾してたメモリが解放される。 -fn makes_copy(some_integer: i32) { // some_integer comes into scope +fn makes_copy(some_integer: i32) { // some_integerがスコープに入る println!("{}", some_integer); -} // Here, some_integer goes out of scope. Nothing special happens. +} // ここでsome_integerがスコープを抜ける。何も特別なことはない。 diff --git a/listings/ch04-understanding-ownership/listing-04-04/Cargo.toml b/listings/ch04-understanding-ownership/listing-04-04/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/listing-04-04/Cargo.toml +++ b/listings/ch04-understanding-ownership/listing-04-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/listing-04-04/src/main.rs b/listings/ch04-understanding-ownership/listing-04-04/src/main.rs index e3e54a818..bb3aa1842 100644 --- a/listings/ch04-understanding-ownership/listing-04-04/src/main.rs +++ b/listings/ch04-understanding-ownership/listing-04-04/src/main.rs @@ -1,29 +1,25 @@ fn main() { - let s1 = gives_ownership(); // gives_ownership moves its return - // value into s1 + let s1 = gives_ownership(); // gives_ownershipは、戻り値をs1に + // ムーブする - let s2 = String::from("hello"); // s2 comes into scope + let s2 = String::from("hello"); // s2がスコープに入る - let s3 = takes_and_gives_back(s2); // s2 is moved into - // takes_and_gives_back, which also - // moves its return value into s3 -} // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was - // moved, so nothing happens. s1 goes out of scope and is dropped. + let s3 = takes_and_gives_back(s2); // s2はtakes_and_gives_backにムーブされ + // 戻り値もs3にムーブされる +} // ここで、s3はスコープを抜け、ドロップされる。s2もスコープを抜けるが、ムーブされているので、 + // 何も起きない。s1もスコープを抜け、ドロップされる。 -fn gives_ownership() -> String { // gives_ownership will move its - // return value into the function - // that calls it +fn gives_ownership() -> String { // gives_ownershipは、戻り値を + // 呼び出した関数にムーブする - let some_string = String::from("hello"); // some_string comes into scope + let some_string = String::from("hello"); // some_stringがスコープに入る - some_string // some_string is returned and - // moves out to the calling - // function + some_string // some_stringが返され、呼び出し元関数に + // ムーブされる } -// takes_and_gives_back will take a String and return one -fn takes_and_gives_back(a_string: String) -> String { // a_string comes into - // scope +// takes_and_gives_backは、Stringを一つ受け取り、返す。 +fn takes_and_gives_back(a_string: String) -> String { // a_stringがスコープに入る。 - a_string // a_string is returned and moves out to the calling function + a_string // a_stringが返され、呼び出し元関数にムーブされる } diff --git a/listings/ch04-understanding-ownership/listing-04-05/Cargo.toml b/listings/ch04-understanding-ownership/listing-04-05/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/listing-04-05/Cargo.toml +++ b/listings/ch04-understanding-ownership/listing-04-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/listing-04-05/src/main.rs b/listings/ch04-understanding-ownership/listing-04-05/src/main.rs index 22aee1419..1f0faaa93 100644 --- a/listings/ch04-understanding-ownership/listing-04-05/src/main.rs +++ b/listings/ch04-understanding-ownership/listing-04-05/src/main.rs @@ -3,11 +3,12 @@ fn main() { let (s2, len) = calculate_length(s1); + //'{}'の長さは、{}です println!("The length of '{}' is {}.", s2, len); } fn calculate_length(s: String) -> (String, usize) { - let length = s.len(); // len() returns the length of a String + let length = s.len(); // len()メソッドは、Stringの長さを返します (s, length) } diff --git a/listings/ch04-understanding-ownership/listing-04-06/Cargo.toml b/listings/ch04-understanding-ownership/listing-04-06/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/listing-04-06/Cargo.toml +++ b/listings/ch04-understanding-ownership/listing-04-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/listing-04-06/output.txt b/listings/ch04-understanding-ownership/listing-04-06/output.txt index 98f438f61..019356390 100644 --- a/listings/ch04-understanding-ownership/listing-04-06/output.txt +++ b/listings/ch04-understanding-ownership/listing-04-06/output.txt @@ -1,16 +1,18 @@ $ cargo run Compiling ownership v0.1.0 (file:///projects/ownership) error[E0596]: cannot borrow `*some_string` as mutable, as it is behind a `&` reference + (`*some_string`は`&`参照の背後にあるため、それを可変として借用することはできません) --> src/main.rs:8:5 | -7 | fn change(some_string: &String) { - | ------- help: consider changing this to be a mutable reference: `&mut std::string::String` 8 | some_string.push_str(", world"); | ^^^^^^^^^^^ `some_string` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to previous error + | (`some_string`は`&`参照なので、それが指すデータを可変として借用することはできません) + | +help: consider changing this to be a mutable reference + (これを可変参照に変更することを検討してください) + | +7 | fn change(some_string: &mut String) { + | +++ For more information about this error, try `rustc --explain E0596`. -error: could not compile `ownership`. - -To learn more, run the command again with --verbose. +error: could not compile `ownership` (bin "ownership") due to 1 previous error diff --git a/listings/ch04-understanding-ownership/listing-04-07/Cargo.toml b/listings/ch04-understanding-ownership/listing-04-07/Cargo.toml index dddcb5a14..e8847526d 100644 --- a/listings/ch04-understanding-ownership/listing-04-07/Cargo.toml +++ b/listings/ch04-understanding-ownership/listing-04-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Carol (Nichols || Goulding) "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/listing-04-08/Cargo.toml b/listings/ch04-understanding-ownership/listing-04-08/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/listing-04-08/Cargo.toml +++ b/listings/ch04-understanding-ownership/listing-04-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/listing-04-09/Cargo.toml b/listings/ch04-understanding-ownership/listing-04-09/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/listing-04-09/Cargo.toml +++ b/listings/ch04-understanding-ownership/listing-04-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/listing-04-09/src/main.rs b/listings/ch04-understanding-ownership/listing-04-09/src/main.rs index b3447e826..fb632583d 100644 --- a/listings/ch04-understanding-ownership/listing-04-09/src/main.rs +++ b/listings/ch04-understanding-ownership/listing-04-09/src/main.rs @@ -16,14 +16,21 @@ fn first_word(s: &str) -> &str { fn main() { let my_string = String::from("hello world"); - // first_word works on slices of `String`s - // first_wordは`String`のスライスに対して機能する + // `first_word` works on slices of `String`s, whether partial or whole + // `first_word`は`String`の全体または部分へのスライスに対して機能する + let word = first_word(&my_string[0..6]); let word = first_word(&my_string[..]); + // `first_word` also works on references to `String`s, which are equivalent + // to whole slices of `String`s + // `first_word`は`String`の参照に対しても機能する。この場合は + // `String`全体へのスライスと同等。 + let word = first_word(&my_string); let my_string_literal = "hello world"; - // first_word works on slices of string literals - // first_wordは文字列リテラルのスライスに対して機能する + // `first_word` works on slices of string literals, whether partial or whole + // `first_word`は文字列リテラルの全体または部分へのスライスに対して機能する + let word = first_word(&my_string_literal[0..6]); let word = first_word(&my_string_literal[..]); // Because string literals *are* string slices already, diff --git a/listings/ch04-understanding-ownership/no-listing-01-can-mutate-string/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-01-can-mutate-string/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-01-can-mutate-string/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-01-can-mutate-string/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-01-can-mutate-string/src/main.rs b/listings/ch04-understanding-ownership/no-listing-01-can-mutate-string/src/main.rs index b68f0f1e7..e9782f2d6 100644 --- a/listings/ch04-understanding-ownership/no-listing-01-can-mutate-string/src/main.rs +++ b/listings/ch04-understanding-ownership/no-listing-01-can-mutate-string/src/main.rs @@ -2,8 +2,8 @@ fn main() { // ANCHOR: here let mut s = String::from("hello"); - s.push_str(", world!"); // push_str() appends a literal to a String + s.push_str(", world!"); // push_str()関数は、リテラルをStringに付け加える - println!("{}", s); // This will print `hello, world!` + println!("{}", s); // これは`hello, world!`と出力する // ANCHOR_END: here } diff --git a/listings/ch04-understanding-ownership/no-listing-02-string-scope/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-02-string-scope/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-02-string-scope/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-02-string-scope/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-02-string-scope/src/main.rs b/listings/ch04-understanding-ownership/no-listing-02-string-scope/src/main.rs index 7e6d46f83..db803b700 100644 --- a/listings/ch04-understanding-ownership/no-listing-02-string-scope/src/main.rs +++ b/listings/ch04-understanding-ownership/no-listing-02-string-scope/src/main.rs @@ -1,10 +1,10 @@ fn main() { // ANCHOR: here - { - let s = String::from("hello"); // s is valid from this point forward + { + let s = String::from("hello"); // sはここから有効になる - // do stuff with s - } // this scope is now over, and s is no - // longer valid + // sで作業をする + } // このスコープはここでおしまい。sは + // もう有効ではない // ANCHOR_END: here } diff --git a/listings/ch04-understanding-ownership/no-listing-03-string-move/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-03-string-move/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-03-string-move/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-03-string-move/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/output.txt b/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/output.txt index 910332ac1..793b6a6e9 100644 --- a/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/output.txt +++ b/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/output.txt @@ -1,19 +1,25 @@ $ cargo run Compiling ownership v0.1.0 (file:///projects/ownership) error[E0382]: borrow of moved value: `s1` + (ムーブされた値の借用: `s1`) --> src/main.rs:5:28 | 2 | let s1 = String::from("hello"); - | -- move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait + | -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait + | (`s1`は`String`型を持ち、これは`Copy`トレイトを実装していないので、ムーブが発生します) 3 | let s2 = s1; | -- value moved here -4 | + | (ここで値がムーブされました) +4 | 5 | println!("{}, world!", s1); | ^^ value borrowed here after move - -error: aborting due to previous error + | (ムーブ後にここで借用されています) + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +3 | let s2 = s1.clone(); + | ++++++++ For more information about this error, try `rustc --explain E0382`. -error: could not compile `ownership`. - -To learn more, run the command again with --verbose. +error: could not compile `ownership` (bin "ownership") due to 1 previous error diff --git a/listings/ch04-understanding-ownership/no-listing-05-clone/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-05-clone/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-05-clone/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-05-clone/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-06-copy/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-06-copy/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-06-copy/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-06-copy/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-07-reference/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-07-reference/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-07-reference/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-07-reference/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-07-reference/src/main.rs b/listings/ch04-understanding-ownership/no-listing-07-reference/src/main.rs index fd32a5fc9..34ca14ed5 100644 --- a/listings/ch04-understanding-ownership/no-listing-07-reference/src/main.rs +++ b/listings/ch04-understanding-ownership/no-listing-07-reference/src/main.rs @@ -6,6 +6,7 @@ fn main() { let len = calculate_length(&s1); // ANCHOR_END: here + // '{}'の長さは、{}です println!("The length of '{}' is {}.", s1, len); } diff --git a/listings/ch04-understanding-ownership/no-listing-08-reference-with-annotations/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-08-reference-with-annotations/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-08-reference-with-annotations/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-08-reference-with-annotations/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-08-reference-with-annotations/src/main.rs b/listings/ch04-understanding-ownership/no-listing-08-reference-with-annotations/src/main.rs index 6e40b8c30..73704d016 100644 --- a/listings/ch04-understanding-ownership/no-listing-08-reference-with-annotations/src/main.rs +++ b/listings/ch04-understanding-ownership/no-listing-08-reference-with-annotations/src/main.rs @@ -7,8 +7,8 @@ fn main() { } // ANCHOR: here -fn calculate_length(s: &String) -> usize { // s is a reference to a String +fn calculate_length(s: &String) -> usize { // sはStringへの参照 s.len() -} // Here, s goes out of scope. But because it does not have ownership of what - // it refers to, nothing happens. +} // ここで、sはスコープ外になる。けど、参照しているものの所有権を持っているわけではないので + // 何も起こらない // ANCHOR_END: here diff --git a/listings/ch04-understanding-ownership/no-listing-09-fixes-listing-04-06/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-09-fixes-listing-04-06/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-09-fixes-listing-04-06/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-09-fixes-listing-04-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/output.txt b/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/output.txt index cb69a714b..ae47fb288 100644 --- a/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/output.txt +++ b/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/output.txt @@ -1,19 +1,19 @@ $ cargo run Compiling ownership v0.1.0 (file:///projects/ownership) error[E0499]: cannot borrow `s` as mutable more than once at a time + (一度に`s`を可変として2回以上借用することはできません) --> src/main.rs:5:14 | 4 | let r1 = &mut s; | ------ first mutable borrow occurs here + | (最初の可変借用はここで発生しています) 5 | let r2 = &mut s; | ^^^^^^ second mutable borrow occurs here -6 | + | (2つ目の可変借用はここで発生しています) +6 | 7 | println!("{}, {}", r1, r2); | -- first borrow later used here - -error: aborting due to previous error + | (最初の参照はここで後で使用されています) For more information about this error, try `rustc --explain E0499`. -error: could not compile `ownership`. - -To learn more, run the command again with --verbose. +error: could not compile `ownership` (bin "ownership") due to 1 previous error diff --git a/listings/ch04-understanding-ownership/no-listing-11-muts-in-separate-scopes/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-11-muts-in-separate-scopes/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-11-muts-in-separate-scopes/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-11-muts-in-separate-scopes/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-11-muts-in-separate-scopes/src/main.rs b/listings/ch04-understanding-ownership/no-listing-11-muts-in-separate-scopes/src/main.rs index 4b1a5a383..f8b382574 100644 --- a/listings/ch04-understanding-ownership/no-listing-11-muts-in-separate-scopes/src/main.rs +++ b/listings/ch04-understanding-ownership/no-listing-11-muts-in-separate-scopes/src/main.rs @@ -4,7 +4,7 @@ fn main() { { let r1 = &mut s; - } // r1 goes out of scope here, so we can make a new reference with no problems. + } // r1はここでスコープを抜けるので、問題なく新しい参照を作ることができる。 let r2 = &mut s; // ANCHOR_END: here diff --git a/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt b/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt index cd4168f8c..af9520170 100644 --- a/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt +++ b/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt @@ -1,20 +1,20 @@ $ cargo run Compiling ownership v0.1.0 (file:///projects/ownership) error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable + (`s`は不変で借用されているので、可変で借用できません) --> src/main.rs:6:14 | -4 | let r1 = &s; // no problem +4 | let r1 = &s; // 問題なし | -- immutable borrow occurs here -5 | let r2 = &s; // no problem -6 | let r3 = &mut s; // BIG PROBLEM + | (不変借用はここで発生しています) +5 | let r2 = &s; // 問題なし +6 | let r3 = &mut s; // 大問題! | ^^^^^^ mutable borrow occurs here -7 | + | (可変借用はここで発生しています) +7 | 8 | println!("{}, {}, and {}", r1, r2, r3); | -- immutable borrow later used here - -error: aborting due to previous error + | (不変借用はその後ここで使われています) For more information about this error, try `rustc --explain E0502`. -error: could not compile `ownership`. - -To learn more, run the command again with --verbose. +error: could not compile `ownership` (bin "ownership") due to 1 previous error diff --git a/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/src/main.rs b/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/src/main.rs index 0da04c010..4d145502d 100644 --- a/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/src/main.rs +++ b/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/src/main.rs @@ -2,9 +2,9 @@ fn main() { // ANCHOR: here let mut s = String::from("hello"); - let r1 = &s; // no problem - let r2 = &s; // no problem - let r3 = &mut s; // BIG PROBLEM + let r1 = &s; // 問題なし + let r2 = &s; // 問題なし + let r3 = &mut s; // 大問題! println!("{}, {}, and {}", r1, r2, r3); // ANCHOR_END: here diff --git a/listings/ch04-understanding-ownership/no-listing-13-reference-scope-ends/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-13-reference-scope-ends/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-13-reference-scope-ends/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-13-reference-scope-ends/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-13-reference-scope-ends/src/main.rs b/listings/ch04-understanding-ownership/no-listing-13-reference-scope-ends/src/main.rs index 3b0a7da65..751a87472 100644 --- a/listings/ch04-understanding-ownership/no-listing-13-reference-scope-ends/src/main.rs +++ b/listings/ch04-understanding-ownership/no-listing-13-reference-scope-ends/src/main.rs @@ -2,12 +2,12 @@ fn main() { // ANCHOR: here let mut s = String::from("hello"); - let r1 = &s; // no problem - let r2 = &s; // no problem + let r1 = &s; // 問題なし + let r2 = &s; // 問題なし println!("{} and {}", r1, r2); - // r1 and r2 are no longer used after this point + // r1とr2はもうこれ以降使用されません - let r3 = &mut s; // no problem + let r3 = &mut s; // 問題なし println!("{}", r3); // ANCHOR_END: here } diff --git a/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/output.txt b/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/output.txt index 6381d2a30..c049f9e0e 100644 --- a/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/output.txt +++ b/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/output.txt @@ -1,16 +1,26 @@ $ cargo run Compiling ownership v0.1.0 (file:///projects/ownership) error[E0106]: missing lifetime specifier +(エラー: ライフタイム指定子がありません) --> src/main.rs:5:16 | 5 | fn dangle() -> &String { - | ^ help: consider giving it a 'static lifetime: `&'static` + | ^ expected named lifetime parameter + | (名前付きのライフタイムパラメータが期待されていました) | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from - -error: aborting due to previous error + = (助言: この関数の戻り値型は、借用した値を含んでいますが、借用される値がどこにもありません) +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` +(助言: `'static`ライフタイムを使うことを検討してください、ただし`const`または`static`から借用した値を返すのでない限り、これはあまり使われません) + | +5 | fn dangle() -> &'static String { + | +++++++ +help: instead, you are more likely to want to return an owned value +(助言: または、所有権を持つ値を返す方がいいかもしれません) + | +5 - fn dangle() -> &String { +5 + fn dangle() -> String { + | For more information about this error, try `rustc --explain E0106`. -error: could not compile `ownership`. - -To learn more, run the command again with --verbose. +error: could not compile `ownership` (bin "ownership") due to 1 previous error diff --git a/listings/ch04-understanding-ownership/no-listing-15-dangling-reference-annotated/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-15-dangling-reference-annotated/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-15-dangling-reference-annotated/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-15-dangling-reference-annotated/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-15-dangling-reference-annotated/src/main.rs b/listings/ch04-understanding-ownership/no-listing-15-dangling-reference-annotated/src/main.rs index 9fbb372a0..7cd451070 100644 --- a/listings/ch04-understanding-ownership/no-listing-15-dangling-reference-annotated/src/main.rs +++ b/listings/ch04-understanding-ownership/no-listing-15-dangling-reference-annotated/src/main.rs @@ -3,11 +3,11 @@ fn main() { } // ANCHOR: here -fn dangle() -> &String { // dangle returns a reference to a String +fn dangle() -> &String { // dangleはStringへの参照を返す - let s = String::from("hello"); // s is a new String + let s = String::from("hello"); // sは新しいString - &s // we return a reference to the String, s -} // Here, s goes out of scope, and is dropped. Its memory goes away. - // Danger! + &s // String sへの参照を返す +} // ここで、sはスコープを抜け、ドロップされる。そのメモリは消される。 + // 危険だ // ANCHOR_END: here diff --git a/listings/ch04-understanding-ownership/no-listing-16-no-dangle/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-16-no-dangle/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-16-no-dangle/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-16-no-dangle/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-17-slice/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-17-slice/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-17-slice/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-17-slice/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-18-first-word-slice/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-18-first-word-slice/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-18-first-word-slice/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-18-first-word-slice/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-19-slice-error/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-19-slice-error/Cargo.toml index 686de938f..e8847526d 100644 --- a/listings/ch04-understanding-ownership/no-listing-19-slice-error/Cargo.toml +++ b/listings/ch04-understanding-ownership/no-listing-19-slice-error/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt b/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt index a1d9caf11..26341bfc5 100644 --- a/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt +++ b/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt @@ -7,18 +7,14 @@ error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immuta 16 | let word = first_word(&s); | -- immutable borrow occurs here | (不変借用はここで発生しています) -17 | +17 | 18 | s.clear(); // error! | ^^^^^^^^^ mutable borrow occurs here | (可変借用はここで発生しています) -19 | +19 | 20 | println!("the first word is: {}", word); | ---- immutable borrow later used here (不変借用はその後ここで使われています) -error: aborting due to previous error - For more information about this error, try `rustc --explain E0502`. -error: could not compile `ownership`. - -To learn more, run the command again with --verbose. +error: could not compile `ownership` (bin "ownership") due to 1 previous error diff --git a/src/ch04-00-understanding-ownership.md b/src/ch04-00-understanding-ownership.md index 220d4a1b1..a3bf3029e 100644 --- a/src/ch04-00-understanding-ownership.md +++ b/src/ch04-00-understanding-ownership.md @@ -5,13 +5,14 @@ # 所有権を理解する -所有権はRustの最もユニークな機能であり、これのおかげでガベージコレクタなしで安全性担保を行うことができるのです。 -故に、Rustにおいて、所有権がどう動作するのかを理解するのは重要です。この章では、所有権以外にも、関連する機能を +所有権はRustの最もユニークな機能であり、それ以外の言語機能と深く関連しています。 +所有権のおかげで、Rustはガベージコレクタの必要なしにメモリ安全性を担保することができていて、 +そのため所有権の仕組みを理解しておくことが重要です。この章では、所有権以外にも、関連する機能を いくつか話していきます: 借用、スライス、そして、コンパイラがデータをメモリにどう配置するかです。 diff --git a/src/ch04-01-what-is-ownership.md b/src/ch04-01-what-is-ownership.md index 2733433d8..9ee58b4ff 100644 --- a/src/ch04-01-what-is-ownership.md +++ b/src/ch04-01-what-is-ownership.md @@ -5,38 +5,38 @@ ## 所有権とは? -Rustの中心的な機能は、*所有権*です。この機能は、説明するのは簡単なのですが、言語の残りの機能全てにかかるほど -深い裏の意味を含んでいるのです。 +*所有権*とは、Rustプログラムがメモリをどのように管理するかを支配している、規則の集合です。 全てのプログラムは、実行中にコンピュータのメモリの使用方法を管理する必要があります。プログラムが動作するにつれて、 定期的に使用されていないメモリを検索するガベージコレクションを持つ言語もありますが、他の言語では、 プログラマが明示的にメモリを確保したり、解放したりしなければなりません。Rustでは第3の選択肢を取っています: -メモリは、コンパイラがコンパイル時にチェックする一定の規則とともに所有権システムを通じて管理されています。 -どの所有権機能も、実行中にプログラムの動作を遅くすることはありません。 +メモリは、コンパイラがチェックする一定の規則とともに所有権システムを通じて管理されています。 +規則のうちどれかひとつにでも違反すれば、プログラムはコンパイルできないでしょう。 +どの所有権機能も、実行中にプログラムの動作を遅くすることはないでしょう。 所有権は多くのプログラマにとって新しい概念なので、慣れるまでに時間がかかります。 -嬉しいことに、Rustと、所有権システムの規則の経験を積むと、より自然に安全かつ効率的なコードを構築できるようになります。 +嬉しいことに、Rustと、所有権システムの規則の経験を積んでいくにつれて、 +自然に安全かつ効率的なコードを構築するのはだんだん簡単だと思えるようになるでしょう。 その調子でいきましょう! - - - - - - - - - - - - - - - - - > ### スタックとヒープ > > 多くのプログラミング言語において、スタックとヒープについて考える機会はそう多くないでしょう。 > しかし、Rustのようなシステムプログラミング言語においては、値がスタックに積まれるかヒープに置かれるかは、 -> 言語の振る舞い方や、特定の決断を下す理由などに影響以上のものを与えるのです。 +> 言語の振る舞いや、特定の決断を下す理由などに影響を与えるのです。 > この章の後半でスタックとヒープを交えて所有権の一部が解説されるので、ここでちょっと予行演習をしておきましょう。 > > スタックもヒープも、実行時にコードが使用できるメモリの一部になりますが、異なる手段で構成されています。 @@ -147,23 +130,24 @@ PROD: START BOX > 途中や一番下に追加したり、取り除いたりすることもできません。データを追加することは、 > *スタックにpushする*といい、データを取り除くことは、*スタックからpopする*と表現します(`訳注`: > 日本語では単純に英語をそのまま活用してプッシュ、ポップと表現するでしょう)。 +> スタック上のデータは全て既知の固定サイズでなければなりません。 +> コンパイル時にサイズがわからなかったり、サイズが可変のデータについては、代わりにヒープに格納しなければなりません。 > -> データへのアクセス方法のおかげで、スタックは高速です: 新しいデータを置いたり、 -> データを取得する場所を探す必要が絶対にないわけです。というのも、その場所は常に一番上だからですね。 -> スタックを高速にする特性は他にもあり、それはスタック上のデータは全て既知の固定サイズでなければならないということです。 -> -> コンパイル時にサイズがわからなかったり、サイズが可変のデータについては、代わりにヒープに格納することができます。 > ヒープは、もっとごちゃごちゃしています: ヒープにデータを置く時、あるサイズのスペースを求めます。 -> OSはヒープ上に十分な大きさの空の領域を見つけ、使用中にし、*ポインタ*を返します。ポインタとは、その場所へのアドレスです。 -> この過程は、*ヒープに領域を確保する(allocating on the heap)*と呼ばれ、時としてそのフレーズを単に*allocateする*などと省略したりします。 +> メモリアロケータはヒープ上に十分な大きさの空の領域を見つけ、使用中にし、*ポインタ*を返します。ポインタとは、その場所へのアドレスです。 +> この過程は、*ヒープに領域を確保する (allocating on the heap)* と呼ばれ、時としてそのフレーズを単に*allocateする*などと省略したりします > (`訳注`: こちらもこなれた日本語訳はないでしょう。allocateは「メモリを確保する」と訳したいところですが) -> スタックに値を積むことは、メモリ確保とは考えられません。ポインタは、既知の固定サイズなので、 +> (スタックに値を積むことは、メモリ確保とは考えられません)。ヒープへのポインタは、既知の固定サイズなので、 > スタックに保管することができますが、実データが必要になったら、ポインタを追いかける必要があります。 -> > レストランで席を確保することを考えましょう。入店したら、グループの人数を告げ、 > 店員が全員座れる空いている席を探し、そこまで誘導します。もしグループの誰かが遅れて来るのなら、 > 着いた席の場所を尋ねてあなたを発見することができます。 > +> スタックにデータを積むほうが、ヒープ上にメモリを確保するより高速です。 +> アロケータが新しいデータを置くための場所を探さなくていいからです。というのも、その場所は常にスタックの一番上だからですね。 +> それと比べて、ヒープ上にメモリを確保するのはより手間の多い仕事です。 +> アロケータはまずデータを入れるのに充分な大きさの場所を探して、そして次のメモリ確保に備えて予約をしないといけないからです。 +> > ヒープへのデータアクセスは、スタックのデータへのアクセスよりも低速です。 > ポインタを追って目的の場所に到達しなければならないからです。現代のプロセッサは、メモリをあちこち行き来しなければ、 > より速くなります。似た例えを続けましょう。レストランで多くのテーブルから注文を受ける給仕人を考えましょう。最も効率的なのは、 @@ -171,7 +155,7 @@ PROD: START BOX > それからテーブルBの注文、さらにまたA、それからまたBと渡り歩くのは、かなり低速な過程になってしまうでしょう。 > 同じ意味で、プロセッサは、 > データが隔離されている(ヒープではそうなっている可能性がある)よりも近くにある(スタックではこうなる)ほうが、 -> 仕事をうまくこなせるのです。ヒープに大きな領域を確保する行為も時間がかかることがあります。 +> 仕事をうまくこなせるのです。 > > コードが関数を呼び出すと、関数に渡された値(ヒープのデータへのポインタも含まれる可能性あり)と、 > 関数のローカル変数がスタックに載ります。関数の実行が終了すると、それらの値はスタックから取り除かれます。 @@ -179,12 +163,8 @@ PROD: START BOX > どの部分のコードがどのヒープ上のデータを使用しているか把握すること、ヒープ上の重複するデータを最小化すること、 > メモリ不足にならないようにヒープ上の未使用のデータを掃除することは全て、所有権が解決する問題です。 > 一度所有権を理解したら、あまり頻繁にスタックとヒープに関して考える必要はなくなるでしょうが、 -> ヒープデータを管理することが所有権の存在する理由だと知っていると、所有権がありのままで動作する理由を -> 説明するのに役立つこともあります。 +> 所有権の主な目的はヒープデータを管理することだと知っていると、所有権がどうしてこうなっているのか説明するのに役立つこともあります。 > - -まず、所有権のルールについて見ていきましょう。 -この規則を具体化する例を扱っていく間もこれらのルールを肝に銘じておいてください: +まず、所有権の規則について見ていきましょう。 +この規則を具体化する例を扱っていく間もこれらの規則を肝に銘じておいてください: -* Rustの各値は、*所有者*と呼ばれる変数と対応している。 +* Rustの各値には、*所有者*が存在する。 * いかなる時も所有者は一つである。 * 所有者がスコープから外れたら、値は破棄される。 @@ -217,27 +197,25 @@ work through the examples that illustrate them: ### 変数スコープ -第2章で、Rustプログラムの例はすでに見ています。もう基本的な記法は通り過ぎたので、 -`fn main() {`というコードはもう例に含みません。従って、例をなぞっているなら、 -これからの例は`main`関数に手動で入れ込まなければいけなくなるでしょう。結果的に、例は少々簡潔になり、 -定型コードよりも具体的な詳細に集中しやすくなります。 +もう基本的なRustの文法は通り過ぎたので、`fn main() {`というコードはもう例に含みません。 +従って、例をなぞっているなら、これからの例は`main`関数に手動で入れ込むようにしてください。 +結果的に、例は少々簡潔になり、定型コードよりも具体的な詳細に集中しやすくなります。 所有権の最初の例として、何らかの変数の*スコープ*について見ていきましょう。スコープとは、 -要素が有効になるプログラム内の範囲のことです。以下のような変数があるとしましょう: +要素が有効になるプログラム内の範囲のことです。以下の変数を例に取ります: ```rust let s = "hello"; @@ -246,37 +224,23 @@ let s = "hello"; 変数`s`は、文字列リテラルを参照し、ここでは、文字列の値はプログラムのテキストとしてハードコードされています。 この変数は、宣言された地点から、現在の*スコープ*の終わりまで有効になります。リスト4-1には、 -変数`s`が有効な場所に関する注釈がコメントで付記されています。 +変数`s`が有効な場所に関する注釈がコメントで付記されたプログラムを示します。 - +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-01/src/main.rs:here}} +``` -```rust -{ // sは、ここでは有効ではない。まだ宣言されていない - let s = "hello"; // sは、ここから有効になる - - // sで作業をする -} // このスコープは終わり。もうsは有効ではない -``` - - - リスト4-1: 変数と有効なスコープ -* `s`が*スコープに入る*と、有効になる -* *スコープを抜ける*まで、有効なまま +* `s`がスコープに*入る*と、有効になる。 +* スコープを*抜ける*まで、有効なまま。 -ここで、スコープと変数が有効になる期間の関係は、他の言語に類似しています。さて、この理解のもとに、 +今のところ、スコープと、変数が有効である期間の関係は、他の言語のそれに類似しています。さて、この理解のもとに、 `String`型を導入して構築していきましょう。 - -所有権の規則を具体化するには、第3章の「データ型」節で講義したものよりも、より複雑なデータ型が必要になります。 -以前講義した型は全てスタックに保管され、スコープが終わるとスタックから取り除かれますが、 -ヒープに確保されるデータ型を観察して、 +than those we covered in the [“Data Types”][data-types] section +of Chapter 3. The types covered previously are of a known size, can be stored +on the stack and popped off the stack when their scope is over, and can be +quickly and trivially copied to make a new, independent instance if another +part of code needs to use the same value in a different scope. But we want to +look at data that is stored on the heap and explore how Rust knows when to +clean up that data, and the `String` type is a great example. +--> + +所有権の規則を具体化するには、第3章の[「データ型」][data-types]節で講義したものよりも、より複雑なデータ型が必要になります。 +以前講義した型は、既知のサイズを持ち、スタックに置いておいてスコープが終わるとスタックから取り除かれるという扱いが可能でした。 +さらに、コードの別の場所で同じ値を異なるスコープを持たせて使う必要があるなら、 +新しい、独立したインスタンスに、高速に、そして自明にコピーすることができました。 +が、ヒープに確保されるデータ型を観察して、 コンパイラがどうそのデータを掃除すべきタイミングを把握しているかを掘り下げていきたいと思います。 +`String`型はその好例です。 -ここでは、例として`String`型を使用し、`String`型の所有権にまつわる部分に着目しましょう。 -また、この観点は、標準ライブラリや自分で生成する他の複雑なデータ型にも適用されます。 -`String`型については、第8章でより深く議論します。 +`String`型の所有権にまつわる部分に着目しましょう。 +またこの観点は、標準ライブラリから提供されたか自分で作成したかを問わず、他の複雑なデータ型にも適用されます。 +`String`型については、[第8章][ch8]でより深く議論します。 既に文字列リテラルは見かけましたね。文字列リテラルでは、文字列の値はプログラムにハードコードされます。 @@ -357,51 +327,35 @@ let s = String::from("hello"); ``` -この二重コロンは、`string_from`などの名前を使うのではなく、 -`String`型直下の`from`関数を特定する働きをする演算子です。この記法について詳しくは、 -第5章の「メソッド記法」節と、第7章の「モジュール定義」でモジュールを使った名前空間分けについて話をするときに議論します。 +この二重コロン`::`演算子は、`string_from`などの名前を使うのではなく、 +`String`型直下の`from`関数を特定する働きをします。この記法について詳しくは、 +第5章の[「メソッド記法」][method-syntax]節と、第7章の[「モジュールツリーの要素を示すためのパス」][paths-module-tree]でモジュールを使った名前空間分けについて話をするときに議論します。 -この種の文字列は、可変化することが*できます*: +この種の文字列は、変更することが*できます*: - - - - - -```rust -let mut s = String::from("hello"); - -s.push_str(", world!"); // push_str()関数は、リテラルをStringに付け加える - -println!("{}", s); // これは`hello, world!`と出力する -``` -では、ここでの違いは何でしょうか?なぜ、`String`型は可変化できるのに、リテラルはできないのでしょうか? +では、ここでの違いは何でしょうか?なぜ、`String`型は変更できるのに、リテラルはできないのでしょうか? 違いは、これら二つの型がメモリを扱う方法にあります。 @@ -434,13 +388,13 @@ to hold the contents. This means: ヒープに確保して内容を保持します。つまり: -* メモリは、実行時にOSに要求される。 -* `String`型を使用し終わったら、OSにこのメモリを返還する方法が必要である。 +* メモリは、実行時にメモリアロケータに要求される。 +* `String`型を使用し終わったら、アロケータにこのメモリを返還する方法が必要である。 - - - ```rust -{ - let s = String::from("hello"); // sはここから有効になる - - // sで作業をする -} // このスコープはここでおしまい。sは - // もう有効ではない +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-02-string-scope/src/main.rs:here}} ``` -`String`型が必要とするメモリをOSに返還することが自然な地点があります: `s`変数がスコープを抜ける時です。 -変数がスコープを抜ける時、Rustは特別な関数を呼んでくれます。この関数は、`drop`と呼ばれ、 +`String`型が必要とするメモリをアロケータに返還することが自然な地点があります: `s`変数がスコープを抜ける時です。 +変数がスコープを抜ける時、Rustは特別な関数を呼んでくれます。この関数は、[`drop`][drop]と呼ばれ、 ここに`String`型の書き手はメモリを返還するコードを配置することができます。Rustは、閉じ波括弧で自動的に`drop`関数を呼び出します。 > 注釈: C++では、要素の生存期間の終了地点でリソースを解放するこのパターンを時に、 @@ -540,11 +478,16 @@ we’ve allocated on the heap. Let’s explore some of those situations now. ヒープ上に確保されたデータを複数の変数に使用させるようなもっと複雑な場面では、コードの振る舞いは、 予期しないものになる可能性もあります。これから、そのような場面を掘り下げてみましょう。 + + + -#### 変数とデータの相互作用法: ムーブ +#### ムーブによる変数とデータの相互作用 + リスト4-2: 変数`x`の整数値を`y`に代入する @@ -584,17 +528,16 @@ Now let’s look at the `String` version: では、`String`バージョンを見ていきましょう: ```rust -let s1 = String::from("hello"); -let s2 = s1; +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-03-string-move/src/main.rs:here}} ``` -このコードは先ほどのコードに酷似していますので、動作方法も同じだと思い込んでしまうかもしれません: +このコードは酷似していますので、動作方法も同じだと思い込んでしまうかもしれません: 要するに、2行目で`s1`の値をコピーし、`s2`に束縛するということです。ところが、 これは全く起こることを言い当てていません。 @@ -612,26 +555,34 @@ heap that holds the contents. 右側には、中身を保持したヒープ上のメモリがあります。 -メモリ上の文字列 +2個の表: 1個目の表はスタック上のs1の表現を含み、表はs1の長さ(5)、許容量(5)、
+そして2個目の表の最初の値へのポインタからなる。2個目の表はヒープ上の文字列データのバイト単位の表現を含む。 - + 図4-1: `s1`に束縛された`"hello"`という値を保持する`String`のメモリ上の表現 長さは、`String`型の中身が現在使用しているメモリ量をバイトで表したものです。許容量は、 -`String`型がOSから受け取った全メモリ量をバイトで表したものです。長さと許容量の違いは問題になることですが、 +`String`型がアロケータから受け取った全メモリ量をバイトで表したものです。長さと許容量の違いは問題になることですが、 この文脈では違うので、とりあえずは、許容量を無視しても構わないでしょう。 -同じ値を指すs1とs2 +3個の表: 表s1とs2はスタック上の文字列s1とs2それぞれを表現し、どちらもヒープ上の同じ文字列データを指している。 - + 図4-2: `s1`のポインタ、長さ、許容量のコピーを保持する変数`s2`のメモリ上での表現 @@ -668,13 +624,18 @@ Rustが代わりにヒープデータもコピーするという選択をして ヒープ上のデータが大きい時に`s2 = s1`という処理の実行時性能がとても悪くなっていた可能性があるでしょう。 -2箇所へのs1とs2 +4個の表: 2個の表はs1とs2のスタックデータを表現し、それぞれがヒープ上の文字列データのコピーを指している。 - + 図4-3: Rustがヒープデータもコピーしていた場合に`s2 = s1`という処理が行なった可能性のあること @@ -696,27 +657,18 @@ corruption, which can potentially lead to security vulnerabilities. セキュリティ上の脆弱性を生む可能性があります。 - - -メモリ安全性を保証するために、Rustにおいてこの場面で起こることの詳細がもう一つあります。 -確保されたメモリをコピーしようとする代わりに、コンパイラは、`s1`が最早有効ではないと考え、 +メモリ安全性を保証するために、`let s2 = s1;`の行の後、コンパイラは`s1`が最早有効ではないとみなします。 故に`s1`がスコープを抜けた際に何も解放する必要がなくなるわけです。`s2`の生成後に`s1`を使用しようとしたら、 どうなるかを確認してみましょう。動かないでしょう: -```rust,ignore -let s1 = String::from("hello"); -let s2 = s1; - -println!("{}, world!", s1); +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/src/main.rs:here}} ``` src/main.rs:5:28 - | -3 | let s2 = s1; - | -- value moved here -4 | -5 | println!("{}, world!", s1); - | ^^ value used here after move - | (ムーブ後にここで使用されています) - | - = note: move occurs because `s1` has type `std::string::String`, which does - not implement the `Copy` trait - (注釈: ムーブが起きたのは、`s1`が`std::string::String`という - `Copy`トレイトを実装していない型だからです) +```console +{{#include ../listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/output.txt}} ``` -他の言語を触っている間に"shallow copy"と"deep copy"という用語を耳にしたことがあるなら、 -データのコピーなしにポインタと長さ、許容量をコピーするという概念は、shallow copyのように思えるかもしれません。 +他の言語を触っている間に*shallow copy*と*deep copy*という用語を耳にしたことがあるなら、 +データのコピーなしにポインタと長さ、許容量をコピーするという概念は、shallow copyすることのように思えるかもしれません。 ですが、コンパイラは最初の変数をも無効化するので、shallow copyと呼ばれる代わりに、 *ムーブ*として知られているわけです。この例では、`s1`は`s2`に*ムーブ*されたと表現するでしょう。 以上より、実際に起きることを図4-4に示してみました。 -s2にムーブされたs1 +3個の表: 表s1とs2はスタック上の文字列s1とs2それぞれを表現し、どちらもヒープ上の同じ文字列データを指している。
+s1はもう有効ではないので、表s1はグレー表示されている。
+s2だけがヒープデータにアクセスするために使用できる。 - + 図4-4: `s1`が無効化された後のメモリ表現 @@ -788,11 +734,16 @@ copying can be assumed to be inexpensive in terms of runtime performance. 自動的にデータの"deep copy"が行われることは絶対にないわけです。それ故に、あらゆる*自動*コピーは、実行時性能の観点で言うと、 悪くないと考えてよいことになります。 + -#### 変数とデータの相互作用法: クローン + + +#### クローンによる変数とデータの相互作用 まだ話題にしていない別の問題があります。 この整数を使用したコードは、一部をリスト4-2で示しましたが、うまく動作する有効なものです: ```rust -let x = 5; -let y = x; - -println!("x = {}, y = {}", x, y); +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-06-copy/src/main.rs:here}} ``` その理由は、整数のようなコンパイル時に既知のサイズを持つ型は、スタック上にすっぽり保持されるので、 @@ -881,41 +826,51 @@ differently from the usual shallow copying and we can leave it out. Rustには`Copy`トレイトと呼ばれる特別な注釈があり、 -整数のようなスタックに保持される型に対して配置することができます(トレイトについては第10章でもっと詳しく話します)。 -型が`Copy`トレイトに適合していれば、代入後も古い変数が使用可能になります。コンパイラは、 -型やその一部分でも`Drop`トレイトを実装している場合、`Copy`トレイトによる注釈をさせてくれません。 +整数のようなスタックに保持される型に対して配置することができます(トレイトについては[第10章][traits]でもっと詳しく話します)。 +型が`Copy`トレイトを実装していれば、その型を持つ変数はムーブされず、代わりに自明な方法でにコピーされます。 +そのため、他の変数に代入した後でも、元の変数は有効なままです。 + + + +コンパイラは、型やその一部分でも`Drop`トレイトを実装している場合、`Copy`による注釈をさせてくれません。 型の値がスコープを外れた時に何か特別なことを起こす必要がある場合に、`Copy`注釈を追加すると、コンパイルエラーが出ます。 -型に`Copy`注釈をつける方法について学ぶには、付録Cの「導出可能なトレイト」をご覧ください。 +型に`Copy`注釈をつけてトレイトを実装する方法について学ぶには、付録Cの[「導出可能なトレイト」][derivable-traits]をご覧ください。 -では、どの型が`Copy`なのでしょうか?ある型について、ドキュメントをチェックすればいいのですが、 -一般規則として、単純なスカラー値の集合は何でも`Copy`であり、メモリ確保が必要だったり、 -何らかの形態のリソースだったりするものは`Copy`ではありません。ここに`Copy`の型の一部を並べておきます。 +では、どの型が`Copy`トレイトを実装しているのでしょうか? +確実に知るためには、調べたい型のドキュメントをチェックすればいいのですが、 +一般規則として、単純なスカラー値の集合は何でも`Copy`を実装でき、メモリ確保が必要だったり、 +何らかの形態のリソースだったりするものは`Copy`を実装できません。ここに`Copy`を実装する型の一部を並べておきます。 * あらゆる整数型。`u32`など。 @@ -932,13 +887,13 @@ be sure, but as a general rule, any group of simple scalar values can be ### 所有権と関数 -意味論的に、関数に値を渡すことと、値を変数に代入することは似ています。関数に変数を渡すと、 +関数に値を渡すことと、値を変数に代入することの仕組みは似ています。関数に変数を渡すと、 代入のようにムーブやコピーされます。リスト4-3は変数がスコープに入ったり、 抜けたりする地点について注釈してある例です。 @@ -948,75 +903,15 @@ showing where variables go into and out of scope. ファイル名: src/main.rs - - - - - - - - - - - +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-03/src/main.rs}} +``` -```rust -fn main() { - let s = String::from("hello"); // sがスコープに入る - - takes_ownership(s); // sの値が関数にムーブされ... - // ... ここではもう有効ではない - - let x = 5; // xがスコープに入る - - makes_copy(x); // xも関数にムーブされるが、 - // i32はCopyなので、この後にxを使っても - // 大丈夫 - -} // ここでxがスコープを抜け、sもスコープを抜ける。ただし、sの値はムーブされているので、何も特別なことは起こらない。 - // - -fn takes_ownership(some_string: String) { // some_stringがスコープに入る。 - println!("{}", some_string); -} // ここでsome_stringがスコープを抜け、`drop`が呼ばれる。後ろ盾してたメモリが解放される。 - // - -fn makes_copy(some_integer: i32) { // some_integerがスコープに入る - println!("{}", some_integer); -} // ここでsome_integerがスコープを抜ける。何も特別なことはない。 -``` - - - リスト4-3: 所有権とスコープが注釈された関数群 -値を返すことでも、所有権は移動します。リスト4-4は、リスト4-3と似た注釈のついた例です。 +値を返すことでも、所有権は移動します。リスト4-4に値を返す関数の例を、リスト4-3と似た注釈を付けて示します。 - - - - - - - - - - - - - - - -```rust -fn main() { - let s1 = gives_ownership(); // gives_ownershipは、戻り値をs1に - // ムーブする - - let s2 = String::from("hello"); // s2がスコープに入る - - let s3 = takes_and_gives_back(s2); // s2はtakes_and_gives_backにムーブされ - // 戻り値もs3にムーブされる -} // ここで、s3はスコープを抜け、ドロップされる。s2もスコープを抜けるが、ムーブされているので、 - // 何も起きない。s1もスコープを抜け、ドロップされる。 - -fn gives_ownership() -> String { // gives_ownershipは、戻り値を - // 呼び出した関数にムーブする - - let some_string = String::from("hello"); // some_stringがスコープに入る - - some_string // some_stringが返され、呼び出し元関数に - // ムーブされる -} - -// takes_and_gives_backは、Stringを一つ受け取り、返す。 -fn takes_and_gives_back(a_string: String) -> String { // a_stringがスコープに入る。 - - a_string // a_stringが返され、呼び出し元関数にムーブされる -} +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-04/src/main.rs}} ``` +heap goes out of scope, the value will be cleaned up by `drop` unless ownership +of the data has been moved to another variable. 変数の所有権は、毎回同じパターンを辿っています: 別の変数に値を代入すると、ムーブされます。 -ヒープにデータを含む変数がスコープを抜けると、データが別の変数に所有されるようムーブされていない限り、 +ヒープにデータを含む変数がスコープを抜けると、データの所有権が別の変数にムーブされていない限り、 `drop`により片付けられるでしょう。 -所有権を取り、またその所有権を戻す、ということを全ての関数でしていたら、ちょっとめんどくさいですね。 +これでもいいのですが、所有権を取り、またその所有権を戻す、ということを全ての関数でしていたら、ちょっとめんどくさいですね。 関数に値は使わせるものの所有権を取らないようにさせるにはどうするべきでしょうか。 返したいと思うかもしれない関数本体で発生したあらゆるデータとともに、再利用したかったら、渡されたものをまた返さなきゃいけないのは、 非常に煩わしいことです。 -タプルで、複数の値を返すことは可能です。リスト4-5のようにですね。 +Rustでは、タプルを使って複数の値を返すことができます。リスト4-5のようにですね。 - - - - - - - - - ```rust -fn main() { - let s1 = String::from("hello"); - - let (s2, len) = calculate_length(s1); - - //'{}'の長さは、{}です - println!("The length of '{}' is {}.", s2, len); -} - -fn calculate_length(s: String) -> (String, usize) { - let length = s.len(); // len()メソッドは、Stringの長さを返します - - (s, length) -} +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-05/src/main.rs}} ``` でも、これでは、大袈裟すぎますし、ありふれているはずの概念に対して、作業量が多すぎます。 -私たちにとって幸運なことに、Rustにはこの概念に対する機能があり、*参照*と呼ばれます。 +私たちにとって幸運なことに、Rustには所有権を移動することなく値を使うための機能があり、*参照*と呼ばれます。 + + + +[data-types]: ch03-02-data-types.html#データ型 +[ch8]: ch08-02-strings.html +[traits]: ch10-02-traits.html +[derivable-traits]: appendix-03-derivable-traits.html +[method-syntax]: ch05-03-method-syntax.html#メソッド記法 +[paths-module-tree]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html +[drop]: https://doc.rust-lang.org/std/ops/trait.Drop.html#tymethod.drop diff --git a/src/ch04-02-references-and-borrowing.md b/src/ch04-02-references-and-borrowing.md index ddd58b726..04fef7157 100644 --- a/src/ch04-02-references-and-borrowing.md +++ b/src/ch04-02-references-and-borrowing.md @@ -8,16 +8,23 @@ The issue with the tuple code in Listing 4-5 is that we have to return the `String` to the calling function so we can still use the `String` after the call to `calculate_length`, because the `String` was moved into -`calculate_length`. +`calculate_length`. Instead, we can provide a reference to the `String` value. +A *reference* is like a pointer in that it’s an address we can follow to access +the data stored at that address; that data is owned by some other variable. +Unlike a pointer, a reference is guaranteed to point to a valid value of a +particular type for the life of that reference. --> リスト4-5のタプルコードの問題は、`String`型を呼び出し元の関数に戻さないと、`calculate_length`を呼び出した後に、 `String`オブジェクトが使えなくなることであり、これは`String`オブジェクトが`calculate_length`にムーブされてしまうためでした。 +代わりに、`String`値への参照を渡すことができます。 +*参照*はアドレスであり、それを辿ってそのアドレスに置かれているデータにアクセスできるという点で、ポインタと似ています; +データは他の変数によって所有されています。 +ポインタと異なる点としては、参照はその生存期間中を通して、特定の型の有効な値を指していることが保証されています。 ここで、値の所有権をもらう代わりに引数としてオブジェクトへの参照を取る`calculate_length`関数を定義し、 @@ -30,43 +37,30 @@ value: ファイル名: src/main.rs ```rust -fn main() { - let s1 = String::from("hello"); - - let len = calculate_length(&s1); - - // '{}'の長さは、{}です - println!("The length of '{}' is {}.", s1, len); -} - -fn calculate_length(s: &String) -> usize { - s.len() -} +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-07-reference/src/main.rs:all}} ``` まず、変数宣言と関数の戻り値にあったタプルコードは全てなくなったことに気付いてください。 2番目に、`&s1`を`calcuate_length`に渡し、その定義では、`String`型ではなく、`&String`を受け取っていることに注目してください。 +これらのアンド記号が参照を表しており、これのおかげで所有権をもらうことなく値を参照することができるのです。 +図4-5にこの概念を描写します。 - -これらのアンド記号が参照であり、これのおかげで所有権をもらうことなく値を参照することができるのです。 -図4-5はその図解です。 - - -文字列s1を指す&String型のs +3個の表: sの表はs1の表へのポインタのみを含む。
+s1の表はs1のスタックデータを含み、ヒープ上の文字列データを指している。 > 注釈: `&`による参照の逆は、*参照外し*であり、参照外し演算子の`*`で達成できます。 @@ -92,22 +86,17 @@ Let’s take a closer look at the function call here: ここの関数呼び出しについて、もっと詳しく見てみましょう: ```rust -# fn calculate_length(s: &String) -> usize { -# s.len() -# } -let s1 = String::from("hello"); - -let len = calculate_length(&s1); +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-07-reference/src/main.rs:here}} ``` この`&s1`という記法により、`s1`の値を*参照する*参照を生成することができますが、これを所有することはありません。 -所有してないということは、指している値は、参照がスコープを抜けてもドロップされないということです。 +所有してないということは、指している値は、参照が使用されなくなってもドロップされないということです。 - ```rust -fn calculate_length(s: &String) -> usize { // sはStringへの参照 - s.len() -} // ここで、sはスコープ外になる。けど、参照しているものの所有権を持っているわけではないので - // 何も起こらない +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-08-reference-with-annotations/src/main.rs:here}} ``` -変数`s`が有効なスコープは、あらゆる関数の引数のものと同じですが、所有権はないので、`s`がスコープを抜けても、 -参照が指しているものをドロップすることはありません。関数が実際の値の代わりに参照を引数に取ると、 +変数`s`が有効なスコープは通常の関数の引数のものと同じですが、`s`はそれが指す値に対する所有権を持っていないので、 +`s`が使用されなくなっても指している値をドロップすることはありません。関数が実際の値の代わりに参照を引数に取ると、 所有権をもらわないので、所有権を返す目的で値を返す必要はありません。 -関数の引数に参照を取ることを*借用*と呼びます。現実生活のように、誰かが何かを所有していたら、 -それを借りることができます。用が済んだら、返さなきゃいけないわけです。 +参照を作成することを*借用*と呼びます。現実生活のように、誰かが何かを所有していたら、 +それを借りることができます。用が済んだら、返さないといけません。持っているのとは違うのです。 @@ -168,16 +146,8 @@ Listing 4-6. Spoiler alert: it doesn’t work! ファイル名: src/main.rs -```rust,ignore -fn main() { - let s = String::from("hello"); - - change(&s); -} - -fn change(some_string: &String) { - some_string.push_str(", world"); -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-06/src/main.rs}} ``` error.rs:8:5 - | -7 | fn change(some_string: &String) { - | ------- use `&mut String` here to make mutable -8 | some_string.push_str(", world"); - | ^^^^^^^^^^^ cannot borrow as mutable +```console +{{#include ../listings/ch04-understanding-ownership/listing-04-06/output.txt}} ``` -### 可変な参照 +### 可変参照 -一捻り加えるだけでリスト4-6のコードのエラーは解決します: +借用された値を変更できるようにするには、代わりに*可変参照*を使うという一捻りを加えるだけでよく、 +これでリスト4-6のコードを修正できます: -始めに、`s`を`mut`に変えなければなりませんでした。そして、`&mut s`で可変な参照を生成し、 -`some_string: &mut String`で可変な参照を受け入れなければなりませんでした。 +まず`s`が`mut`となるように変更します。次に、`change`関数を呼ぶところで`&mut s`によって可変参照を作成し、 +さらに関数シグネチャを、`some_string: &mut String`で可変参照を受け入れるように更新します。 +これにより、`change`関数は借用する値を変更しようとすることがとても明確になります。 -ところが、可変な参照には大きな制約が一つあります: 特定のスコープで、ある特定のデータに対しては、 -一つしか可変な参照を持てないことです。こちらのコードは失敗します: +可変参照には大きな制約が一つあります: ある値への可変参照が存在するなら、その値への参照を他に作ることはできません。 +このコードは`s`への可変参照を2個作成しようとしていますが、これは失敗します: src/main.rs:5:14 - | -4 | let r1 = &mut s; - | ------ first mutable borrow occurs here - | (最初の可変な参照はここ) -5 | let r2 = &mut s; - | ^^^^^^ second mutable borrow occurs here - | (二つ目の可変な参照はここ) -6 | -7 | println!("{}, {}", r1, r2); - | -- first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. -error: could not compile `ownership` - -To learn more, run the command again with --verbose. +```console +{{#include ../listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/output.txt}} ``` -この制約は、可変化を許可するものの、それを非常に統制の取れた形で行えます。これは、新たなRustaceanにとっては、 -壁です。なぜなら、多くの言語では、いつでも好きな時に可変化できるからです。 +このエラーによると、一度に`s`を可変として2回以上借用することはできないので、このコードは不正だ、とのことです。 +最初の可変借用は`r1`にあり、`println!`で使用されるまで続かないといけませんが、この可変借用の作成から使用までの間に、 +`r1`と同じデータを借用する別の可変借用を`r2`に作成しようとしました。 +同じデータへの複数の可変参照が同時に存在することを禁止する、という制約は、可変化を許可するものの、 +それを非常に統制の取れた形で行えます。これは、新たなRustaceanにとっては、 +壁です。なぜなら、多くの言語では、いつでも好きな時に可変化できるからです。 この制約がある利点は、コンパイラがコンパイル時にデータ競合を防ぐことができる点です。 -データ競合とは、競合条件と類似していて、これら3つの振る舞いが起きる時に発生します: +データ競合とは、競合状態と類似していて、これら3つの振る舞いが起きる時に発生します: データ競合は未定義の振る舞いを引き起こし、実行時に追いかけようとした時に特定し解決するのが難しい問題です。 -しかし、Rustは、データ競合が起こるコードをコンパイルさえしないので、この問題が発生しないようにしてくれるわけです。 +しかし、Rustは、データ競合が起こるコードのコンパイルを拒否することで、この問題が発生しないようにしてくれるわけです。 +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-11-muts-in-separate-scopes/src/main.rs:here}} +``` - +コンパイラは可変と不変な参照を組み合わせることに関しても、似たような規則を強制します。このコードはエラーになります: - - -```rust -let mut s = String::from("hello"); -{ - let r1 = &mut s; + -} // r1はここでスコープを抜けるので、問題なく新しい参照を作ることができる +これがエラーです: -let r2 = &mut s; +```console +{{#include ../listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt}} ``` -可変と不変な参照を組み合わせることに関しても、似たような規則が存在しています。このコードはエラーになります: +ふう!*さらに*不変な参照をしている間は、同じ値に対して可変な参照をすることはできません。 - - -```rust,ignore -let mut s = String::from("hello"); - -let r1 = &s; // 問題なし -let r2 = &s; // 問題なし -let r3 = &mut s; // 大問題! -``` +不変参照の使用者は、それ以降に値が突然変わることなんて予想してません! +しかしながら、複数の不変参照をすることは許されています。 +データを読み込んでいるだけの人に、他人がデータを読み込むことに対して影響を与える能力はないからです。 -これがエラーです: +参照のスコープは、それが導入されたところから始まり、その参照が最後に使用される時点まで続きます。 +例えば、次のコードはコンパイルできるでしょう。不変参照の最後の使用箇所である`println!`は、 +可変参照が導入されるよりも前に発生するからです: -```text -error[E0502]: cannot borrow `s` as mutable because it is also borrowed as -immutable -(エラー: `s`は不変で借用されているので、可変で借用できません) - --> borrow_thrice.rs:6:19 - | -4 | let r1 = &s; // no problem - | - immutable borrow occurs here -5 | let r2 = &s; // no problem -6 | let r3 = &mut s; // BIG PROBLEM - | ^ mutable borrow occurs here -7 | } - | - immutable borrow ends here +```rust,edition2021 +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-13-reference-scope-ends/src/main.rs:here}} ``` -ふう!*さらに*不変な参照をしている間は、可変な参照をすることはできません。不変参照の使用者は、 -それ以降に値が突然変わることなんて予想してません!しかしながら、複数の不変参照をすることは可能です。 -データを読み込んでいるだけの人に、他人がデータを読み込むことに対して影響を与える能力はないからです。 +不変参照`r1`と`r2`のスコープは、それらが最後に使用される`println!`の後で終了します。 +これは可変参照`r3`が作成されるより前のことです。これらのスコープは重なっていないので、 +このコードは許可されます: コンパイラは、スコープの終了より前の時点で参照がもはや使用されていないということを、 +判別できるのです。 -これらのエラーは、時としてイライラするものではありますが、Rustコンパイラがバグの可能性を早期に指摘してくれ(それも実行時ではなくコンパイル時に)、 +借用エラーは、時としてイライラするものではありますが、Rustコンパイラがバグの可能性を早期に指摘してくれ(それも実行時ではなくコンパイル時に)、 問題の発生箇所をズバリ示してくれるのだと覚えておいてください。そうして想定通りにデータが変わらない理由を追いかける必要がなくなります。 -ダングリング参照作りを試してみますが、コンパイラはこれをコンパイルエラーで阻止します: +ダングリング参照を作ってみて、コンパイラがどのようにこれをコンパイルエラーで阻止するか見てみましょう: main.rs:5:16 - | -5 | fn dangle() -> &String { - | ^ expected lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no - value for it to be borrowed from - (助言: この関数の戻り値型は、借用した値を含んでいますが、借用される値がどこにもありません) - = help: consider giving it a 'static lifetime - ('staticライフタイムを与えることを考慮してみてください) +```console +{{#include ../listings/ch04-understanding-ownership/no-listing-14-dangling-reference/output.txt}} ``` -このエラーメッセージは、まだ講義していない機能について触れています: *ライフタイム*です。 +このエラーメッセージは、まだ講義していない機能について触れています: ライフタイムです。 ライフタイムについては第10章で詳しく議論しますが、ライフタイムに関する部分を無視すれば、 このメッセージは、確かにこのコードが問題になる理由に関する鍵を握っています: ```text this function's return type contains a borrowed value, but there is no value -for it to be borrowed from. +for it to be borrowed from ``` - - - - - ファイル名: src/main.rs -```rust,ignore -fn dangle() -> &String { // dangleはStringへの参照を返す - - let s = String::from("hello"); // sは新しいString - - &s // String sへの参照を返す -} // ここで、sはスコープを抜け、ドロップされる。そのメモリは消される。 - // 危険だ +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-15-dangling-reference-annotated/src/main.rs:here}} ``` diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index e33bc3742..a9a0ed65c 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -5,44 +5,46 @@ ## スライス型 -所有権のない別のデータ型は、*スライス*です。スライスにより、コレクション全体ではなく、 -その内の一連の要素を参照することができます。 +*スライス*により、コレクション全体ではなく、その内の連続した要素の列を参照することができます。 +スライスは参照の一種であり、そのため所有権を持っていません。 -ちょっとしたプログラミングの問題を考えてみましょう: 文字列を受け取って、その文字列中の最初の単語を返す関数を書いてください。 +ちょっとしたプログラミングの問題を考えてみましょう: スペースで区切られた複数の単語からなる文字列を受け取って、その文字列中の最初の単語を返す関数を書いてください。 関数が文字列中に空白を見つけられなかったら、文字列全体が一つの単語に違いないので、文字列全体が返されるべきです。 -この関数のシグニチャについて考えてみましょう: +スライスが解決しようとしている問題を理解するために、スライスを使わずにこの関数のシグネチャをどう書くかという問題を通して、 +考えてみましょう。 ```rust,ignore fn first_word(s: &String) -> ? ``` -この関数、`first_word`は引数に`&String`をとります。所有権はいらないので、これで十分です。 +`first_word`関数は引数に`&String`をとります。所有権はいらないので、これで十分です。 ですが、何を返すべきでしょうか?文字列の*一部*について語る方法が全くありません。しかし、 -単語の終端の添え字を返すことができますね。リスト4-7に示したように、その方法を試してみましょう。 +空白によって示される単語の終端の添え字を返すことができますね。リスト4-7に示したように、その方法を試してみましょう。 `String`の値を要素ごとに見て、空白かどうかを確かめる必要があるので、 @@ -85,35 +87,37 @@ Next, we create an iterator over the array of bytes using the `iter` method: ``` -イテレータについて詳しくは、第13章で議論します。今は、`iter`は、コレクション内の各要素を返すメソッドであること、 +イテレータについて詳しくは、[第13章][ch13]で議論します。今は、`iter`は、コレクション内の各要素を返すメソッドであること、 `enumerate`が`iter`の結果をラップして、(結果をそのまま返す)代わりにタプルの一部として各要素を返すことを知っておいてください。 `enumerate`から返ってくるタプルの第1要素は、添え字であり、2番目の要素は、(コレクションの)要素への参照になります。 これは、手動で添え字を計算するよりも少しだけ便利です。 -`enumerate`メソッドがタプルを返すので、Rustのあらゆる場所同様、パターンを使って、そのタプルを分配できます。 -従って、`for`ループ内で、タプルの添え字に対する`i`とタプルの1バイトに対応する`&item`を含むパターンを指定しています。 +`enumerate`メソッドがタプルを返すので、パターンを使って、そのタプルを分配できます。 +パターンについては[第6章][ch6]でさらに議論します。 +`for`ループ内で、タプルの添え字に対する`i`とタプルの1バイトに対応する`&item`を含むパターンを指定しています。 `.iter().enumerate()`から要素への参照を取得するので、パターンに`&`を使っています。 `for`ループ内で、バイトリテラル表記を使用して空白を表すバイトを検索しています。空白が見つかったら、その位置を返します。 @@ -184,8 +188,8 @@ fn second_word(s: &String) -> (usize, usize) { 今、私たちは開始*と*終端の添え字を追うようになりました。特定の状態のデータから計算されたが、 @@ -214,29 +218,23 @@ A *string slice* is a reference to part of a `String`, and it looks like this: ``` -これは、`String`全体への参照を取ることに似ていますが、余計な`[0..5]`という部分が付いています。 -`String`全体への参照ではなく、`String`の一部への参照です。 - - - -`[starting_index..ending_index]`と指定することで、角かっこに範囲を使い、スライスを生成できます。 +`hello`は`String`全体への参照ではなく、追加の`[0..5]`という部分で指定された、`String`の一部への参照です。 +`[starting_index..ending_index]`と指定することで、角かっこに範囲を使い、スライスを生成します。 ここで、`starting_index`はスライスの最初の位置、`ending_index`はスライスの終端位置よりも、 1大きい値です。内部的には、スライスデータ構造は、開始地点とスライスの長さを保持しており、 スライスの長さは`ending_index`から`starting_index`を引いたものに対応します。以上より、 -`let world = &s[6..11];`の場合には、`world`は`s`の添え字6のバイトへのポインタと5という長さを持つスライスになるでしょう。 +`let world = &s[6..11];`の場合には、`world`は`s`の添え字6のバイトへのポインタと`5`という長さを持つスライスになるでしょう。 -文字列sの6バイト目へのポインタと長さ5を保持するworld +3個の表: sのスタックデータを表現するテーブルは、ヒープ上の文字列データ"hello world"のテーブル内の添え字0のバイトを指している。
+3個目の表はスライスworldのスタックデータを表現していて、長さの値5を持ち、ヒープデータの表のバイト6を指している。 -Rustの`..`という範囲記法で、最初の番号(ゼロ)から始めたければ、2連ピリオドの前に値を書かなければいいです。 +Rustの`..`という範囲記法で、添え字0から始めたければ、2連ピリオドの前に値を書かなければいいです。 換言すれば、これらは等価です: ```rust @@ -338,10 +342,10 @@ slice. The type that signifies “string slice” is written as `&str`: ``` リスト4-7で取った方法と同じように、最初の空白を探すことで単語の終端の添え字を取得しています。 @@ -367,7 +371,7 @@ fn second_word(s: &String) -> &str { ``` 借用規則から、何かへの不変な参照がある時、さらに可変な参照を得ることはできないことを思い出してください。 -`clear`は`String`を切り詰める必要があるので、可変な参照を得る必要があります。Rustはこれを認めないので、コンパイルが失敗します。 +`clear`は`String`を切り詰める必要があるので、可変な参照を得る必要があります。 +`clear`の呼び出しの後の`println!`は`word`中の参照を使用するので、不変参照はその時点でもまだ有効でなくてはいけません。 +Rustは`clear`中の可変参照と`word`中の不変参照が同時に存在することを認めないので、コンパイルが失敗します。 RustのおかげでAPIが使いやすくなるだけでなく、ある種のエラー全てを完全にコンパイル時に排除してくれるのです! + + + -#### 文字列リテラルはスライスである +#### スライスとしての文字列リテラル もし、文字列スライスがあるなら、それを直接渡せます。`String`があるなら、 -その`String`全体のスライスを渡せます。`String`への参照の代わりに文字列スライスを取るよう関数を定義すると、 +その`String`のスライスか、`String`への参照を渡せます。この柔軟性は、第15章の[「関数やメソッドで暗黙的な参照外し型強制」][deref-coercions]で扱う機能、 +*参照外し型強制*の利点を活用して実現されています。 + + + +`String`への参照の代わりに文字列スライスを取るよう関数を定義すると、 何も機能を失うことなくAPIをより一般的で有益なものにできるのです。 Filename: src/main.rs @@ -508,7 +531,7 @@ without losing any functionality: 文字列リテラルは、ご想像通り、文字列に特化したものです。ですが、もっと一般的なスライス型も存在します。 @@ -519,8 +542,8 @@ let a = [1, 2, 3, 4, 5]; ``` 文字列の一部を参照したくなる可能性があるのと同様、配列の一部を参照したくなる可能性もあります。 @@ -530,6 +553,8 @@ to part of an array. We’d do so like this: let a = [1, 2, 3, 4, 5]; let slice = &a[1..3]; + +assert_eq!(slice, &[2, 3]); ``` + +[ch13]: ch13-02-iterators.html +[ch6]: ch06-02-match.html#値に束縛されるパターン [strings]: ch08-02-strings.html#文字列でutf-8でエンコードされたテキストを保持する +[deref-coercions]: ch15-02-deref.html#関数やメソッドで暗黙的な参照外し型強制 From 7dce9e15dfa4aa9bb17212a042ef4c47d958854f Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:02 +0900 Subject: [PATCH 06/22] =?UTF-8?q?ch05=20=E6=A7=8B=E9=80=A0=E4=BD=93?= =?UTF-8?q?=E3=82=92=E4=BD=BF=E7=94=A8=E3=81=97=E3=81=A6=E9=96=A2=E4=BF=82?= =?UTF-8?q?=E3=81=AE=E3=81=82=E3=82=8B=E3=83=87=E3=83=BC=E3=82=BF=E3=82=92?= =?UTF-8?q?=E6=A7=8B=E9=80=A0=E5=8C=96=E3=81=99=E3=82=8B=E3=81=AE=E5=92=8C?= =?UTF-8?q?=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-05-01/Cargo.toml | 3 +- .../listing-05-01/src/main.rs | 2 +- .../listing-05-02/Cargo.toml | 3 +- .../listing-05-02/src/main.rs | 10 +- .../listing-05-03/Cargo.toml | 3 +- .../listing-05-03/src/main.rs | 10 +- .../listing-05-04/Cargo.toml | 3 +- .../listing-05-04/src/main.rs | 6 +- .../listing-05-05/Cargo.toml | 3 +- .../listing-05-05/src/main.rs | 6 +- .../listing-05-06/Cargo.toml | 3 +- .../listing-05-06/src/main.rs | 14 +- .../listing-05-07/Cargo.toml | 3 +- .../listing-05-07/src/main.rs | 11 +- .../listing-05-08/Cargo.lock | 3 +- .../listing-05-08/Cargo.toml | 5 +- .../listing-05-08/output.txt | 5 +- .../listing-05-08/src/main.rs | 1 + .../listing-05-09/Cargo.lock | 3 +- .../listing-05-09/Cargo.toml | 5 +- .../listing-05-10/Cargo.lock | 3 +- .../listing-05-10/Cargo.toml | 5 +- .../listing-05-11/Cargo.lock | 3 +- .../listing-05-11/Cargo.toml | 5 +- .../listing-05-11/output.txt | 13 +- .../listing-05-11/src/main.rs | 1 + .../listing-05-12/Cargo.lock | 3 +- .../listing-05-12/Cargo.toml | 5 +- .../listing-05-12/output.txt | 4 +- .../listing-05-13/Cargo.lock | 3 +- .../listing-05-13/Cargo.toml | 5 +- .../listing-05-13/src/main.rs | 1 + .../listing-05-14/Cargo.lock | 3 +- .../listing-05-14/Cargo.toml | 5 +- .../listing-05-15/Cargo.lock | 3 +- .../listing-05-15/Cargo.toml | 5 +- .../listing-05-16/Cargo.lock | 3 +- .../listing-05-16/Cargo.toml | 5 +- .../no-listing-01-tuple-structs/Cargo.toml | 3 +- .../no-listing-01-tuple-structs/src/main.rs | 8 +- .../Cargo.toml | 3 +- .../output.txt | 33 +- .../src/main.rs | 2 +- .../Cargo.lock | 3 +- .../Cargo.toml | 5 +- .../src/main.rs | 4 +- .../Cargo.lock | 7 + .../Cargo.toml | 6 + .../src/main.rs | 5 + .../no-listing-05-dbg-macro/Cargo.lock | 5 + .../no-listing-05-dbg-macro/Cargo.toml | 6 + .../no-listing-05-dbg-macro/output.txt | 9 + .../no-listing-05-dbg-macro/src/main.rs | 15 + .../Cargo.lock | 5 + .../Cargo.toml | 6 + .../src/main.rs | 25 + .../output-only-01-debug/Cargo.lock | 3 +- .../output-only-01-debug/Cargo.toml | 5 +- .../output-only-01-debug/output.txt | 24 +- .../output-only-02-pretty-debug/Cargo.lock | 3 +- .../output-only-02-pretty-debug/Cargo.toml | 5 +- .../output-only-02-pretty-debug/output.txt | 4 +- src/ch05-00-structs.md | 31 +- src/ch05-01-defining-structs.md | 573 ++++++++++-------- src/ch05-02-example-structs.md | 347 ++++++----- src/ch05-03-method-syntax.md | 425 ++++++------- 66 files changed, 973 insertions(+), 774 deletions(-) create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/Cargo.lock create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/Cargo.toml create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/src/main.rs create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/Cargo.lock create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/Cargo.toml create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/output.txt create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/src/main.rs create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/Cargo.lock create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/Cargo.toml create mode 100644 listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/src/main.rs diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-01/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-01/Cargo.toml index 431e5c305..3232b6065 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-01/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "structs" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-01/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-01/src/main.rs index a7cff6ec2..16dd15b29 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-01/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-01/src/main.rs @@ -1,9 +1,9 @@ // ANCHOR: here struct User { + active: bool, username: String, email: String, sign_in_count: u64, - active: bool, } // ANCHOR_END: here diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-02/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-02/Cargo.toml index 431e5c305..3232b6065 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-02/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "structs" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-02/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-02/src/main.rs index 390c8ff19..122d25164 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-02/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-02/src/main.rs @@ -1,17 +1,17 @@ struct User { + active: bool, username: String, email: String, sign_in_count: u64, - active: bool, } +// ANCHOR: here fn main() { - // ANCHOR: here let user1 = User { - email: String::from("someone@example.com"), - username: String::from("someusername123"), active: true, + username: String::from("someusername123"), + email: String::from("someone@example.com"), sign_in_count: 1, }; - // ANCHOR_END: here } +// ANCHOR_END: here diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-03/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-03/Cargo.toml index 431e5c305..3232b6065 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-03/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "structs" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-03/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-03/src/main.rs index c599c9d60..35eea8a9a 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-03/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-03/src/main.rs @@ -1,19 +1,19 @@ struct User { + active: bool, username: String, email: String, sign_in_count: u64, - active: bool, } +// ANCHOR: here fn main() { - // ANCHOR: here let mut user1 = User { - email: String::from("someone@example.com"), - username: String::from("someusername123"), active: true, + username: String::from("someusername123"), + email: String::from("someone@example.com"), sign_in_count: 1, }; user1.email = String::from("anotheremail@example.com"); - // ANCHOR_END: here } +// ANCHOR_END: here diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-04/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-04/Cargo.toml index 431e5c305..3232b6065 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-04/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "structs" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-04/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-04/src/main.rs index f934d4c00..8614561c1 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-04/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-04/src/main.rs @@ -1,16 +1,16 @@ struct User { + active: bool, username: String, email: String, sign_in_count: u64, - active: bool, } // ANCHOR: here fn build_user(email: String, username: String) -> User { User { - email: email, - username: username, active: true, + username: username, + email: email, sign_in_count: 1, } } diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-05/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-05/Cargo.toml index 431e5c305..3232b6065 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-05/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "structs" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-05/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-05/src/main.rs index 1833aa8e4..c893c86a9 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-05/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-05/src/main.rs @@ -1,16 +1,16 @@ struct User { + active: bool, username: String, email: String, sign_in_count: u64, - active: bool, } // ANCHOR: here fn build_user(email: String, username: String) -> User { User { - email, - username, active: true, + username, + email, sign_in_count: 1, } } diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-06/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-06/Cargo.toml index 431e5c305..3232b6065 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-06/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "structs" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-06/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-06/src/main.rs index 6c6d83d9b..15e7690e1 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-06/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-06/src/main.rs @@ -1,24 +1,28 @@ struct User { + active: bool, username: String, email: String, sign_in_count: u64, - active: bool, } +// ANCHOR: here fn main() { + // --snip-- + // ANCHOR_END: here + let user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, }; - // ANCHOR: here + let user2 = User { - email: String::from("another@example.com"), - username: String::from("anotherusername567"), active: user1.active, + username: user1.username, + email: String::from("another@example.com"), sign_in_count: user1.sign_in_count, }; - // ANCHOR_END: here } +// ANCHOR_END: here diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-07/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-07/Cargo.toml index 431e5c305..3232b6065 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-07/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "structs" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-07/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-07/src/main.rs index 17cef457b..008ad18f6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-07/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-07/src/main.rs @@ -1,23 +1,26 @@ struct User { + active: bool, username: String, email: String, sign_in_count: u64, - active: bool, } +// ANCHOR: here fn main() { + // --snip-- + // ANCHOR_END: here + let user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, }; - // ANCHOR: here + let user2 = User { email: String::from("another@example.com"), - username: String::from("anotherusername567"), ..user1 }; - // ANCHOR_END: here } +// ANCHOR_END: here diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-08/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/listing-05-08/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-08/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-08/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-08/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-08/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-08/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-08/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-08/output.txt b/listings/ch05-using-structs-to-structure-related-data/listing-05-08/output.txt index 88e10d320..aaedb98a4 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-08/output.txt +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-08/output.txt @@ -1,5 +1,6 @@ $ cargo run - Compiling structs v0.1.0 (file:///projects/structs) + Compiling rectangles v0.1.0 (file:///projects/rectangles) Finished dev [unoptimized + debuginfo] target(s) in 0.42s - Running `target/debug/structs` + Running `target/debug/rectangles` The area of the rectangle is 1500 square pixels. +(長方形の面積は、1500平方ピクセルです) diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-08/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-08/src/main.rs index f324529fd..587e870bb 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-08/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-08/src/main.rs @@ -4,6 +4,7 @@ fn main() { let height1 = 50; println!( + // 長方形の面積は、{}平方ピクセルです "The area of the rectangle is {} square pixels.", area(width1, height1) ); diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-09/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/listing-05-09/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-09/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-09/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-09/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-09/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-09/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-09/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-10/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/listing-05-10/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-10/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-10/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-10/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-10/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-10/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-10/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-11/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/listing-05-11/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-11/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-11/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-11/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-11/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-11/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-11/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt b/listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt index 1e03d0625..d19319d00 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt @@ -1,6 +1,7 @@ $ cargo run - Compiling structs v0.1.0 (file:///projects/structs) + Compiling rectangles v0.1.0 (file:///projects/rectangles) error[E0277]: `Rectangle` doesn't implement `std::fmt::Display` +(エラー: `Rectangle`は`std::fmt::Display`を実装していません) --> src/main.rs:12:29 | 12 | println!("rect1 is {}", rect1); @@ -8,11 +9,9 @@ error[E0277]: `Rectangle` doesn't implement `std::fmt::Display` | = help: the trait `std::fmt::Display` is not implemented for `Rectangle` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead - = note: required by `std::fmt::Display::fmt` - -error: aborting due to previous error + (ヘルプ: `std::fmt::Display`は`Rectangle`に対して実装されていません) + (注釈: フォーマット文字列では代わりに`{:?}`(またはpretty-printするためには{:#?})が使用できるかもしれません) + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0277`. -error: could not compile `structs`. - -To learn more, run the command again with --verbose. +error: could not compile `rectangles` (bin "rectangles") due to 1 previous error diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-11/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-11/src/main.rs index 0ff8dcc8c..5e45f74e8 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-11/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-11/src/main.rs @@ -9,5 +9,6 @@ fn main() { height: 50, }; + // rect1は{}です println!("rect1 is {}", rect1); } diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-12/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/listing-05-12/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-12/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-12/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-12/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-12/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-12/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-12/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-12/output.txt b/listings/ch05-using-structs-to-structure-related-data/listing-05-12/output.txt index 3abfb4257..c37be6b5b 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-12/output.txt +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-12/output.txt @@ -1,5 +1,5 @@ $ cargo run - Compiling structs v0.1.0 (file:///projects/structs) + Compiling rectangles v0.1.0 (file:///projects/rectangles) Finished dev [unoptimized + debuginfo] target(s) in 0.48s - Running `target/debug/structs` + Running `target/debug/rectangles` rect1 is Rectangle { width: 30, height: 50 } diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-13/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/listing-05-13/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-13/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-13/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-13/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-13/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-13/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-13/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-13/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/listing-05-13/src/main.rs index e4f45e868..a5c6cb1f9 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-13/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-13/src/main.rs @@ -17,6 +17,7 @@ fn main() { }; println!( + // 長方形の面積は{}平方ピクセルです。 "The area of the rectangle is {} square pixels.", rect1.area() ); diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-14/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/listing-05-14/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-14/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-14/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-14/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-14/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-14/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-14/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-15/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/listing-05-15/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-15/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-15/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-15/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-15/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-15/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-15/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-16/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/listing-05-16/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-16/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-16/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/listing-05-16/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/listing-05-16/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/listing-05-16/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/listing-05-16/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/Cargo.toml index 431e5c305..3232b6065 100644 --- a/listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "structs" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs index 4c92c5d77..0d993162b 100644 --- a/listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs @@ -1,9 +1,7 @@ -fn main() { - // ANCHOR: here - struct Color(i32, i32, i32); - struct Point(i32, i32, i32); +struct Color(i32, i32, i32); +struct Point(i32, i32, i32); +fn main() { let black = Color(0, 0, 0); let origin = Point(0, 0, 0); - // ANCHOR_END: here } diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/Cargo.toml index dec1c4bd5..d36dbc1d3 100644 --- a/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "structs" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt b/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt index 9a75534c3..5f9344c51 100644 --- a/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt @@ -1,20 +1,31 @@ $ cargo run Compiling structs v0.1.0 (file:///projects/structs) error[E0106]: missing lifetime specifier - --> src/main.rs:2:15 + --> src/main.rs:3:15 + | +3 | username: &str, + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +1 ~ struct User<'a> { +2 | active: bool, +3 ~ username: &'a str, | -2 | username: &str, - | ^ expected lifetime parameter error[E0106]: missing lifetime specifier - --> src/main.rs:3:12 + --> src/main.rs:4:12 + | +4 | email: &str, + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +1 ~ struct User<'a> { +2 | active: bool, +3 | username: &str, +4 ~ email: &'a str, | -3 | email: &str, - | ^ expected lifetime parameter - -error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0106`. -error: could not compile `structs`. - -To learn more, run the command again with --verbose. +error: could not compile `structs` (bin "structs") due to 2 previous errors diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/src/main.rs index 3cf6ffa4f..96092d042 100644 --- a/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/src/main.rs @@ -1,8 +1,8 @@ struct User { + active: bool, username: &str, email: &str, sign_in_count: u64, - active: bool, } fn main() { diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/src/main.rs index d5b1692a4..47fedc552 100644 --- a/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/src/main.rs +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/src/main.rs @@ -6,8 +6,8 @@ struct Rectangle { // ANCHOR: here impl Rectangle { - fn square(size: u32) -> Rectangle { - Rectangle { + fn square(size: u32) -> Self { + Self { width: size, height: size, } diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/Cargo.lock new file mode 100644 index 000000000..fb30ed9c8 --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "structs" +version = "0.1.0" diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/Cargo.toml new file mode 100644 index 000000000..3232b6065 --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "structs" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/src/main.rs new file mode 100644 index 000000000..d48c94e99 --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/src/main.rs @@ -0,0 +1,5 @@ +struct AlwaysEqual; + +fn main() { + let subject = AlwaysEqual; +} diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/Cargo.lock new file mode 100644 index 000000000..4aabe7da6 --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "rectangles" +version = "0.1.0" diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/Cargo.toml new file mode 100644 index 000000000..4a279a450 --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rectangles" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/output.txt b/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/output.txt new file mode 100644 index 000000000..bfb88ebee --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/output.txt @@ -0,0 +1,9 @@ +$ cargo run + Compiling rectangles v0.1.0 (file:///projects/rectangles) + Finished dev [unoptimized + debuginfo] target(s) in 0.61s + Running `target/debug/rectangles` +[src/main.rs:10:16] 30 * scale = 60 +[src/main.rs:14:5] &rect1 = Rectangle { + width: 60, + height: 50, +} diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/src/main.rs new file mode 100644 index 000000000..dd0342959 --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/src/main.rs @@ -0,0 +1,15 @@ +#[derive(Debug)] +struct Rectangle { + width: u32, + height: u32, +} + +fn main() { + let scale = 2; + let rect1 = Rectangle { + width: dbg!(30 * scale), + height: 50, + }; + + dbg!(&rect1); +} diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/Cargo.lock new file mode 100644 index 000000000..4aabe7da6 --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "rectangles" +version = "0.1.0" diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/Cargo.toml new file mode 100644 index 000000000..4a279a450 --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rectangles" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/src/main.rs b/listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/src/main.rs new file mode 100644 index 000000000..f893f095c --- /dev/null +++ b/listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/src/main.rs @@ -0,0 +1,25 @@ +#[derive(Debug)] +struct Rectangle { + width: u32, + height: u32, +} + +// ANCHOR: here +impl Rectangle { + fn width(&self) -> bool { + self.width > 0 + } +} + +fn main() { + let rect1 = Rectangle { + width: 30, + height: 50, + }; + + if rect1.width() { + // 長方形は非ゼロの幅を持っています; それは{}です + println!("The rectangle has a nonzero width; it is {}", rect1.width); + } +} +// ANCHOR_END: here diff --git a/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt b/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt index c891d9342..5c67e0b06 100644 --- a/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt +++ b/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt @@ -1,18 +1,22 @@ $ cargo run - Compiling structs v0.1.0 (file:///projects/structs) -error[E0277]: `Rectangle` doesn't implement `std::fmt::Debug` + Compiling rectangles v0.1.0 (file:///projects/rectangles) +error[E0277]: `Rectangle` doesn't implement `Debug` +(エラー: `Rectangle`は`Debug`を実装していません) --> src/main.rs:12:31 | 12 | println!("rect1 is {:?}", rect1); | ^^^^^ `Rectangle` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Rectangle` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required by `std::fmt::Debug::fmt` - -error: aborting due to previous error + = help: the trait `Debug` is not implemented for `Rectangle` + = note: add `#[derive(Debug)]` to `Rectangle` or manually `impl Debug for Rectangle` + (ヘルプ: トレイト`Debug`は`Rectangle`に対して実装されていません) + (注釈: `Rectangle`に`#[derive(Debug)]`を追加するか、手動で`impl Debug for Rectangle`してください) + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Rectangle` with `#[derive(Debug)]` + | +1 + #[derive(Debug)] +2 | struct Rectangle { + | For more information about this error, try `rustc --explain E0277`. -error: could not compile `structs`. - -To learn more, run the command again with --verbose. +error: could not compile `rectangles` (bin "rectangles") due to 1 previous error diff --git a/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/Cargo.lock b/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/Cargo.lock index bede081a0..4aabe7da6 100644 --- a/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/Cargo.lock +++ b/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "structs" +name = "rectangles" version = "0.1.0" - diff --git a/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/Cargo.toml b/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/Cargo.toml index 431e5c305..4a279a450 100644 --- a/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/Cargo.toml +++ b/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "structs" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/output.txt b/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/output.txt index 099ef9eac..db6deed9b 100644 --- a/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/output.txt +++ b/listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/output.txt @@ -1,7 +1,7 @@ $ cargo run - Compiling structs v0.1.0 (file:///projects/structs) + Compiling rectangles v0.1.0 (file:///projects/rectangles) Finished dev [unoptimized + debuginfo] target(s) in 0.48s - Running `target/debug/structs` + Running `target/debug/rectangles` rect1 is Rectangle { width: 30, height: 50, diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index 28fca40bf..16458e0af 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -5,19 +5,26 @@ # 構造体を使用して関係のあるデータを構造化する *struct*または、*構造体*は、意味のあるグループを形成する複数の関連した値をまとめ、名前付けできる独自のデータ型です。 あなたがオブジェクト指向言語に造詣が深いなら、*struct*はオブジェクトのデータ属性みたいなものです。 -この章では、タプルと構造体を対照的に比較し、構造体の使用法をデモし、メソッドや関連関数を定義して、 -構造体のデータに紐付く振る舞いを指定する方法について議論します。構造体と*enum*(第6章で議論します)は、 -自分のプログラム領域で新しい型を定義し、Rustのコンパイル時型精査機能をフル活用する構成要素になります。 +この章では、すでに学習したものに積み重ねる目的でタプルと構造体を対照的に比較し、データをまとめるのに構造体がより良い方法となるのはどういう場合かを示します。 + + + +構造体を定義してインスタンス化する方法を実演します。 +関連関数、特に*メソッド*と呼ばれる種類の関連関数を定義して、構造体型に紐付く振る舞いを指定する方法について議論します。 +構造体と*enum*(第6章で議論します)は、自分のプログラム領域で新しい型を定義し、Rustのコンパイル時型精査機能をフル活用する構成要素になります。 \ No newline at end of file diff --git a/src/ch05-01-defining-structs.md b/src/ch05-01-defining-structs.md index f53841954..ba2a031be 100644 --- a/src/ch05-01-defining-structs.md +++ b/src/ch05-01-defining-structs.md @@ -5,16 +5,18 @@ ## 構造体を定義し、インスタンス化する -構造体は第3章で議論したタプルと似ています。タプル同様、構造体の一部を異なる型にできます。 -一方タプルとは違って、各データ片には名前をつけるので、値の意味が明確になります。 -この名前のおかげで、構造体はタプルに比して、より柔軟になるわけです: データの順番に頼って、 +構造体は、[「タプル型」][tuples]の節で議論したタプルと、どちらも関係する複数の値を抱えるという点で似ています。 +タプル同様、構造体の一部を異なる型にできます。 +一方タプルとは違って、構造体では各データ片には名前をつけるので、値の意味が明確になります。 +これらの名前が付いていることで、構造体はタプルに比して、より柔軟になるわけです: データの順番に頼って、 インスタンスの値を指定したり、アクセスしたりする必要がないのです。 + +ファイル名: src/main.rs + ```rust -struct User { - username: String, - email: String, - sign_in_count: u64, - active: bool, -} +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-01/src/main.rs:here}} ``` 構造体を定義した後に使用するには、各フィールドに対して具体的な値を指定して構造体の*インスタンス*を生成します。 -インスタンスは、構造体名を記述し、`key: value`ペアを含む波かっこを付け加えることで生成します。 +インスタンスは、構造体名を記述し、*key: value*ペアを含む波かっこを付け加えることで生成します。 ここで、キーはフィールド名、値はそのフィールドに格納したいデータになります。フィールドは、 構造体で宣言した通りの順番に指定する必要はありません。換言すると、構造体定義とは、 型に対する一般的な雛形のようなものであり、インスタンスは、その雛形を特定のデータで埋め、その型の値を生成するわけです。 例えば、リスト5-2で示されたように特定のユーザを宣言することができます。 + + +ファイル名: src/main.rs + ```rust -# struct User { -# username: String, -# email: String, -# sign_in_count: u64, -# active: bool, -# } -# -let user1 = User { - email: String::from("someone@example.com"), - username: String::from("someusername123"), - active: true, - sign_in_count: 1, -}; +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-02/src/main.rs:here}} ``` -構造体から特定の値を得るには、ドット記法が使えます。このユーザのEメールアドレスだけが欲しいなら、 -この値を使いたかった場所全部で`user1.email`が使えます。インスタンスが可変であれば、 -ドット記法を使い特定のフィールドに代入することで値を変更できます。リスト5-3では、 -可変な`User`インスタンスの`email`フィールド値を変更する方法を示しています。 +構造体から特定の値を得るには、ドット記法を使います。例えば、 +このユーザのEメールアドレスにアクセスするには、`user1.email`を使います。 +インスタンスが可変であれば、ドット記法を使い特定のフィールドに代入することで値を変更できます。 +リスト5-3では、可変な`User`インスタンスの`email`フィールド値を変更する方法を示しています。 + + + +ファイル名: src/main.rs ```rust -# struct User { -# username: String, -# email: String, -# sign_in_count: u64, -# active: bool, -# } -# -let mut user1 = User { - email: String::from("someone@example.com"), - username: String::from("someusername123"), - active: true, - sign_in_count: 1, -}; - -user1.email = String::from("anotheremail@example.com"); +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-03/src/main.rs:here}} ``` + +ファイル名: src/main.rs + ```rust -# struct User { -# username: String, -# email: String, -# sign_in_count: u64, -# active: bool, -# } -# -fn build_user(email: String, username: String) -> User { - User { - email: email, - username: username, - active: true, - sign_in_count: 1, - } -} +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-04/src/main.rs:here}} ``` 構造体のフィールドと同じ名前を関数の引数にもつけることは筋が通っていますが、 @@ -182,47 +163,44 @@ would get even more annoying. Luckily, there's a convenient shorthand! 構造体にもっとフィールドがあれば、名前を繰り返すことはさらに煩わしくなるでしょう。 幸運なことに、便利な省略記法があります! + -### フィールドと変数が同名の時にフィールド初期化省略記法を使う + + +### フィールド初期化省略記法を使う 仮引数名と構造体のフィールド名がリスト5-4では、全く一緒なので、*フィールド初期化省略*記法を使って`build_user`を書き換えても、 -振る舞いは全く同じにしつつ、リスト5-5に示したように`email`と`username`を繰り返さなくてもよくなります。 +振る舞いは全く同じにしつつ、リスト5-5に示したように`username`と`email`を繰り返さなくてもよくなります。 + + + +ファイル名: src/main.rs ```rust -# struct User { -# username: String, -# email: String, -# sign_in_count: u64, -# active: bool, -# } -# -fn build_user(email: String, username: String) -> User { - User { - email, - username, - active: true, - sign_in_count: 1, - } -} +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-05/src/main.rs:here}} ``` -リスト5-5: `email`と`username`引数が構造体のフィールドと同名なので、 +リスト5-5: `username`と`email`引数が構造体のフィールドと同名なので、 フィールド初期化省略法を使用する`build_user`関数 ### 構造体更新記法で他のインスタンスからインスタンスを生成する -多くは前のインスタンスの値を使用しつつ、変更する箇所もある形で新しいインスタンスを生成できるとしばしば有用です。 +他のインスタンスからの値の多くの部分を含みつつ、一部を変更する形で新しいインスタンスを生成できるとしばしば有用です。 *構造体更新記法*でそうすることができます。 -まず、リスト5-6では、更新記法なしで`user2`に新しい`User`インスタンスを生成する方法を示しています。 -`email`と`username`には新しい値をセットしていますが、それ以外にはリスト5-2で生成した`user1`の値を使用しています。 +まず、リスト5-6では、更新記法なしで普通に`user2`に新しい`User`インスタンスを生成する方法を示しています。 +`email`には新しい値をセットしていますが、それ以外にはリスト5-2で生成した`user1`の値を使用しています。 + + + +ファイル名: src/main.rs ```rust -# struct User { -# username: String, -# email: String, -# sign_in_count: u64, -# active: bool, -# } -# -# let user1 = User { -# email: String::from("someone@example.com"), -# username: String::from("someusername123"), -# active: true, -# sign_in_count: 1, -# }; -# -let user2 = User { - email: String::from("another@example.com"), - username: String::from("anotherusername567"), - active: user1.active, - sign_in_count: user1.sign_in_count, -}; +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-06/src/main.rs:here}} ``` リスト5-6: `user1`の一部の値を使用しつつ、新しい`User`インスタンスを生成する @@ -300,203 +266,275 @@ explicitly set should have the same value as the fields in the given instance. 構造体更新記法を使用すると、リスト5-7に示したように、コード量を減らしつつ、同じ効果を達成できます。`..`という記法により、 明示的にセットされていない残りのフィールドが、与えられたインスタンスのフィールドと同じ値になるように指定します。 + + +ファイル名: src/main.rs + ```rust -# struct User { -# username: String, -# email: String, -# sign_in_count: u64, -# active: bool, -# } -# -# let user1 = User { -# email: String::from("someone@example.com"), -# username: String::from("someusername123"), -# active: true, -# sign_in_count: 1, -# }; -# -let user2 = User { - email: String::from("another@example.com"), - username: String::from("anotherusername567"), - ..user1 -}; +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-07/src/main.rs:here}} ``` -リスト5-7: 構造体更新記法を使用して、新しい`User`インスタンス用の値に新しい`email`と`username`をセットしつつ、 -残りの値は、`user1`変数のフィールド値を使う +リスト5-7: 構造体更新記法を使用して、新しい`User`インスタンス用の値に新しい`email`をセットしつつ、 +残りの値は`user1`を使う -リスト5-7のコードも、`email`と`username`については異なる値、`active`と`sign_in_count`フィールドについては、 +リスト5-7のコードも、`email`については`user1`とは異なる値、`username`、`active`と`sign_in_count`フィールドについては、 `user1`と同じ値になるインスタンスを`user2`に生成します。 +`..user1`は、残りのフィールドについては`user1`の対応するフィールドから値を取る、ということを示すために最後に来る必要がありますが、 +フィールドについては好きなだけ多く、構造体定義中のフィールドの順序とは無関係に好きな順で、値を指定してかまいません。 + + + +構造体更新記法は代入と同様に`=`を使います; これは、[「ムーブによる変数とデータの相互作用」][move]の節で見たのと同じように、 +データをムーブするからです。この例で言うと、`user2`を作成した後は、もう`user1`をそっくりそのまま使うことはできません。 +`user1`の`username`フィールド中の`String`が`user2`の中にムーブされてしまったからです。 +もし`user2`に、`email`と`username`のために新しい`String`値を与えていたなら、つまり、 +`user1`からは`active`と`sign_in_count`の値だけを使用していたなら、`user2`を作成した後も`user1`はまだ有効だったでしょう。 +`active`と`sign_in_count`はどちらも`Copy`トレイトを実装した型なので、[「スタックのみのデータ: コピー」][copy]節で議論した振る舞いが適用されるからです。 ### 異なる型を生成する名前付きフィールドのないタプル構造体を使用する -構造体名により追加の意味を含むものの、フィールドに紐づけられた名前がなく、むしろフィールドの型だけの*タプル構造体*と呼ばれる、 -タプルに似た構造体を定義することもできます。タプル構造体は、構造体名が提供する追加の意味は含むものの、 +Rustは、構造体名により追加の意味を含むものの、フィールドに紐づけられた名前がなく、むしろフィールドの型だけの*タプル構造体*と呼ばれる、 +タプルに似た構造体もサポートしています。タプル構造体は、構造体名が提供する追加の意味は含むものの、 フィールドに紐付けられた名前はありません; むしろ、フィールドの型だけが存在します。タプル構造体は、タプル全体に名前をつけ、 -そのタプルを他のタプルとは異なる型にしたい場合に有用ですが、普通の構造体のように各フィールド名を与えるのは、 -冗長、または余計になるでしょう。 +そのタプルを他のタプルとは異なる型にしたいが、普通の構造体のように各フィールド名を与えるのは、 +冗長、または余計という場合に有用です。 -タプル構造体を定義するには、`struct`キーワードの後に構造体名、さらにタプルに含まれる型を続けます。 -例えば、こちらは、`Color`と`Point`という2種類のタプル構造体の定義と使用法です: +タプル構造体を定義するには、`struct`キーワードの後に構造体名、さらにタプルに含まれる型を続けてください。 +例えば、ここでは、`Color`と`Point`という2種類のタプル構造体の定義して使用します: -```rust -struct Color(i32, i32, i32); -struct Point(i32, i32, i32); + + +ファイル名: src/main.rs -let black = Color(0, 0, 0); -let origin = Point(0, 0, 0); +```rust +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs}} ``` `black`と`origin`の値は、違う型であることに注目してください。これらは、異なるタプル構造体のインスタンスだからですね。 定義された各構造体は、構造体内のフィールドが同じ型であっても、それ自身が独自の型になります。 例えば、`Color`型を引数に取る関数は、`Point`を引数に取ることはできません。たとえ、両者の型が、 3つの`i32`値からできていてもです。それ以外については、タプル構造体のインスタンスは、 -タプルと同じように振る舞います: 分配して個々の部品にしたり、`.`と添え字を使用して個々の値にアクセスするなどです。 +分配して個々の部品にしたり、`.`と添え字を使用して個々の値にアクセスできるという点で、タプルと似ています。 ### フィールドのないユニット(よう)構造体 -また、一切フィールドのない構造体を定義することもできます!これらは、`()`、ユニット型と似たような振る舞いをすることから、 +また、一切フィールドのない構造体を定義することもできます!これらは、`()`、 +[「タプル型」][tuples]の節で言及したユニット型と似たような振る舞いをすることから、 *ユニット様構造体*と呼ばれます。ユニット様構造体は、ある型にトレイトを実装するけれども、 型自体に保持させるデータは一切ない場面に有効になります。トレイトについては第10章で議論します。 +以下は、`AlwaysEqual`という名前のユニット様構造体を宣言し、インスタンス化する例です: - -error[E0106]: missing lifetime specifier +`AlwaysEqual`を定義するためには、`struct`キーワード、付けたい名前、そしてセミコロンを使います。 +波括弧や丸括弧は不要です! +次に、同じようにして、`subject`変数に`AlwaysEqual`のインスタンスを得られます: 波括弧や丸括弧を付けずに、定義した名前を使います。 +後でこの型の振る舞いを、おそらくはテスト目的で既知の結果を得るために、`AlwaysEqual`のすべてのインスタンスが常に他の任意の型と等価であるように実装することを想像してください。 +この挙動を実装するためにデータはまったく必要ないですね! +トレイトを定義して、ユニット様構造体も含めた任意の型にそれを実装する方法については10章で触れます。 -| -3 | email: &str, -| ^ expected lifetime parameter -``` + -In Chapter 10, we’ll discuss how to fix these errors so you can store -references in structs, but for now, we’ll fix errors like these using owned -types like `String` instead of references like `&str`. + > ### 構造体データの所有権 > > リスト5-1の`User`構造体定義において、`&str`文字列スライス型ではなく、所有権のある`String`型を使用しました。 -> これは意図的な選択です。というのも、この構造体のインスタンスには全データを所有してもらう必要があり、 +> これは意図的な選択です。というのも、この構造体の各インスタンスには自身の全データを所有してもらう必要があり、 > このデータは、構造体全体が有効な間はずっと有効である必要があるのです。 > > 構造体に、他の何かに所有されたデータへの参照を保持させることもできますが、 > そうするには*ライフタイム*という第10章で議論するRustの機能を使用しなければなりません。 > ライフタイムのおかげで構造体に参照されたデータが、構造体自体が有効な間、ずっと有効であることを保証してくれるのです。 -> ライフタイムを指定せずに構造体に参照を保持させようとしたとしましょう。以下の通りですが、これは動きません: +> 次のように、ライフタイムを指定せずに構造体に参照を保持させようとしたとしましょう。これは動きません: > > ファイル名: src/main.rs > -> ```rust,ignore +> ```rust,ignore,does_not_compile > struct User { +> active: bool, > username: &str, > email: &str, > sign_in_count: u64, -> active: bool, > } > > fn main() { > let user1 = User { -> email: "someone@example.com", -> username: "someusername123", > active: true, +> username: "someusername123", +> email: "someone@example.com", > sign_in_count: 1, > }; > } @@ -504,21 +542,58 @@ types like `String` instead of references like `&str`. > > コンパイラは、ライフタイム指定子が必要だと怒るでしょう: > -> ```text +> ```console +> $ cargo run +> Compiling structs v0.1.0 (file:///projects/structs) > error[E0106]: missing lifetime specifier > (エラー: ライフタイム指定子がありません) -> --> -> | -> 2 | username: &str, -> | ^ expected lifetime parameter -> (ライフタイム引数を予期しました) +> --> src/main.rs:3:15 +> | +> 3 | username: &str, +> | ^ expected named lifetime parameter +> | (ライフタイム引数を予期しました) +> | +> help: consider introducing a named lifetime parameter +> | +> 1 ~ struct User<'a> { +> 2 | active: bool, +> 3 ~ username: &'a str, +> | > > error[E0106]: missing lifetime specifier -> --> -> | -> 3 | email: &str, -> | ^ expected lifetime parameter +> --> src/main.rs:4:12 +> | +> 4 | email: &str, +> | ^ expected named lifetime parameter +> | +> help: consider introducing a named lifetime parameter +> | +> 1 ~ struct User<'a> { +> 2 | active: bool, +> 3 | username: &str, +> 4 ~ email: &'a str, +> | +> +> For more information about this error, try `rustc --explain E0106`. +> error: could not compile `structs` (bin "structs") due to 2 previous errors > ``` > > 第10章で、これらのエラーを解消して構造体に参照を保持する方法について議論しますが、 > 当面、今回のようなエラーは、`&str`のような参照の代わりに、`String`のような所有された型を使うことで修正します。 + + + + + +[tuples]: ch03-02-data-types.html#タプル型 +[move]: ch04-01-what-is-ownership.html#ムーブによる変数とデータの相互作用 +[copy]: ch04-01-what-is-ownership.html#スタックのみのデータ-コピー diff --git a/src/ch05-02-example-structs.md b/src/ch05-02-example-structs.md index 76cb30c15..cb2e7151f 100644 --- a/src/ch05-02-example-structs.md +++ b/src/ch05-02-example-structs.md @@ -6,8 +6,8 @@ 構造体を使用したくなる可能性のあるケースを理解するために、長方形の面積を求めるプログラムを書きましょう。 @@ -15,7 +15,7 @@ refactor the program until we’re using structs instead. @@ -31,20 +31,7 @@ Cargoで*rectangles*という新規バイナリプロジェクトを作成しま ファイル名: src/main.rs ```rust -fn main() { - let width1 = 30; - let height1 = 50; - - println!( - // 長方形の面積は、{}平方ピクセルです - "The area of the rectangle is {} square pixels.", - area(width1, height1) - ); -} - -fn area(width: u32, height: u32) -> u32 { - width * height -} +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-08/src/main.rs:all}} ``` - -### タプルでリファクタリングする - - -リスト5-8のコードはうまく動き、各寸法を与えて`area`関数を呼び出すことで長方形の面積を割り出しますが、 -改善点があります。幅と高さは、組み合わせると一つの長方形を表すので、相互に関係があるわけです。 +このコードは、各寸法を与えて`area`関数を呼び出すことで長方形の面積を割り出すことができますが、 +このコードはもっと簡潔で読みやすくすることができます。 -`area`関数は、1長方形の面積を求めるものと考えられますが、今書いた関数には、引数が2つあります。 -引数は関連性があるのに、このプログラム内のどこにもそのことは表現されていません。 +`area`関数は、1長方形の面積を求めるものと考えられますが、今書いた関数には引数が2つあり、 +そしてこのプログラム内のどこを見ても、これらの引数に関連性があることが明確になっていません。 幅と高さを一緒にグループ化する方が、より読みやすく、扱いやすくなるでしょう。 -それをする一つの方法については、第3章の「タプル型」節ですでに議論しました: タプルを使うのです。 +それをする一つの方法については、第3章の[「タプル型」][the-tuple-type]節ですでに議論しました: タプルを使うのです。 ある意味では、このプログラムはマシです。タプルのおかげで少し構造的になり、一引数を渡すだけになりました。 しかし別の意味では、このバージョンは明確性を失っています: タプルは要素に名前を付けないので、 -計算が不明瞭になったのです。なぜなら、タプルの一部に添え字アクセスする必要があるからです。 +タプルの要素に添え字でアクセスする必要があり、計算が不明瞭になったのです。 -面積計算で幅と高さを混在させるのなら問題はないのですが、長方形を画面に描画したいとなると、問題になるのです! +面積計算では幅と高さを混同しても問題ないですが、長方形を画面に描画したいとなると、これは問題になります! タプルの添え字`0`が`幅`で、添え字`1`が`高さ`であることを肝に銘じておかなければなりません。 -他人がこのコードをいじることになったら、このことを割り出し、同様に肝に銘じなければならないでしょう。 -容易く、このことを忘れたり、これらの値を混ぜこぜにしたりしてエラーを発生させてしまうでしょう。 -データの意味をコードに載せていないからです。 +もし他人がこのコードを使用することになったら、彼らがこのことを見つけ出して肝に銘じておくのはより難しくなるでしょう。 +データの意味をコードに載せていないことで、エラーを招きやすくなってしまいました。 -データのラベル付けで意味を付与するために構造体を使います。現在使用しているタプルを全体と一部に名前のあるデータ型に、 +データのラベル付けで意味を付与するために構造体を使います。現在使用しているタプルを全体と一部に名前のある構造体に、 変形することができます。そう、リスト5-10に示したように。 ここでは、構造体を定義し、`Rectangle`という名前にしています。波括弧の中で`width`と`height`というフィールドを定義し、 `u32`という型にしました。それから`main`内で`Rectangle`の特定のインスタンスを生成し、 -幅を30、高さを50にしました。 +幅を`30`、高さを`50`にしました。 `area`関数は、`Rectangle`インスタンスの`width`と`height`フィールドにアクセスしています。 +(借用された構造体インスタンスのフィールドにアクセスしても、そのフィールドの値はムーブされないことに注意してください。 +構造体の借用をよく使うのはこのためです) これで、`area`の関数シグニチャは、我々の意図をズバリ示すようになりました: `width`と`height`フィールドを使って、 `Rectangle`の面積を計算します。これにより、幅と高さが相互に関係していることが伝わり、 タプルの`0`や`1`という添え字を使うよりも、これらの値に説明的な名前を与えられるのです。プログラムの意図が明瞭になりました。 @@ -263,14 +218,15 @@ and `1`. This is a win for clarity. ### トレイトの導出で有用な機能を追加する -プログラムのデバッグをしている間に、`Rectangle`のインスタンスを出力し、フィールドの値を確認できると、 -素晴らしいわけです。リスト5-11では、以前の章のように、`println!`マクロを試しに使用しようとしていますが、動きません。 +プログラムのデバッグをしている間に、`Rectangle`のインスタンスを出力し、フィールドの値を確認できると便利でしょう。 +リスト5-11では、以前の章のように、[`println!`マクロ][println]を試しに使用しようとしています。 +ですが、これは動きません。 -このコードを走らせると、こんな感じのエラーが出ます: +このコードをコンパイルすると、こんな感じのエラーが出ます: + + ```text -error[E0277]: the trait bound `Rectangle: std::fmt::Display` is not satisfied -(エラー: トレイト境界`Rectangle: std::fmt::Display`が満たされていません) +{{#include ../listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt:3:4}} ``` `println!`マクロには、様々な整形があり、標準では、波括弧は`Display`として知られる整形をするよう、 @@ -328,7 +275,7 @@ implementation of `Display`. 標準で`Display`を実装しています。というのも、`1`や他の基本型をユーザに見せる方法は一つしかないからです。 しかし構造体では、`println!`が出力を整形する方法は自明ではなくなります。出力方法がいくつもあるからです: カンマは必要なの?波かっこを出力する必要はある?全フィールドが見えるべき?この曖昧性のため、 -Rustは必要なものを推測しようとせず、構造体には`Display`実装が提供されないのです。 +Rustは必要なものを推測しようとせず、構造体は`println!`と`{}`プレースホルダで使用される`Display`実装を提供しないのです。 + ```text -`Rectangle` cannot be formatted with the default formatter; try using -`:?` instead if you are using a format string -(注釈: `Rectangle`は、デフォルト整形機では、整形できません; フォーマット文字列を使うのなら -代わりに`:?`を試してみてください) +{{#include ../listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt:10:13}} ``` -変更してコードを走らせてください。なに!まだエラーが出ます: +変更してコードをコンパイルしてください。なに!まだエラーが出ます: + + ```text -error[E0277]: the trait bound `Rectangle: std::fmt::Debug` is not satisfied -(エラー: トレイト境界`Rectangle: std::fmt::Debug`が満たされていません) +{{#include ../listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt:3:4}} ``` + ```text -`Rectangle` cannot be formatted using `:?`; if it is defined in your -crate, add `#[derive(Debug)]` or manually implement it -(注釈: `Rectangle`は`:?`を使って整形できません; 自分のクレートで定義しているのなら -`#[derive(Debug)]`を追加するか、手動で実装してください) +{{#include ../listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt:10:13}} ``` *確かに*Rustにはデバッグ用の情報を出力する機能が備わっていますが、この機能を構造体で使えるようにするには、 -明示的な選択をしなければならないのです。そうするには、構造体定義の直前に`#[derive(Debug)]`という注釈を追加します。 +明示的な選択をしなければならないのです。そうするには、構造体定義の直前に`#[derive(Debug)]`という外部属性を追加します。 そう、リスト5-12で示されている通りです。 -リスト5-12: `Debug`トレイトを導出する注釈を追加し、 +リスト5-12: `Debug`トレイトを導出する属性を追加し、 `Rectangle`インスタンスをデバッグ用整形機で出力する 素晴らしい!最善の出力ではないものの、このインスタンスの全フィールドの値を出力しているので、 @@ -443,33 +379,116 @@ When we use the `{:#?}` style in the example, the output will look like this: そのような場合には、`println!`文字列中の`{:?}`の代わりに`{:#?}`を使うことができます。 この例で`{:#?}`というスタイルを使用したら、出力は以下のようになるでしょう: -```text -rect1 is Rectangle { - width: 30, - height: 50 -} +```console +{{#include ../listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/output.txt}} ``` -Rustには、`derive`注釈で使えるトレイトが多く提供されており、独自の型に有用な振る舞いを追加することができます。 +`Debug`整形を使用して値を出力するためのもう一つの方法は、[`dbg!`マクロ][dbg]を使用することです。 +`dbg!`マクロは式の所有権を奪い(参照を取る`println!`とは対照的です)、その呼び出しが発生したコード内のファイル名と行番号とともに式を評価した結果を出力して、 +その値の所有権を返します。 + + + +> 注釈: 標準出力コンソールストリーム(`stdout`)に出力する`println!`とは異なり、`dbg!`マクロの呼び出しは標準エラーコンソールストリーム(`stderr`)に出力します。 +> `stderr`と`stdout`については[12章の「標準出力ではなく標準エラーにエラーメッセージを書き込む」節][err]でより詳しく触れます。 + + + +以下は、`width`フィールドに代入される値と、`rect1`の構造体全体の値に関心がある場合の例です: + +```rust +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/src/main.rs}} +``` + + + +`dbg!`は式が評価された値の所有権を返すため、式`30 * scale`を囲うように`dbg!`を書くことで、`width`フィールドはここで`dbg!`の呼び出しをしなかった場合とまったく同じ値になります。 +`rect1`の所有権は奪ってほしくないので、次の`dbg!`呼び出しでは`rect1`への参照を使用しています。 +この例の出力は以下のようになります: + +```console +{{#include ../listings/ch05-using-structs-to-structure-related-data/no-listing-05-dbg-macro/output.txt}} +``` + + + +出力の前半は*src/main.rs*の10行目からの出力です。 +ここでは式`30 * scale`をデバッグ出力していて、その結果の値は`60`です(整数に実装されている`Debug`整形を使用して出力されています)。 +*src/main.rs*の14行目の`dbg!`呼び出しは`&rect1`の値を出力し、これは`Rectangle`構造体です。 +この出力は `Rectangle`型の pretty `Debug`整形を使用します。 +`dbg!`マクロは、コードが何をしているのか理解しようとするときには非常に有用です! + + + +`Debug`トレイトの他にも、Rustでは`derive`属性で使えるトレイトが多く提供されており、独自の型に有用な振る舞いを追加することができます。 そのようなトレイトとその振る舞いは、付録Cで一覧になっています。 これらのトレイトを独自の動作とともに実装する方法だけでなく、独自のトレイトを生成する方法については、第10章で解説します。 +また、`derive`の他にも多数の属性が存在します; さらなる情報については[Rust Referenceの“Attributes”節][attributes]を参照してください。 `area`関数は、非常に特殊です: 長方形の面積を算出するだけです。`Rectangle`構造体とこの動作をより緊密に結び付けられると、 役に立つでしょう。なぜなら、他のどんな型でもうまく動作しなくなるからです。 `area`関数を`Rectangle`型に定義された`area`*メソッド*に変形することで、 このコードをリファクタリングし続けられる方法について見ていきましょう。 + + + +[the-tuple-type]: ch03-02-data-types.html#タプル型 +[app-c]: appendix-03-derivable-traits.md +[println]: https://doc.rust-lang.org/std/macro.println.html +[dbg]: https://doc.rust-lang.org/std/macro.dbg.html +[err]: ch12-06-writing-to-stderr-instead-of-stdout.html +[attributes]: https://doc.rust-lang.org/reference/attributes.html diff --git a/src/ch05-03-method-syntax.md b/src/ch05-03-method-syntax.md index 9807a8656..5696d5243 100644 --- a/src/ch05-03-method-syntax.md +++ b/src/ch05-03-method-syntax.md @@ -5,19 +5,21 @@ ## メソッド記法 -*メソッド*は関数に似ています: `fn`キーワードと名前で宣言されるし、引数と返り値があるし、 -どこか別の場所で呼び出された時に実行されるコードを含みます。ところが、 -メソッドは構造体の文脈(あるいはenumかトレイトオブジェクトの。これらについては各々第6章と17章で解説します)で定義されるという点で、 -関数とは異なり、最初の引数は必ず`self`になり、これはメソッドが呼び出されている構造体インスタンスを表します。 +*メソッド*は関数に似ています: `fn`キーワードと名前を使って宣言され、引数と戻り値を持つことができ、 +メソッドがどこか別の場所で呼び出された時に実行されるコードを含みます。 +関数とは異なり、メソッドは構造体の文脈の中で定義されます(enumの文脈やトレイトオブジェクトの文脈の中でも定義されますが、これらについてはそれぞれ[6章][enums]と[17章][trait-objects]で解説します)。 +最初の引数は必ず`self`になり、これはメソッドが呼び出されている構造体インスタンスを表します。 - -`Rectangle`の文脈内で関数を定義するには、`impl`(implementation; 実装)ブロックを始めます。 +(implementation) block for `Rectangle`. Everything within this `impl` block +will be associated with the `Rectangle` type. Then we move the `area` function +within the `impl` curly brackets and change the first (and in this case, only) +parameter to be `self` in the signature and everywhere within the body. In +`main`, where we called the `area` function and passed `rect1` as an argument, +we can instead use *method syntax* to call the `area` method on our `Rectangle` +instance. The method syntax goes after an instance: we add a dot followed by +the method name, parentheses, and any arguments. +--> + +`Rectangle`の文脈内で関数を定義するには、`Rectangle`のための`impl`(implementation; 実装)ブロックを始めます。 +この`impl`ブロック内のあらゆる定義は`Rectangle`に関連付けられたものとなるでしょう。 それから`area`関数を`impl`の波かっこ内に移動させ、最初の(今回は唯一の)引数をシグニチャ内と本体内全てで`self`に変えます。 `area`関数を呼び出し、`rect1`を引数として渡す`main`では、代替としてメソッド記法を使用して、 `Rectangle`インスタンスの`area`メソッドを呼び出せます。メソッド記法は、インスタンスの後に続きます: ドット、メソッド名、かっこ、そして引数と続くわけです。 `area`のシグニチャでは、`rectangle: &Rectangle`の代わりに`&self`を使用しています。 -というのも、コンパイラは、このメソッドが`impl Rectangle`という文脈内に存在するために、 -`self`の型が`Rectangle`であると把握しているからです。`&Rectangle`と同様に、 -`self`の直前に`&`を使用していることに注意してください。メソッドは、`self`の所有権を奪ったり、 -ここでしているように不変で`self`を借用したり、可変で`self`を借用したりできるのです。 +`&self`は実際のところ`self: &Self`の省略記法です。 +`impl`ブロック内では、型`Self`はその`impl`ブロックの対象である型に対するエイリアスとして使えます。 +メソッドはその第1引数として`self`という名前の`Self`型引数を持たなくてはならないので、 +Rust処理系は第1引数の位置では`self`という名前のみに省略することを許可しているのです。 +ただし、`self`省略記法の前の`&`は依然として必要であることに注意してください。 +これは、`rectangle: &Rectangle`と書いたときと同様に、このメソッドが`Self`のインスタンスを借用することを示しています。 +メソッドは、`self`の所有権を奪ったり、ここでしているように不変で`self`を借用したり、可変で`self`を借用したりできるのです。 他の引数と全く同じですね。 ここで`&self`を選んでいるのは、関数バージョンで`&Rectangle`を使用していたのと同様の理由です: @@ -121,66 +113,118 @@ to prevent the caller from using the original instance after the transformation. メソッドが`self`を何か別のものに変形し、変形後に呼び出し元が元のインスタンスを使用できないようにしたい場合に使用されます。 -関数の代替としてメソッドを使う主な利点は、メソッド記法を使用して全メソッドのシグニチャで`self`の型を繰り返す必要がなくなる以外だと、 -体系化です。コードの将来的な利用者に`Rectangle`の機能を提供しているライブラリ内の各所でその機能を探させるのではなく、 +関数の代替としてメソッドを使う主な理由は、メソッド記法を使用できるようにすることと、 +すべてのメソッドのシグニチャでいちいち`self`の型を繰り返す必要がなくなることに加えて、体系化のためです。 +コードの将来的な利用者に、私たちが提供するライブラリ内のあらゆる箇所から`Rectangle`の機能を探させるのではなく、 この型のインスタンスでできることを一つの`impl`ブロックにまとめあげています。 - -Here’s how it works: when you call a method with `object.something()`, Rust -automatically adds in `&`, `&mut`, or `*` so `object` matches the signature of -the method. In other words, the following are the same: +ファイル名: src/main.rs ```rust -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# -# impl Point { -# fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) -# } -# } -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -p1.distance(&p2); -(&p1).distance(&p2); +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-06-method-field-interaction/src/main.rs:here}} ``` -The first one looks much cleaner. This automatic referencing behavior works -because methods have a clear receiver—the type of `self`. Given the receiver -and name of a method, Rust can figure out definitively whether the method is -reading (`&self`), mutating (`&mut self`), or consuming (`self`). The fact -that Rust makes borrowing implicit for method receivers is a big part of -making ownership ergonomic in practice. + + +ここで`width`メソッドは、インスタンスの`width`フィールドの値が`0`より大きい場合に`true`を返し、値が`0`の場合は`false`を返すようにしています: +同名のメソッド内でも、フィールドをあらゆる目的のために使用することができます。 +`main`では`rect1.width`の後に丸かっこを続けているので、処理系はメソッドの`width`を意図したものと認識します。 +丸かっこを使わなければ、処理系はフィールドの`width`を意図したものと認識します。 + + + +フィールドの値を返すだけで他に何もしないメソッドに、フィールドと同じ名前を与えることが、常にではありませんが、よくあります。 +このようなメソッドは*ゲッター*と呼ばれます。 +他のいくつかの言語で行われているような自動的なゲッターの実装を、Rustが構造体フィールドに対して行うことはありません。 +フィールドを非公開にしながらメソッドは公開するということができ、そうすることで、型の公開APIの一部としてフィールドへの読み込み専用アクセスを提供できるので、ゲッターは有用です。 +公開と非公開とはなにか、そしてフィールドやメソッドを公開または非公開として指定する方法については、[7章][public]で議論します。 + + + + > ### `->`演算子はどこに行ったの? @@ -198,6 +242,7 @@ making ownership ergonomic in practice. > コンパイラは`object`がメソッドのシグニチャと合致するように、自動で`&`か`&mut`、`*`を付与するのです。 > 要するに、以下のコードは同じものです: > +> > ```rust > # #[derive(Debug,Copy,Clone)] > # struct Point { @@ -232,17 +277,16 @@ making ownership ergonomic in practice. -`Rectangle`構造体に2番目のメソッドを実装して、メソッドを使う鍛錬をしましょう。今回は、`Rectangle`のインスタンスに、 -別の`Rectangle`のインスタンスを取らせ、2番目の`Rectangle`が`self`に完全にはめ込まれたら、`true`を返すようにしたいのです; -そうでなければ、`false`を返すべきです。つまり、一旦`can_hold`メソッドを定義したら、 -リスト5-14のようなプログラムを書けるようになりたいのです。 +`Rectangle`構造体に2番目のメソッドを実装して、メソッドを使う練習をしましょう。 +今回は`Rectangle`のインスタンスに別の`Rectangle`のインスタンスを受け取らせ、2番目の`Rectangle`が`self`(1番目の`Rectangle`)に完全に収まるなら、`true`を返すようにしたいとしましょう; +そうでなければ、`false`を返すべきです。つまり、一旦`can_hold`メソッドを定義したら、リスト5-14のようなプログラムを書けるようにしたいのです。 -そして、予期される出力は以下のようになります。なぜなら、`rect2`の各寸法は`rect1`よりも小さいものの、 +予期される出力は以下のようになります。なぜなら、`rect2`の各寸法は`rect1`よりも小さいものの、 `rect3`は`rect1`より幅が広いからです: ```text @@ -294,7 +330,7 @@ read `rect2` (rather than write, which would mean we’d need a mutable borrow), and we want `main` to retain ownership of `rect2` so we can use it again after calling the `can_hold` method. The return value of `can_hold` will be a Boolean, and the implementation will check whether the width and height of -`self` are both greater than the width and height of the other `Rectangle`, +`self` are greater than the width and height of the other `Rectangle`, respectively. Let’s add the new `can_hold` method to the `impl` block from Listing 5-13, shown in Listing 5-15. --> @@ -316,21 +352,7 @@ Listing 5-13, shown in Listing 5-15. ファイル名: src/main.rs ```rust -# #[derive(Debug)] -# struct Rectangle { -# width: u32, -# height: u32, -# } -# -impl Rectangle { - fn area(&self) -> u32 { - self.width * self.height - } - - fn can_hold(&self, other: &Rectangle) -> bool { - self.width > other.width && self.height > other.height - } -} +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-15/src/main.rs:here}} ``` -`impl`ブロックの別の有益な機能は、`impl`ブロック内に`self`を引数に取ら*ない*関数を定義できることです。 -これは、構造体に関連付けられているので、*関連関数*と呼ばれます。それでも、関連関数は関数であり、メソッドではありません。 -というのも、対象となる構造体のインスタンスが存在しないからです。もう`String::from`という関連関数を使用したことがありますね。 +`impl`ブロック内で定義されたすべての関数は、`impl`の後に書かれた型に関連付けられているので、*関連関数*と呼ばれます。 +対象の型のインスタンスを必要としないために、`self`を第1引数として持たない(つまりメソッドではない)関連関数を定義することもできます。 +このような関数は、すでにひとつ使用しています: `String::from`関数は`String`型の上に定義された関数です。 -関連関数は、構造体の新規インスタンスを返すコンストラクタによく使用されます。例えば、一つの寸法を引数に取り、 -長さと幅両方に使用する関連関数を提供することができ、その結果、同じ値を2回指定する必要なく、 -正方形の`Rectangle`を生成しやすくすることができます。 +メソッドでない関連関数は、構造体の新規インスタンスを返すコンストラクタによく使用されます。 +これらにはしばしば`new`という名前が付けられますが、`new`は特別な名前ではなく、言語に組み込まれたものでもありません。 +例えば、一つの寸法を引数に取り、それを高さと幅の両方として使用する関連関数`square`を提供してもよいでしょう。 +そうすれば同じ値を2回指定する必要なく、正方形の`Rectangle`を生成しやすくすることができます。 + +戻り値型と関数本体内のの`Self` キーワードは`impl` キーワードの後に現れる型に対するエイリアスで、今回の場合は`Rectangle`です。 + この関連関数を呼び出すために、構造体名と一緒に`::`記法を使用します; 一例は`let sq = Rectangle::square(3);`です。 この関数は、構造体によって名前空間分けされています: `::`という記法は、関連関数とモジュールによって作り出される名前空間両方に使用されます。 -モジュールについては第7章で議論します。 +モジュールについては[第7章][modules]で議論します。 各構造体には、複数の`impl`ブロックを存在させることができます。例えば、リスト5-15はリスト5-16に示したコードと等価で、 リスト5-16では、各メソッドごとに`impl`ブロックを用意しています。 ```rust -# #[derive(Debug)] -# struct Rectangle { -# width: u32, -# height: u32, -# } -# -impl Rectangle { - fn area(&self) -> u32 { - self.width * self.height - } -} - -impl Rectangle { - fn can_hold(&self, other: &Rectangle) -> bool { - self.width > other.width && self.height > other.height - } -} +{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-16/src/main.rs:here}} ``` @@ -472,23 +480,34 @@ useful in Chapter 10, where we discuss generic types and traits. ## まとめ -構造体により、自分の領域で意味のある独自の型を作成することができます。構造体を使用することで、 +構造体により、ドメインにとって意味のある独自の型を作成することができます。構造体を使用することで、 関連のあるデータ片を相互に結合させたままにし、各部品に名前を付け、コードを明確にすることができます。 -メソッドにより、構造体のインスタンスが行う動作を指定することができ、関連関数により、 -構造体に特有の機能をインスタンスを利用することなく、名前空間分けすることができます。 +`impl`ブロック内では型に関連付けられた関数を定義することができ、メソッドは構造体のインスタンスが持つ振る舞いを規定することができる関連関数の一種です。 しかし、構造体だけが独自の型を作成する手段ではありません: Rustのenum機能に目を向けて、 別の道具を道具箱に追加しましょう。 + + + +[enums]: ch06-00-enums.html +[trait-objects]: ch17-02-trait-objects.md +[public]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#パスをpubキーワードで公開する +[modules]: ch07-02-defining-modules-to-control-scope-and-privacy.html From 0de9bcf18d3ea5bfae055a979c08ee6af66614e8 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:03 +0900 Subject: [PATCH 07/22] =?UTF-8?q?ch06=20Enum=E3=81=A8=E3=83=91=E3=82=BF?= =?UTF-8?q?=E3=83=BC=E3=83=B3=E3=83=9E=E3=83=83=E3=83=81=E3=83=B3=E3=82=B0?= =?UTF-8?q?=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88?= =?UTF-8?q?=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-06-01/Cargo.toml | 3 +- .../listing-06-02/Cargo.toml | 3 +- .../listing-06-03/Cargo.toml | 3 +- .../listing-06-04/Cargo.toml | 3 +- .../listing-06-04/src/main.rs | 4 +- .../listing-06-05/Cargo.toml | 3 +- .../listing-06-06/Cargo.toml | 3 +- .../listing-06-06/src/main.rs | 6 +- .../no-listing-01-defining-enums/Cargo.toml | 3 +- .../no-listing-02-enum-with-data/Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../src/main.rs | 6 +- .../no-listing-05-methods-on-enums/Cargo.toml | 3 +- .../src/main.rs | 2 +- .../no-listing-06-option-examples/Cargo.toml | 3 +- .../no-listing-06-option-examples/src/main.rs | 2 +- .../Cargo.toml | 3 +- .../output.txt | 21 +- .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../output.txt | 21 +- .../src/main.rs | 12 - .../no-listing-12-if-let/Cargo.toml | 3 +- .../no-listing-12-if-let/src/main.rs | 6 +- .../Cargo.toml | 3 +- .../src/main.rs | 2 +- .../Cargo.toml | 3 +- .../src/main.rs | 2 +- .../Cargo.lock | 0 .../Cargo.toml | 3 +- .../src/main.rs | 14 + .../Cargo.lock | 6 + .../Cargo.toml | 6 + .../src/main.rs | 14 + .../no-listing-17-underscore-unit/Cargo.lock | 6 + .../no-listing-17-underscore-unit/Cargo.toml | 6 + .../no-listing-17-underscore-unit/src/main.rs | 13 + src/SUMMARY.md | 4 +- src/ch06-00-enums.md | 19 +- src/ch06-01-defining-an-enum.md | 398 +++++++---------- src/ch06-02-match.md | 411 +++++++++--------- src/ch06-03-if-let.md | 95 ++-- 44 files changed, 526 insertions(+), 610 deletions(-) delete mode 100644 listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/src/main.rs rename listings/ch06-enums-and-pattern-matching/{no-listing-11-underscore-placeholder => no-listing-15-binding-catchall}/Cargo.lock (100%) rename listings/ch06-enums-and-pattern-matching/{no-listing-11-underscore-placeholder => no-listing-15-binding-catchall}/Cargo.toml (50%) create mode 100644 listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/src/main.rs create mode 100644 listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/Cargo.lock create mode 100644 listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/Cargo.toml create mode 100644 listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/src/main.rs create mode 100644 listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/Cargo.lock create mode 100644 listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/Cargo.toml create mode 100644 listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/src/main.rs diff --git a/listings/ch06-enums-and-pattern-matching/listing-06-01/Cargo.toml b/listings/ch06-enums-and-pattern-matching/listing-06-01/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/listing-06-01/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/listing-06-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/listing-06-02/Cargo.toml b/listings/ch06-enums-and-pattern-matching/listing-06-02/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/listing-06-02/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/listing-06-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/listing-06-03/Cargo.toml b/listings/ch06-enums-and-pattern-matching/listing-06-03/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/listing-06-03/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/listing-06-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/listing-06-04/Cargo.toml b/listings/ch06-enums-and-pattern-matching/listing-06-04/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/listing-06-04/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/listing-06-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/listing-06-04/src/main.rs b/listings/ch06-enums-and-pattern-matching/listing-06-04/src/main.rs index 3ba384fba..ac134534e 100644 --- a/listings/ch06-enums-and-pattern-matching/listing-06-04/src/main.rs +++ b/listings/ch06-enums-and-pattern-matching/listing-06-04/src/main.rs @@ -1,9 +1,9 @@ // ANCHOR: here -#[derive(Debug)] // so we can inspect the state in a minute +#[derive(Debug)] // すぐに州を検査できるように enum UsState { Alabama, Alaska, - // --snip-- + // --略-- } enum Coin { diff --git a/listings/ch06-enums-and-pattern-matching/listing-06-05/Cargo.toml b/listings/ch06-enums-and-pattern-matching/listing-06-05/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/listing-06-05/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/listing-06-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/listing-06-06/Cargo.toml b/listings/ch06-enums-and-pattern-matching/listing-06-06/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/listing-06-06/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/listing-06-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/listing-06-06/src/main.rs b/listings/ch06-enums-and-pattern-matching/listing-06-06/src/main.rs index 222d54552..dc2bffb91 100644 --- a/listings/ch06-enums-and-pattern-matching/listing-06-06/src/main.rs +++ b/listings/ch06-enums-and-pattern-matching/listing-06-06/src/main.rs @@ -1,8 +1,8 @@ fn main() { // ANCHOR: here - let some_u8_value = Some(0u8); - match some_u8_value { - Some(3) => println!("three"), + let config_max = Some(3u8); + match config_max { + Some(max) => println!("The maximum is configured to be {}", max), _ => (), } // ANCHOR_END: here diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-01-defining-enums/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-01-defining-enums/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-01-defining-enums/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-01-defining-enums/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-02-enum-with-data/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-02-enum-with-data/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-02-enum-with-data/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-02-enum-with-data/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-03-variants-with-different-data/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-03-variants-with-different-data/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-03-variants-with-different-data/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-03-variants-with-different-data/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-04-structs-similar-to-message-enum/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-04-structs-similar-to-message-enum/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-04-structs-similar-to-message-enum/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-04-structs-similar-to-message-enum/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-04-structs-similar-to-message-enum/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-04-structs-similar-to-message-enum/src/main.rs index df451be8b..182221bf0 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-04-structs-similar-to-message-enum/src/main.rs +++ b/listings/ch06-enums-and-pattern-matching/no-listing-04-structs-similar-to-message-enum/src/main.rs @@ -1,11 +1,11 @@ // ANCHOR: here -struct QuitMessage; // unit struct +struct QuitMessage; // ユニット構造体 struct MoveMessage { x: i32, y: i32, } -struct WriteMessage(String); // tuple struct -struct ChangeColorMessage(i32, i32, i32); // tuple struct +struct WriteMessage(String); // タプル構造体 +struct ChangeColorMessage(i32, i32, i32); // タプル構造体 // ANCHOR_END: here fn main() {} diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-05-methods-on-enums/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-05-methods-on-enums/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-05-methods-on-enums/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-05-methods-on-enums/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-05-methods-on-enums/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-05-methods-on-enums/src/main.rs index 66e0b6da1..2395b0e6d 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-05-methods-on-enums/src/main.rs +++ b/listings/ch06-enums-and-pattern-matching/no-listing-05-methods-on-enums/src/main.rs @@ -9,7 +9,7 @@ fn main() { // ANCHOR: here impl Message { fn call(&self) { - // method body would be defined here + // メソッド本体はここで定義されます } } diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/src/main.rs index 9de5791b4..be552bfa5 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/src/main.rs +++ b/listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/src/main.rs @@ -1,7 +1,7 @@ fn main() { // ANCHOR: here let some_number = Some(5); - let some_string = Some("a string"); + let some_char = Some('e'); let absent_number: Option = None; // ANCHOR_END: here diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt b/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt index d3092d9fb..2f0596aaf 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt +++ b/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt @@ -1,16 +1,21 @@ $ cargo run Compiling enums v0.1.0 (file:///projects/enums) -error[E0277]: cannot add `std::option::Option` to `i8` +error[E0277]: cannot add `Option` to `i8` +(エラー: `Option`を`i8`に足すことはできません) --> src/main.rs:5:17 | 5 | let sum = x + y; - | ^ no implementation for `i8 + std::option::Option` + | ^ no implementation for `i8 + Option` + (`i8 + `Option`のための実装がありません) | - = help: the trait `std::ops::Add>` is not implemented for `i8` - -error: aborting due to previous error + = help: the trait `Add>` is not implemented for `i8` + (ヘルプ: トレイト`Add`が`i8`に対して実装されていません) + = help: the following other types implement trait `Add`: + (ヘルプ: 以下の型であればトレイト`Add`を実装しています:) + + > + <&'a i8 as Add> + <&i8 as Add<&i8>> For more information about this error, try `rustc --explain E0277`. -error: could not compile `enums`. - -To learn more, run the command again with --verbose. +error: could not compile `enums` (bin "enums") due to 1 previous error diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-08-match-arm-multiple-lines/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-08-match-arm-multiple-lines/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-08-match-arm-multiple-lines/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-08-match-arm-multiple-lines/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-09-variable-in-pattern/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-09-variable-in-pattern/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-09-variable-in-pattern/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-09-variable-in-pattern/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt b/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt index da9e9d9bf..fa6e843fa 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt +++ b/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt @@ -1,16 +1,25 @@ $ cargo run Compiling enums v0.1.0 (file:///projects/enums) error[E0004]: non-exhaustive patterns: `None` not covered +(エラー: 包括的でないパターン: `None`が網羅されていません) --> src/main.rs:3:15 | 3 | match x { | ^ pattern `None` not covered + (パターン`None`が網羅されていません) + | +note: `Option` defined here + --> /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/option.rs:570:1 + ::: /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/option.rs:574:5 + | + = note: not covered + = note: the matched value is of type `Option` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown +(ヘルプ: ワイルドカードパターンか、以下に示すように明示的なパターンを持つアームを追加することで、すべての可能な場合が確実に処理されるようにしてください) + | +4 ~ Some(i) => Some(i + 1), +5 ~ None => todo!(), | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - -error: aborting due to previous error For more information about this error, try `rustc --explain E0004`. -error: could not compile `enums`. - -To learn more, run the command again with --verbose. +error: could not compile `enums` (bin "enums") due to 1 previous error diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/src/main.rs deleted file mode 100644 index 6fc8ab058..000000000 --- a/listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/src/main.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn main() { - // ANCHOR: here - let some_u8_value = 0u8; - match some_u8_value { - 1 => println!("one"), - 3 => println!("three"), - 5 => println!("five"), - 7 => println!("seven"), - _ => (), - } - // ANCHOR_END: here -} diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-12-if-let/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-12-if-let/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-12-if-let/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-12-if-let/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-12-if-let/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-12-if-let/src/main.rs index fb6578cf6..735086d4e 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-12-if-let/src/main.rs +++ b/listings/ch06-enums-and-pattern-matching/no-listing-12-if-let/src/main.rs @@ -1,8 +1,8 @@ fn main() { - let some_u8_value = Some(0u8); // ANCHOR: here - if let Some(3) = some_u8_value { - println!("three"); + let config_max = Some(3u8); + if let Some(max) = config_max { + println!("The maximum is configured to be {}", max); } // ANCHOR_END: here } diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-13-count-and-announce-match/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-13-count-and-announce-match/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-13-count-and-announce-match/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-13-count-and-announce-match/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-13-count-and-announce-match/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-13-count-and-announce-match/src/main.rs index 12c4c0fec..ac721ba43 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-13-count-and-announce-match/src/main.rs +++ b/listings/ch06-enums-and-pattern-matching/no-listing-13-count-and-announce-match/src/main.rs @@ -2,7 +2,7 @@ enum UsState { Alabama, Alaska, - // --snip-- + // --略-- } enum Coin { diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-14-count-and-announce-if-let-else/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-14-count-and-announce-if-let-else/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-14-count-and-announce-if-let-else/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-14-count-and-announce-if-let-else/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-14-count-and-announce-if-let-else/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-14-count-and-announce-if-let-else/src/main.rs index ba7eda27b..1d145c272 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-14-count-and-announce-if-let-else/src/main.rs +++ b/listings/ch06-enums-and-pattern-matching/no-listing-14-count-and-announce-if-let-else/src/main.rs @@ -2,7 +2,7 @@ enum UsState { Alabama, Alaska, - // --snip-- + // --略-- } enum Coin { diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/Cargo.lock b/listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/Cargo.lock similarity index 100% rename from listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/Cargo.lock rename to listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/Cargo.lock diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/Cargo.toml similarity index 50% rename from listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/Cargo.toml rename to listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/Cargo.toml index 04988d1ff..e959295f9 100644 --- a/listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/Cargo.toml +++ b/listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "enums" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/src/main.rs new file mode 100644 index 000000000..6ce0b5998 --- /dev/null +++ b/listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/src/main.rs @@ -0,0 +1,14 @@ +fn main() { + // ANCHOR: here + let dice_roll = 9; + match dice_roll { + 3 => add_fancy_hat(), + 7 => remove_fancy_hat(), + other => move_player(other), + } + + fn add_fancy_hat() {} + fn remove_fancy_hat() {} + fn move_player(num_spaces: u8) {} + // ANCHOR_END: here +} diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/Cargo.lock b/listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/Cargo.lock new file mode 100644 index 000000000..f62e8ac45 --- /dev/null +++ b/listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "enums" +version = "0.1.0" + diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/Cargo.toml new file mode 100644 index 000000000..e959295f9 --- /dev/null +++ b/listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "enums" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/src/main.rs new file mode 100644 index 000000000..586e23751 --- /dev/null +++ b/listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/src/main.rs @@ -0,0 +1,14 @@ +fn main() { + // ANCHOR: here + let dice_roll = 9; + match dice_roll { + 3 => add_fancy_hat(), + 7 => remove_fancy_hat(), + _ => reroll(), + } + + fn add_fancy_hat() {} + fn remove_fancy_hat() {} + fn reroll() {} + // ANCHOR_END: here +} diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/Cargo.lock b/listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/Cargo.lock new file mode 100644 index 000000000..f62e8ac45 --- /dev/null +++ b/listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "enums" +version = "0.1.0" + diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/Cargo.toml b/listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/Cargo.toml new file mode 100644 index 000000000..e959295f9 --- /dev/null +++ b/listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "enums" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/src/main.rs b/listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/src/main.rs new file mode 100644 index 000000000..e791742ee --- /dev/null +++ b/listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/src/main.rs @@ -0,0 +1,13 @@ +fn main() { + // ANCHOR: here + let dice_roll = 9; + match dice_roll { + 3 => add_fancy_hat(), + 7 => remove_fancy_hat(), + _ => (), + } + + fn add_fancy_hat() {} + fn remove_fancy_hat() {} + // ANCHOR_END: here +} diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 26386ca98..1a0898305 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -73,12 +73,12 @@ - [Enumとパターンマッチング](ch06-00-enums.md) - [Enumを定義する](ch06-01-defining-an-enum.md) - - [`match`制御フロー演算子](ch06-02-match.md) + - [`match`制御フロー構造](ch06-02-match.md) - [`if let`で簡潔な制御フロー](ch06-03-if-let.md) -この章では、*列挙型*について見ていきます。列挙型は、*enum*とも称されます。enumは、取りうる値を列挙することで、 +この章では、*列挙型*について見ていきます。列挙型は、*enum*とも称されます。enumは、取りうる*列挙子*を列挙することで、 型を定義させてくれます。最初に、enumを定義し、使用して、enumがデータとともに意味をコード化する方法を示します。 次に、特別に有用なenumである`Option`について掘り下げていきましょう。この型は、 値が何かかなんでもないかを表現します。それから、`match`式のパターンマッチングにより、 どうenumの色々な値に対して異なるコードを走らせやすくなるかを見ます。最後に、`if let`文法要素も、 如何(いか)にenumをコードで扱う際に使用可能な便利で簡潔な慣用句であるかを解説します。 - - - -enumは多くの言語に存在する機能ですが、その能力は言語ごとに異なります。Rustのenumは、F#、OCaml、Haskellなどの、 -関数型言語に存在する*代数的データ型*に最も酷似しています。 diff --git a/src/ch06-01-defining-an-enum.md b/src/ch06-01-defining-an-enum.md index ba7c87fdb..03d573975 100644 --- a/src/ch06-01-defining-an-enum.md +++ b/src/ch06-01-defining-an-enum.md @@ -4,24 +4,37 @@ ## Enumを定義する + + +構造体は、`width`と`height`を持つ`Rectangle`のように、関連するフィールドとデータをひとつにまとめる方法を提供してくれます。 +一方でenumは、ある値が、とりうる値の集合のうちのいずれかひとつであることを表現する方法を提供するものです。 +例えば、`Rectangle`は、`Circle`や`Triangle`も含めたとりうる形の集合のいずれかひとつである、と表現したいことがあります。 +これを達成するために、Rustではこれらの可能性をenumとしてエンコードすることができます。 + コードで表現したくなるかもしれない場面に目を向けて、enumが有用でこの場合、構造体よりも適切である理由を確認しましょう。 IPアドレスを扱う必要が出たとしましょう。現在、IPアドレスの規格は二つあります: バージョン4とバージョン6です。 -これらは、プログラムが遭遇するIPアドレスのすべての可能性です: 列挙型は、取りうる値をすべて*列挙*でき、 +これらはプログラムが遭遇するIPアドレスの可能性のすべてですので、取りうる列挙子をすべて*列挙*できます。 これが列挙型の名前の由来です。 この概念をコードでは、`IpAddrKind`列挙型を定義し、IPアドレスがなりうる種類、`V4`と`V6`を列挙することで、 -表現できます。これらは、enumの*列挙子*として知られています: +表現できます。これらがenumの列挙子です: ```rust -enum IpAddrKind { - V4, - V6, -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-01-defining-enums/src/main.rs:def}} ``` enumの列挙子は、その識別子の元に名前空間分けされていることと、 @@ -91,12 +94,7 @@ enumの列挙子は、その識別子の元に名前空間分けされている 同じ型`IpAddrKind`になったからです。そうしたら、例えば、どんな`IpAddrKind`を取る関数も定義できるようになります。 ```rust -# enum IpAddrKind { -# V4, -# V6, -# } -# -fn route(ip_type: IpAddrKind) { } +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-01-defining-enums/src/main.rs:fn}} ``` enumの利用には、さらなる利点さえもあります。このIPアドレス型についてもっと考えてみると、現状では、 実際のIPアドレスの*データ*を保持する方法がありません。つまり、どんな*種類*であるかを知っているだけです。 -構造体について第5章で学んだばっかりとすると、この問題に対して、あなたはリスト6-1のように対処するかもしれません。 +構造体について第5章で学んだばっかりとすると、この問題に対して、あなたはリスト6-1のように構造体を使って対処したくなるかもしれません。 ```rust -enum IpAddrKind { - V4, - V6, -} - -struct IpAddr { - kind: IpAddrKind, - address: String, -} - -let home = IpAddr { - kind: IpAddrKind::V4, - address: String::from("127.0.0.1"), -}; - -let loopback = IpAddr { - kind: IpAddrKind::V6, - address: String::from("::1"), -}; +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-01/src/main.rs:here}} ``` ここでは、二つのフィールドを持つ`IpAddr`という構造体を定義しています: `IpAddrKind`型(先ほど定義したenumですね)の`kind`フィールドと、 -`String`型の`address`フィールドです。この構造体のインスタンスが2つあります。最初のインスタンス、 -`home`には`kind`として`IpAddrKind::V4`があり、紐付けられたアドレスデータは`127.0.0.1`です。 -2番目のインスタンス、`loopback`には、`kind`の値として、`IpAddrKind`のもう一つの列挙子、`V6`があり、 +`String`型の`address`フィールドです。この構造体のインスタンスが2つあります。最初のインスタンスは`home`で、 +これには`kind`として`IpAddrKind::V4`があり、紐付けられたアドレスデータは`127.0.0.1`です。 +2番目のインスタンスは`loopback`です。これには`kind`の値として、`IpAddrKind`のもう一つの列挙子、`V6`があり、 アドレス`::1`が紐付いています。構造体を使って`kind`と`address`値を一緒に包んだので、 もう列挙子は値と紐付けられています。 -各enumの列挙子に直接データを格納して、enumを構造体内に使うというよりもenumだけを使って、 -同じ概念をもっと簡潔な方法で表現することができます。この新しい`IpAddr`の定義は、 -`V4`と`V6`列挙子両方に`String`値が紐付けられていることを述べています。 +しかしながら、enumだけを使って同じ概念を表現するほうがより簡潔です: +構造体の中にenumを持たせるのではなく、enumの各列挙子に直接データを格納することができるのです。 +この新しい`IpAddr`の定義は、`V4`と`V6`列挙子両方に`String`値が紐付けられていることを述べています。 ```rust -enum IpAddr { - V4(String), - V6(String), -} - -let home = IpAddr::V4(String::from("127.0.0.1")); - -let loopback = IpAddr::V6(String::from("::1")); +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-02-enum-with-data/src/main.rs:here}} ``` enumの各列挙子にデータを直接添付できるので、余計な構造体を作る必要は全くありません。 +またここでは、enumがどう機能するかについての別の詳細も確認することができます: +ここで定義したenumの各列挙子の名前は、そのenumを構築する関数にもなるのです。 +つまり、`IpAddr::V4()`は`String`引数を受け取り`IpAddr`型のインスタンスを返す関数の呼び出しになるのです。 +enumを定義した結果として、自動でこのコンストラクタ関数が定義されます。 - - ```rust struct Ipv4Addr { - // 省略 + // --略-- } struct Ipv6Addr { - // 省略 + // --略-- } enum IpAddr { @@ -314,12 +276,7 @@ variety of types embedded in its variants. リスト6-2でenumの別の例を見てみましょう: 今回のコードは、幅広い種類の型が列挙子に埋め込まれています。 ```rust -enum Message { - Quit, - Move { x: i32, y: i32 }, - Write(String), - ChangeColor(i32, i32, i32), -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-02/src/main.rs:here}} ``` -* `Quit`には紐付けられたデータは全くなし。 -* `Move`は、中に匿名構造体を含む。 -* `Write`は、単独の`String`オブジェクトを含む。 -* `ChangeColor`は、3つの`i32`値を含む。 +* `Quit`は関連付けられたデータをまったく持ちません。 +* `Move`は構造体のように名前付きのフィールドを持っています。 +* `Write`は`String`オブジェクトを1個だけ含んでいます。 +* `ChangeColor`は3個の`i32`値を含んでいます。 - ```rust -struct QuitMessage; // ユニット構造体 -struct MoveMessage { - x: i32, - y: i32, -} -struct WriteMessage(String); // タプル構造体 -struct ChangeColorMessage(i32, i32, i32); // タプル構造体 +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-04-structs-similar-to-message-enum/src/main.rs:here}} ``` - - -ですが、異なる構造体を使っていたら、各々、それ自身の型があるので、単独の型になるリスト6-2で定義した`Message` enumほど、 -これらの種のメッセージいずれもとる関数を簡単に定義することはできないでしょう。 +ですがそれぞれ独自の型を持つ異なる構造体を使ってしまうと、リスト6-2で定義した単一の型である`Message` enumを使う場合と比較して、 +これらの任意の種類のメッセージを取る関数を簡単には定義できません。 -前節で、`IpAddr` enumがRustの型システムを使用して、プログラムにデータ以上の情報をコード化できる方法を目撃しました。 この節では、`Option`のケーススタディを掘り下げていきます。この型も標準ライブラリにより定義されているenumです。 -この`Option`型はいろんな箇所で使用されます。なぜなら、値が何かかそうでないかという非常に一般的な筋書きをコード化するからです。 -この概念を型システムの観点で表現することは、コンパイラが、プログラマが処理すべき場面全てを処理していることをチェックできることを意味します; +この`Option`型は、値が何かかそうでないかという非常に一般的な筋書きをコード化します。 + + + +例えば、空でないリストの最初のアイテムをリクエストすると、値が得られるでしょう。 +空リストの最初のアイテムをリクエストすると、何も得られないでしょう。 +この概念を型システムの観点で表現することは、コンパイラが、プログラマが処理すべき場面全てを処理しているかどうかチェックできることを意味します; この機能は、他の言語において、究極的にありふれたバグを阻止することができます。 -`Option`は有益すぎて、初期化処理(prelude)にさえ含まれています。つまり、明示的にスコープに導入する必要がないのです。 -さらに、列挙子もそうなっています: `Some`と`None`を`Option::`の接頭辞なしに直接使えるわけです。 -ただ、`Option`はそうは言っても、普通のenumであり、`Some(T)`と`None`も`Option`型のただの列挙子です。 +`Option`は有益すぎて、preludeにさえ含まれています; 明示的にスコープに導入する必要がないのです。 +そしてその列挙子もまたpreludeに含まれています: `Some`と`None`を`Option::`の接頭辞なしに直接使えるわけです。 +ただ、`Option` enumはそうは言っても、普通のenumであり、`Some(T)`と`None`も`Option`型のただの列挙子です。 -``という記法は、まだ語っていないRustの機能です。これは、ジェネリック型引数であり、ジェネリクスについて詳しくは、 -第10章で解説します。とりあえず、知っておく必要があることは、``は、`Option` enumの`Some`列挙子が、 -あらゆる型のデータを1つだけ持つことができることを意味していることだけです。こちらは、 -`Option`値を使って、数値型や文字列型を保持する例です。 +``という記法は、まだ語っていないRustの機能です。 +これはジェネリック型引数で、ジェネリクスについて詳しくは第10章で解説します。 +とりあえず``の意味に関して知っておく必要があることは、`Option` enumの`Some`列挙子はあらゆる型のデータを1つだけ持つことができ、 +`T`の代わりに使用される具体的な型に応じて、`Option`型はそれぞれ異なる型になるということだけです。 +以下は`Option`値を使って数値型や文字列型を保持する例です。 ```rust -let some_number = Some(5); -let some_string = Some("a string"); - -let absent_number: Option = None; +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/src/main.rs:here}} ``` -`Some`ではなく、`None`を使ったら、コンパイラに`Option`の型が何になるかを教えなければいけません。 -というのも、`None`値を見ただけでは、`Some`列挙子が保持する型をコンパイラが推論できないからです。 +`some_number`の型は`Option`です。`some_char`の型は`Option`で、これは先ほどとは異なる型です。 +`Some`列挙子の中で値を指定しているので、コンパイラはこれらの型を推論することができます。 +`absent_number`に関しては、コンパイラはジェネリクス適用後の`Option`型を注釈することを要求します: +`None`値を見ただけでは、それに対応する`Some`列挙子が保持する型をコンパイラは推論できないからです。 +ここでは、`absent_number`が`Option`型を持つことをコンパイラに伝えています。 `Some`値がある時、値が存在するとわかり、その値は、`Some`に保持されています。`None`値がある場合、 @@ -594,8 +524,8 @@ nullよりも少しでも好ましいのでしょうか? @@ -603,28 +533,18 @@ trying to add an `i8` to an `Option`: コンパイラが`Option`値を確実に有効な値かのようには使用させてくれません。 例えば、このコードは`i8`を`Option`に足そうとしているので、コンパイルできません。 -```rust,ignore -let x: i8 = 5; -let y: Option = Some(5); - -let sum = x + y; +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/src/main.rs:here}} ``` このコードを動かしたら、以下のようなエラーメッセージが出ます。 -```text -error[E0277]: the trait bound `i8: std::ops::Add>` is -not satisfied -(エラー: `i8: std::ops::Add>`というトレイト境界が満たされていません) - --> - | -5 | let sum = x + y; - | ^ no implementation for `i8 + std::option::Option` - | +```console +{{#include ../listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt}} ``` 言い換えると、`T`型の処理を行う前には、`Option`を`T`に変換する必要があるわけです。一般的に、 @@ -657,7 +576,7 @@ is. そうでないかのように想定することです。 -不正確にnullでない値を想定する心配をしなくてもよいということは、コード内でより自信を持てることになります。 +値がnullでないと誤って想定するリスクを削減することは、コードに確信を持つための助けになります。 nullになる可能性のある値を保持するには、その値の型を`Option`にすることで明示的に同意しなければなりません。 それからその値を使用する際には、値がnullである場合を明示的に処理する必要があります。 値が`Option`以外の型であるところ全てにおいて、値がnullでないと安全に想定することが*できます*。 これは、Rustにとって、意図的な設計上の決定であり、nullの普遍性を制限し、Rustコードの安全性を向上させます。 では、`Option`型の値がある時、その値を使えるようにするには、どのように`Some`列挙子から`T`型の値を取り出せばいいのでしょうか? @@ -686,21 +606,29 @@ the methods on `Option` will be extremely useful in your journey with Rust. [ドキュメント][docs]でそれらを確認できます。`Option`のメソッドに馴染むと、 Rustの旅が極めて有益になるでしょう。 -[docs]: https://doc.rust-lang.org/std/option/enum.Option.html - 一般的に、`Option`値を使うには、各列挙子を処理するコードが欲しくなります。 -`Some(T)`値がある時だけ走る何らかのコードが欲しくなり、このコードが内部の`T`を使用できます。 -`None`値があった場合に走る別のコードが欲しくなり、そちらのコードは`T`値は使用できない状態になります。 +`Some(T)`値がある場合だけ走る何らかのコードが欲しくなり、このコードが内部の`T`を使用できます。 +`None`値がある場合だけ走る別のコードが欲しくなり、そちらのコードは`T`を使用できない状態になります。 `match`式が、enumとともに使用した時にこれだけの動作をする制御フロー文法要素になります: enumの列挙子によって、違うコードが走り、そのコードがマッチした値の中のデータを使用できるのです。 + + + +[IpAddr]: https://doc.rust-lang.org/std/net/enum.IpAddr.html +[option]: https://doc.rust-lang.org/std/option/enum.Option.html +[docs]: https://doc.rust-lang.org/std/option/enum.Option.html diff --git a/src/ch06-02-match.md b/src/ch06-02-match.md index f0fe802b4..968bedb2f 100644 --- a/src/ch06-02-match.md +++ b/src/ch06-02-match.md @@ -1,26 +1,32 @@ + -## `match`制御フロー演算子 + + +## `match`制御フロー構造 Rustには、一連のパターンに対して値を比較し、マッチしたパターンに応じてコードを実行させてくれる`match`と呼ばれる、 -非常に強力な制御フロー演算子があります。パターンは、リテラル値、変数名、ワイルドカードやその他多数のもので構成することができます; -第18章で、全ての種類のパターンと、その目的については解説します。`match`のパワーは、 +非常に強力な制御フロー構造があります。パターンは、リテラル値、変数名、ワイルドカードやその他多数のもので構成することができます; +[第18章][ch18-00-patterns]で、全ての種類のパターンと、その目的については解説します。`match`のパワーは、 パターンの表現力とコンパイラが全てのありうるパターンを処理しているかを確認してくれるという事実に由来します。 -コインについて話したので、それを`match`を使用する例にとってみましょう!数え上げ装置と同じ要領で未知のアメリカコインを一枚取り、 +せっかくコインについて話したので、それを`match`を使用する例にとってみましょう!数え上げ装置と同じ要領で未知のアメリカコインを一枚取り、 どの種類のコインなのか決定し、その価値をセントで返す関数をリスト6-3で示したように記述することができます。 ```rust -enum Coin { - Penny, - Nickel, - Dime, - Quarter, -} - -fn value_in_cents(coin: Coin) -> u32 { - match coin { - Coin::Penny => 1, - Coin::Nickel => 5, - Coin::Dime => 10, - Coin::Quarter => 25, - } -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-03/src/main.rs:here}} ``` リスト6-3: enumとそのenumの列挙子をパターンにした`match`式 `value_in_cents`関数内の`match`を噛み砕きましょう。まず、`match`キーワードに続けて式を並べています。 -この式は今回の場合、値`coin`です。`if`で使用した式と非常に酷似しているみたいですね。しかし、大きな違いがあります: -`if`では、式は論理値を返す必要がありますが、ここでは、どんな型でも構いません。この例における`coin`の型は、 +この式は今回の場合、値`coin`です。`if`で使用した条件式と非常に酷似しているみたいですね。しかし、大きな違いがあります: +`if`では、条件は論理値に評価される必要がありますが、ここでは、どんな型でも構いません。この例における`coin`の型は、 1行目で定義した`Coin` enumです。 @@ -112,47 +104,32 @@ entire `match` expression. 各アームに紐付けられるコードは式であり、マッチしたアームの式の結果が`match`式全体の戻り値になります。 -典型的に、アームのコードが短い場合、波かっこは使用されません。リスト6-3では、各アームが値を返すだけなので、 -これに倣っています。マッチのアームで複数行のコードを走らせたいのなら、波かっこを使用することができます。 +典型的に、アームのコードが短い場合、波かっこは使用しません。リスト6-3では、各アームが値を返すだけなので、 +これに倣っています。マッチのアームで複数行のコードを走らせたいのなら、波かっこを使わなくてはなりませんが、 +この場合アームの後のカンマは省略することができます。 例えば、以下のコードは、メソッドが`Coin::Penny`とともに呼び出されるたびに「Lucky penny!」と表示しつつ、 -ブロックの最後の値、`1`を返すでしょう。 +ブロックの最後の値、`1`を返します。 ```rust -# enum Coin { -# Penny, -# Nickel, -# Dime, -# Quarter, -# } -# -fn value_in_cents(coin: Coin) -> u32 { - match coin { - Coin::Penny => { - println!("Lucky penny!"); - 1 - }, - Coin::Nickel => 5, - Coin::Dime => 10, - Coin::Quarter => 25, - } -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-08-match-arm-multiple-lines/src/main.rs:here}} ``` ### 値に束縛されるパターン @@ -165,8 +142,8 @@ As an example, let’s change one of our enum variants to hold data inside it. From 1999 through 2008, the United States minted quarters with different designs for each of the 50 states on one side. No other coins got state designs, so only quarters have this extra value. We can add this information to -our `enum` by changing the `Quarter` variant to include a `UsState` value stored -inside it, which we've done here in Listing 6-4. +our `enum` by changing the `Quarter` variant to include a `UsState` value +stored inside it, which we’ve done in Listing 6-4. --> 例として、enumの列挙子の一つを中にデータを保持するように変えましょう。1999年から2008年まで、 @@ -175,40 +152,8 @@ inside it, which we've done here in Listing 6-4. `Quarter`列挙子を変更して、`UsState`値が中に保持されるようにすることで`enum`にこの情報を追加でき、 それをしたのがリスト6-4のコードになります。 - - - - -```rust -#[derive(Debug)] // すぐに州を点検できるように -enum UsState { - Alabama, - Alaska, - // ... などなど -} - -enum Coin { - Penny, - Nickel, - Dime, - Quarter(UsState), -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-04/src/main.rs:here}} ``` @@ -240,30 +185,7 @@ quarter’s state. Then we can use `state` in the code for that arm, like so: `state`をそのアームのコードで使用できます。以下のようにですね: ```rust -# #[derive(Debug)] -# enum UsState { -# Alabama, -# Alaska, -# } -# -# enum Coin { -# Penny, -# Nickel, -# Dime, -# Quarter(UsState), -# } -# -fn value_in_cents(coin: Coin) -> u32 { - match coin { - Coin::Penny => 1, - Coin::Nickel => 5, - Coin::Dime => 10, - Coin::Quarter(state) => { - println!("State quarter from {:?}!", state); - 25 - }, - } -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-09-variable-in-pattern/src/main.rs:here}} ``` 前節では、`Option`を使用する際に、`Some`ケースから中身の`T`の値を取得したくなりました。要するに、 @@ -317,16 +239,7 @@ Listing 6-5. `match`のおかげで、この関数は大変書きやすく、リスト6-5のような見た目になります。 ```rust -fn plus_one(x: Option) -> Option { - match x { - None => None, - Some(i) => Some(i + 1), - } -} - -let five = Some(5); -let six = plus_one(five); -let none = plus_one(None); +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:here}} ``` `plus_one`の最初の実行についてもっと詳しく検証しましょう。`plus_one(five)`と呼び出した時、 -`plus_one`の本体の変数`x`は`Some(5)`になります。そして、これをマッチの各アームと比較します。 +`plus_one`の本体の変数`x`は`Some(5)`になります。そして、これをマッチの各アームと比較します: ```rust,ignore -None => None, +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:first_arm}} ``` -`Some(5)`という値は、`None`というパターンにはマッチしませんので、次のアームに処理が移ります。 +`Some(5)`という値は、`None`というパターンにはマッチしませんので、次のアームに処理が移ります: ```rust,ignore -Some(i) => Some(i + 1), +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:second_arm}} ``` - -`Some(5)`は`Some(i)`にマッチしますか?なんと、します!列挙子が同じです。`i`は`Some`に含まれる値に束縛されるので、 +`Some(5)`は`Some(i)`にマッチしますか?しますね!列挙子が同じです。`i`は`Some`に含まれる値に束縛されるので、 `i`は値`5`になります。それから、このマッチのアームのコードが実行されるので、`i`の値に1を足し、 合計の`6`を中身にした新しい`Some`値を生成します。 さて、`x`が`None`になるリスト6-5の2回目の`plus_one`の呼び出しを考えましょう。`match`に入り、 -最初のアームと比較します。 +最初のアームと比較します: ```rust,ignore -None => None, +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:first_arm}} ``` -もう一つ議論する必要のある`match`の観点があります。一点バグがありコンパイルできないこんなバージョンの`plus_one`関数を考えてください: +もう一つ議論する必要のある`match`の観点があります: アームのパターンはすべての可能性を網羅しなくてはなりません。 +こんなバージョンの`plus_one`関数を考えてください、これにはバグがありコンパイルできないでしょう: -```rust,ignore -fn plus_one(x: Option) -> Option { - match x { - Some(i) => Some(i + 1), - } -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/src/main.rs:here}} ``` - | -6 | match x { - | ^ pattern `None` not covered +```console +{{#include ../listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt}} ``` 全可能性を網羅していないことをコンパイラは検知しています。もっと言えば、どのパターンを忘れているかさえ知っているのです。 Rustにおけるマッチは、*包括的*です: 全てのあらゆる可能性を網羅し尽くさなければ、コードは有効にならないのです。 特に`Option`の場合には、私達が明示的に`None`の場合を処理するのを忘れないようにしてくれます。 -nullになるかもしれないのに値があると思い込まないよう、すなわち前に議論した10億ドルの失敗を犯さないよう、 +nullになるかもしれないのに値があると思い込まないよう、すなわち前に議論した10億ドルの失敗を犯すことができないよう、 コンパイラが保護してくれるわけです。 -### `_`というプレースホルダー +### catch-allパターンとプレースホルダー(`_`) -Rustには、全ての可能性を列挙したくない時に使用できるパターンもあります。例えば、`u8`は、有効な値として、 -0から255までを取ります。1、3、5、7の値にだけ興味があったら、0、2、4、6、8、9と255までの数値を列挙する必要に迫られたくはないです。 -幸運なことに、する必要はありません: 代わりに特別なパターンの`_`を使用できます: +enumを使用することで、いくつかの特定の値に対して特別な操作を行うが、他のすべての値に対してはデフォルトの操作を行う、ということができます。 +ゲームを実装しているところを想像してください。 +サイコロを振って3の目が出たら、そのプレイヤーは移動できませんが、代わりにおしゃれな帽子をもらえます。 +サイコロを振って7の目が出たら、そのプレイヤーはおしゃれな帽子を失います。 +他のすべての値については、そのプレイヤーはゲーム盤上で同じ数だけマスを移動します。 +以下はこのロジックを実装する`match`です。 +ただしサイコロを振った結果はランダム値ではなくハードコードされており、また他のすべてのロジックは、それを実際に実装するのは本題ではないので、本体の無い関数によって表現されています: ```rust -let some_u8_value = 0u8; -match some_u8_value { - 1 => println!("one"), - 3 => println!("three"), - 5 => println!("five"), - 7 => println!("seven"), - _ => (), -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/src/main.rs:here}} ``` + +最初の2つのアームについては、パターンはリテラル値`3`および`7`です。 +他のあらゆる可能な値を網羅する最後のアームについては、パターンは変数で、この変数には`other`と名付けることを選びました。 +`other`アームで実行されるコードは、`move_player`関数にこの変数を渡すことで、この変数を使用しています。 + + + +`u8`が取りうるすべての値を列挙していないにも関わらず、このコードはコンパイルできます。 +最後のパターンが、個別に列挙していないすべての値にマッチするからです。 +このcatch-allパターンのおかげで、`match`は包括的でなくてはならないという必要条件が満たされます。 +パターンは順に評価されるので、catch-allアームは最後に書く必要があることに注意してください。 +catch-allアームを先に書いてしまうと他のアームは絶対に実行されなくなってしまうため、 +catch-allの後にアームを追加するとコンパイラが警告を発するでしょう! + + + +Rustには、catch-allしたいが、catch-allパターン内で値を*使用*したくない時に使用できるパターンもあります: +`_`は任意の値にマッチし、その値を束縛しない特別なパターンです。 +これはコンパイラにその値を使用しないということを伝えるので、コンパイラは未使用の変数についての警告を発しなくなるしょう。 + + + +ゲームのルールを変更しましょう: これからは、3または7以外の目を出したら、もう一度サイコロを振らなくてはなりません。 +catch-allの値を使用する必要がなくなるので、`other`変数の代わりに`_`を使用するようにコードを変更します: + + +```rust +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/src/main.rs:here}} +``` + + + +この例もまた、最後のアームで明示的にすべての他の値を無視しているので、網羅性要件を満たしています; +見落としている場合分けはありません。 + + + +最後に、もう一度だけゲームのルールを変更することにします。 +3または7以外の目を出したら、プレイヤーの番には何も起きません。 +以下の`_`アームのコードのように、ユニット値([「タプル型」][tuples]節で説明した空タプル型)を使用することでこれを表現できます: + +```rust +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/src/main.rs:here}} +``` + + + +このコードでは、先の方のアームのパターンにマッチしないあらゆる値は使用せず、 +この場合にはいかなるコードも実行したくないということを、コンパイラに明示的に伝えています。 + + -`_`というパターンは、どんな値にもマッチします。他のアームの後に記述することで、`_`は、 -それまでに指定されていない全ての可能性にマッチします。`()`は、ただのユニット値なので、`_`の場合には、 -何も起こりません。結果として、`_`プレースホルダーの前に列挙していない可能性全てに対しては、 -何もしたくないと言えるわけです。 +パターンとマッチングについては[第18章][ch18-00-patterns]でさらに深く取り扱います。 +ひとまず、`match`式ではちょっと長ったらしいという状況で便利かもしれない、`if let`構文に進むことにましょう。 -ですが、*一つ*のケースにしか興味がないような場面では、`match`式はちょっと長ったらしすぎます。 -このような場面用に、Rustには、`if let`が用意されています。 +[tuples]: ch03-02-data-types.html#タプル型 +[ch18-00-patterns]: ch18-00-patterns.html diff --git a/src/ch06-03-if-let.md b/src/ch06-03-if-let.md index e946ce219..057123639 100644 --- a/src/ch06-03-if-let.md +++ b/src/ch06-03-if-let.md @@ -7,38 +7,36 @@ `if let`記法で`if`と`let`をより冗長性の少ない方法で組み合わせ、残りを無視しつつ、一つのパターンにマッチする値を扱うことができます。 -`Option`にマッチするけれど、値が3の時にだけコードを実行したい、リスト6-6のプログラムを考えてください。 +`config_max`変数の`Option`値にマッチするけれど、値が`Some`列挙子の時にだけコードを実行したい、リスト6-6のプログラムを考えてください。 ```rust -let some_u8_value = Some(0u8); -match some_u8_value { - Some(3) => println!("three"), - _ => (), -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-06/src/main.rs:here}} ``` -リスト6-6: 値が`Some(3)`の時だけコードを実行する`match` +リスト6-6: 値が`Some`の時だけコードを実行する`match` -`Some(3)`にマッチした時だけ何かをし、他の`Some`値や`None`値の時には何もしたくありません。 -`match`式を満たすためには、列挙子を一つだけ処理した後に`_ => ()`を追加しなければなりません。 -これでは、追加すべき定型コードが多すぎます。 +値が`Some`の場合は、その`Some`列挙子の値をパターン内の変数`max`に束縛することで、それを出力します。 +`None`値に対しては何もしたくありません。 +`match`式の要件を満たすためには、列挙子を一つだけ処理した後に`_ => ()`を追加しなければなりませんが、これは煩わしい定型コードです。 -`if let`という記法は等号記号で区切られたパターンと式を取り、式が`match`に与えられ、パターンが最初のアームになった`match`と、 -同じ動作をします。 +`if let`という記法は等号記号で区切られたパターンと式を取り、式が`match`に与えられ、パターンが最初のアームになった`match`と同じ動作をします。 +この場合は、パターンは`Some(max)`で`max`は`Some`内の値に束縛されます。 +そうすると、対応する`match`アームの中で`max`を使用したのと全く同じように、`if let`ブロックの本体の中で`max`を使用することができます。 +値がパターンにマッチしない場合は、`if let`ブロック内のコードは実行されません。 `if let`では、`else`を含むこともできます。`else`に入るコードブロックは、 @@ -101,53 +102,17 @@ expression like this: 見かけたクォーター以外のコインの枚数を数えたいなら、以下のように`match`式で実現することができるでしょう: ```rust -# #[derive(Debug)] -# enum UsState { -# Alabama, -# Alaska, -# } -# -# enum Coin { -# Penny, -# Nickel, -# Dime, -# Quarter(UsState), -# } -# let coin = Coin::Penny; -let mut count = 0; -match coin { - // {:?}州のクォーターコイン - Coin::Quarter(state) => println!("State quarter from {:?}!", state), - _ => count += 1, -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-13-count-and-announce-match/src/main.rs:here}} ``` または、以下のように`if let`と`else`を使うこともできるでしょう: ```rust -# #[derive(Debug)] -# enum UsState { -# Alabama, -# Alaska, -# } -# -# enum Coin { -# Penny, -# Nickel, -# Dime, -# Quarter(UsState), -# } -# let coin = Coin::Penny; -let mut count = 0; -if let Coin::Quarter(state) = coin { - println!("State quarter from {:?}!", state); -} else { - count += 1; -} +{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-14-count-and-announce-if-let-else/src/main.rs:here}} ``` From 20bed516851c17f4963e4d9d60cbb194ce86ff0c Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:03 +0900 Subject: [PATCH 08/22] =?UTF-8?q?ch07=20=E8=82=A5=E5=A4=A7=E5=8C=96?= =?UTF-8?q?=E3=81=97=E3=81=A6=E3=81=84=E3=81=8F=E3=83=97=E3=83=AD=E3=82=B8?= =?UTF-8?q?=E3=82=A7=E3=82=AF=E3=83=88=E3=82=92=E3=83=91=E3=83=83=E3=82=B1?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=80=81=E3=82=AF=E3=83=AC=E3=83=BC=E3=83=88?= =?UTF-8?q?=E3=80=81=E3=83=A2=E3=82=B8=E3=83=A5=E3=83=BC=E3=83=AB=E3=82=92?= =?UTF-8?q?=E5=88=A9=E7=94=A8=E3=81=97=E3=81=A6=E7=AE=A1=E7=90=86=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0?= =?UTF-8?q?=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-07-01/Cargo.toml | 3 +- .../listing-07-01/src/lib.rs | 4 - .../listing-07-03/Cargo.toml | 3 +- .../listing-07-03/output.txt | 26 +- .../listing-07-05/Cargo.toml | 3 +- .../listing-07-05/output.txt | 22 +- .../listing-07-07/Cargo.toml | 3 +- .../listing-07-07/src/lib.rs | 4 - .../listing-07-08/Cargo.toml | 3 +- .../listing-07-08/src/lib.rs | 8 +- .../listing-07-09/Cargo.toml | 3 +- .../listing-07-10/Cargo.toml | 3 +- .../listing-07-11/Cargo.toml | 3 +- .../listing-07-11/src/lib.rs | 6 - .../listing-07-12/Cargo.toml | 3 +- .../listing-07-12/output.txt | 28 ++ .../listing-07-12/src/lib.rs | 14 +- .../listing-07-13/Cargo.toml | 3 +- .../listing-07-13/src/lib.rs | 6 - .../listing-07-14/Cargo.toml | 3 +- .../listing-07-15/Cargo.toml | 3 +- .../listing-07-16/Cargo.toml | 3 +- .../listing-07-17/Cargo.toml | 3 +- .../listing-07-17/src/lib.rs | 6 - .../listing-07-18/Cargo.lock | 84 ++--- .../listing-07-18/Cargo.toml | 5 +- .../listing-07-18/src/main.rs | 6 +- .../listing-07-19/Cargo.toml | 3 +- .../listing-07-20/Cargo.toml | 3 +- .../listing-07-21-and-22/Cargo.toml | 3 +- .../listing-07-21-and-22/src/lib.rs | 2 - .../no-listing-01-use-std-unnested/Cargo.lock | 84 ++--- .../no-listing-01-use-std-unnested/Cargo.toml | 5 +- .../src/main.rs | 6 +- .../Cargo.toml | 3 +- .../src/lib.rs | 2 - .../quick-reference-example/Cargo.lock | 7 + .../quick-reference-example/Cargo.toml | 6 + .../quick-reference-example/output.txt | 5 + .../quick-reference-example/src/garden.rs | 1 + .../src/garden/vegetables.rs | 2 + .../quick-reference-example/src/main.rs | 8 + ...ojects-with-packages-crates-and-modules.md | 43 ++- src/ch07-01-packages-and-crates.md | 149 ++++---- ...ng-modules-to-control-scope-and-privacy.md | 253 ++++++++++--- ...referring-to-an-item-in-the-module-tree.md | 357 +++++++++++------- ...g-paths-into-scope-with-the-use-keyword.md | 174 +++++---- ...separating-modules-into-different-files.md | 150 ++++++-- 48 files changed, 950 insertions(+), 577 deletions(-) create mode 100644 listings/ch07-managing-growing-projects/listing-07-12/output.txt create mode 100644 listings/ch07-managing-growing-projects/quick-reference-example/Cargo.lock create mode 100644 listings/ch07-managing-growing-projects/quick-reference-example/Cargo.toml create mode 100644 listings/ch07-managing-growing-projects/quick-reference-example/output.txt create mode 100644 listings/ch07-managing-growing-projects/quick-reference-example/src/garden.rs create mode 100644 listings/ch07-managing-growing-projects/quick-reference-example/src/garden/vegetables.rs create mode 100644 listings/ch07-managing-growing-projects/quick-reference-example/src/main.rs diff --git a/listings/ch07-managing-growing-projects/listing-07-01/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-01/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-01/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-01/src/lib.rs b/listings/ch07-managing-growing-projects/listing-07-01/src/lib.rs index 0e40be70d..591e24557 100644 --- a/listings/ch07-managing-growing-projects/listing-07-01/src/lib.rs +++ b/listings/ch07-managing-growing-projects/listing-07-01/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here mod front_of_house { mod hosting { fn add_to_waitlist() {} @@ -14,6 +13,3 @@ mod front_of_house { fn take_payment() {} } } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch07-managing-growing-projects/listing-07-03/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-03/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-03/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-03/output.txt b/listings/ch07-managing-growing-projects/listing-07-03/output.txt index 2a494c29e..2d06c7fd1 100644 --- a/listings/ch07-managing-growing-projects/listing-07-03/output.txt +++ b/listings/ch07-managing-growing-projects/listing-07-03/output.txt @@ -4,17 +4,29 @@ error[E0603]: module `hosting` is private --> src/lib.rs:9:28 | 9 | crate::front_of_house::hosting::add_to_waitlist(); - | ^^^^^^^ + | ^^^^^^^ --------------- function `add_to_waitlist` is not publicly re-exported + | | + | private module + | +note: the module `hosting` is defined here + --> src/lib.rs:2:5 + | +2 | mod hosting { + | ^^^^^^^^^^^ error[E0603]: module `hosting` is private --> src/lib.rs:12:21 | 12 | front_of_house::hosting::add_to_waitlist(); - | ^^^^^^^ - -error: aborting due to 2 previous errors + | ^^^^^^^ --------------- function `add_to_waitlist` is not publicly re-exported + | | + | private module + | +note: the module `hosting` is defined here + --> src/lib.rs:2:5 + | +2 | mod hosting { + | ^^^^^^^^^^^ For more information about this error, try `rustc --explain E0603`. -error: could not compile `restaurant`. - -To learn more, run the command again with --verbose. +error: could not compile `restaurant` (lib) due to 2 previous errors diff --git a/listings/ch07-managing-growing-projects/listing-07-05/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-05/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-05/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-05/output.txt b/listings/ch07-managing-growing-projects/listing-07-05/output.txt index 664c6a480..98d8d6e2a 100644 --- a/listings/ch07-managing-growing-projects/listing-07-05/output.txt +++ b/listings/ch07-managing-growing-projects/listing-07-05/output.txt @@ -4,17 +4,25 @@ error[E0603]: function `add_to_waitlist` is private --> src/lib.rs:9:37 | 9 | crate::front_of_house::hosting::add_to_waitlist(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ private function + | +note: the function `add_to_waitlist` is defined here + --> src/lib.rs:3:9 + | +3 | fn add_to_waitlist() {} + | ^^^^^^^^^^^^^^^^^^^^ error[E0603]: function `add_to_waitlist` is private --> src/lib.rs:12:30 | 12 | front_of_house::hosting::add_to_waitlist(); - | ^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors + | ^^^^^^^^^^^^^^^ private function + | +note: the function `add_to_waitlist` is defined here + --> src/lib.rs:3:9 + | +3 | fn add_to_waitlist() {} + | ^^^^^^^^^^^^^^^^^^^^ For more information about this error, try `rustc --explain E0603`. -error: could not compile `restaurant`. - -To learn more, run the command again with --verbose. +error: could not compile `restaurant` (lib) due to 2 previous errors diff --git a/listings/ch07-managing-growing-projects/listing-07-07/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-07/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-07/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs b/listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs index 74788f6cf..1e7c8b03c 100644 --- a/listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs +++ b/listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here mod front_of_house { pub mod hosting { pub fn add_to_waitlist() {} @@ -14,6 +13,3 @@ pub fn eat_at_restaurant() { // 相対パス front_of_house::hosting::add_to_waitlist(); } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch07-managing-growing-projects/listing-07-08/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-08/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-08/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs b/listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs index a789379ae..b3ddb4f0f 100644 --- a/listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs +++ b/listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs @@ -1,14 +1,10 @@ -// ANCHOR: here -fn serve_order() {} +fn deliver_order() {} mod back_of_house { fn fix_incorrect_order() { cook_order(); - super::serve_order(); + super::deliver_order(); } fn cook_order() {} } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch07-managing-growing-projects/listing-07-09/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-09/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-09/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-10/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-10/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-10/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-11/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-11/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-11/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-11/src/lib.rs b/listings/ch07-managing-growing-projects/listing-07-11/src/lib.rs index 3a7568375..cf31a9c97 100644 --- a/listings/ch07-managing-growing-projects/listing-07-11/src/lib.rs +++ b/listings/ch07-managing-growing-projects/listing-07-11/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here mod front_of_house { pub mod hosting { pub fn add_to_waitlist() {} @@ -9,9 +8,4 @@ use crate::front_of_house::hosting; pub fn eat_at_restaurant() { hosting::add_to_waitlist(); - hosting::add_to_waitlist(); - hosting::add_to_waitlist(); } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch07-managing-growing-projects/listing-07-12/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-12/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-12/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-12/output.txt b/listings/ch07-managing-growing-projects/listing-07-12/output.txt new file mode 100644 index 000000000..ae7425abc --- /dev/null +++ b/listings/ch07-managing-growing-projects/listing-07-12/output.txt @@ -0,0 +1,28 @@ +$ cargo build + Compiling restaurant v0.1.0 (file:///projects/restaurant) +error[E0433]: failed to resolve: use of undeclared crate or module `hosting` +(エラー: 名前解決に失敗しました: 宣言されていないクレートまたはモジュール`hosting`の使用) + --> src/lib.rs:11:9 + | +11 | hosting::add_to_waitlist(); + | ^^^^^^^ use of undeclared crate or module `hosting` + | (宣言されていないクレートまたはモジュール`hosting`の使用) + | +help: consider importing this module through its public re-export +(ヘルプ: 公開再エクスポートからこのモジュールをインポートすることを検討してください) + | +10 + use crate::hosting; + | + +warning: unused import: `crate::front_of_house::hosting` +(警告: 未使用のインポート: `crate::front_of_house::hosting`) + --> src/lib.rs:7:5 + | +7 | use crate::front_of_house::hosting; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +For more information about this error, try `rustc --explain E0433`. +warning: `restaurant` (lib) generated 1 warning +error: could not compile `restaurant` (lib) due to 1 previous error; 1 warning emitted diff --git a/listings/ch07-managing-growing-projects/listing-07-12/src/lib.rs b/listings/ch07-managing-growing-projects/listing-07-12/src/lib.rs index 6b0101b7d..afc759423 100644 --- a/listings/ch07-managing-growing-projects/listing-07-12/src/lib.rs +++ b/listings/ch07-managing-growing-projects/listing-07-12/src/lib.rs @@ -1,17 +1,13 @@ -// ANCHOR: here mod front_of_house { pub mod hosting { pub fn add_to_waitlist() {} } } -use self::front_of_house::hosting; +use crate::front_of_house::hosting; -pub fn eat_at_restaurant() { - hosting::add_to_waitlist(); - hosting::add_to_waitlist(); - hosting::add_to_waitlist(); +mod customer { + pub fn eat_at_restaurant() { + hosting::add_to_waitlist(); + } } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch07-managing-growing-projects/listing-07-13/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-13/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-13/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-13/src/lib.rs b/listings/ch07-managing-growing-projects/listing-07-13/src/lib.rs index 98414aac9..c72994efe 100644 --- a/listings/ch07-managing-growing-projects/listing-07-13/src/lib.rs +++ b/listings/ch07-managing-growing-projects/listing-07-13/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here mod front_of_house { pub mod hosting { pub fn add_to_waitlist() {} @@ -9,9 +8,4 @@ use crate::front_of_house::hosting::add_to_waitlist; pub fn eat_at_restaurant() { add_to_waitlist(); - add_to_waitlist(); - add_to_waitlist(); } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch07-managing-growing-projects/listing-07-14/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-14/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-14/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-14/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-15/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-15/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-15/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-16/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-16/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-16/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-16/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-17/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-17/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-17/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-17/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-17/src/lib.rs b/listings/ch07-managing-growing-projects/listing-07-17/src/lib.rs index e948d7c38..45cf1bac9 100644 --- a/listings/ch07-managing-growing-projects/listing-07-17/src/lib.rs +++ b/listings/ch07-managing-growing-projects/listing-07-17/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here mod front_of_house { pub mod hosting { pub fn add_to_waitlist() {} @@ -9,9 +8,4 @@ pub use crate::front_of_house::hosting; pub fn eat_at_restaurant() { hosting::add_to_waitlist(); - hosting::add_to_waitlist(); - hosting::add_to_waitlist(); } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch07-managing-growing-projects/listing-07-18/Cargo.lock b/listings/ch07-managing-growing-projects/listing-07-18/Cargo.lock index c346748e5..2ae9e459e 100644 --- a/listings/ch07-managing-growing-projects/listing-07-18/Cargo.lock +++ b/listings/ch07-managing-growing-projects/listing-07-18/Cargo.lock @@ -1,87 +1,75 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "bitflags" -version = "1.2.1" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cloudabi" -version = "0.0.3" +name = "getrandom" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "guessing_game" version = "0.1.0" dependencies = [ - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand", ] [[package]] name = "libc" -version = "0.2.53" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.5.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_chacha", + "rand_core", ] [[package]] -name = "rand_core" -version = "0.3.1" +name = "rand_chacha" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)" = "ec350a9417dfd244dc9a6c4a71e13895a4db6b92f0b106f07ebbc3f3bc580cee" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/listings/ch07-managing-growing-projects/listing-07-18/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-18/Cargo.toml index ad5ca696d..d508e9578 100644 --- a/listings/ch07-managing-growing-projects/listing-07-18/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-18/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "guessing_game" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] -rand = "0.5.5" +rand = "0.8.5" diff --git a/listings/ch07-managing-growing-projects/listing-07-18/src/main.rs b/listings/ch07-managing-growing-projects/listing-07-18/src/main.rs index 233198a58..7eda7322f 100644 --- a/listings/ch07-managing-growing-projects/listing-07-18/src/main.rs +++ b/listings/ch07-managing-growing-projects/listing-07-18/src/main.rs @@ -10,9 +10,9 @@ use std::{cmp::Ordering, io}; fn main() { println!("Guess the number!"); - let secret_number = rand::thread_rng().gen_range(1, 101); + let secret_number = rand::thread_rng().gen_range(1..=100); - println!("The secret number is: {}", secret_number); + println!("The secret number is: {secret_number}"); println!("Please input your guess."); @@ -24,7 +24,7 @@ fn main() { let guess: u32 = guess.trim().parse().expect("Please type a number!"); - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), diff --git a/listings/ch07-managing-growing-projects/listing-07-19/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-19/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-19/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-19/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-20/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-20/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-20/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-20/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-21-and-22/Cargo.toml b/listings/ch07-managing-growing-projects/listing-07-21-and-22/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/listing-07-21-and-22/Cargo.toml +++ b/listings/ch07-managing-growing-projects/listing-07-21-and-22/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/listing-07-21-and-22/src/lib.rs b/listings/ch07-managing-growing-projects/listing-07-21-and-22/src/lib.rs index 065b1b804..d6769556a 100644 --- a/listings/ch07-managing-growing-projects/listing-07-21-and-22/src/lib.rs +++ b/listings/ch07-managing-growing-projects/listing-07-21-and-22/src/lib.rs @@ -4,6 +4,4 @@ pub use crate::front_of_house::hosting; pub fn eat_at_restaurant() { hosting::add_to_waitlist(); - hosting::add_to_waitlist(); - hosting::add_to_waitlist(); } diff --git a/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/Cargo.lock b/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/Cargo.lock index 2b3d41ad6..2ae9e459e 100644 --- a/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/Cargo.lock +++ b/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/Cargo.lock @@ -1,87 +1,75 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "bitflags" -version = "1.2.0" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cloudabi" -version = "0.0.3" +name = "getrandom" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "guessing_game" version = "0.1.0" dependencies = [ - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand", ] [[package]] name = "libc" -version = "0.2.51" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.5.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_chacha", + "rand_core", ] [[package]] -name = "rand_core" -version = "0.3.1" +name = "rand_chacha" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/Cargo.toml b/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/Cargo.toml index 10932024b..7eda67aea 100644 --- a/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/Cargo.toml +++ b/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/Cargo.toml @@ -1,10 +1,9 @@ [package] name = "guessing_game" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.5.5" +rand = "0.8.5" diff --git a/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/src/main.rs b/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/src/main.rs index c46464ec2..ecea756fa 100644 --- a/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/src/main.rs +++ b/listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/src/main.rs @@ -11,9 +11,9 @@ use std::io; fn main() { println!("Guess the number!"); - let secret_number = rand::thread_rng().gen_range(1, 101); + let secret_number = rand::thread_rng().gen_range(1..=100); - println!("The secret number is: {}", secret_number); + println!("The secret number is: {secret_number}"); println!("Please input your guess."); @@ -23,7 +23,7 @@ fn main() { .read_line(&mut guess) .expect("Failed to read line"); - println!("You guessed: {}", guess); + println!("You guessed: {guess}"); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), diff --git a/listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/Cargo.toml b/listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/Cargo.toml index 8bdd0a418..60cec7cb0 100644 --- a/listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/Cargo.toml +++ b/listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "restaurant" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/lib.rs b/listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/lib.rs index 065b1b804..d6769556a 100644 --- a/listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/lib.rs +++ b/listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/lib.rs @@ -4,6 +4,4 @@ pub use crate::front_of_house::hosting; pub fn eat_at_restaurant() { hosting::add_to_waitlist(); - hosting::add_to_waitlist(); - hosting::add_to_waitlist(); } diff --git a/listings/ch07-managing-growing-projects/quick-reference-example/Cargo.lock b/listings/ch07-managing-growing-projects/quick-reference-example/Cargo.lock new file mode 100644 index 000000000..4773c201d --- /dev/null +++ b/listings/ch07-managing-growing-projects/quick-reference-example/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "backyard" +version = "0.1.0" diff --git a/listings/ch07-managing-growing-projects/quick-reference-example/Cargo.toml b/listings/ch07-managing-growing-projects/quick-reference-example/Cargo.toml new file mode 100644 index 000000000..6e904abbe --- /dev/null +++ b/listings/ch07-managing-growing-projects/quick-reference-example/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "backyard" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch07-managing-growing-projects/quick-reference-example/output.txt b/listings/ch07-managing-growing-projects/quick-reference-example/output.txt new file mode 100644 index 000000000..e36a45eb0 --- /dev/null +++ b/listings/ch07-managing-growing-projects/quick-reference-example/output.txt @@ -0,0 +1,5 @@ +$ cargo run + Compiling backyard v0.1.0 (file:///projects/backyard) + Finished dev [unoptimized + debuginfo] target(s) in 0.36s + Running `target/debug/backyard` +I'm growing Asparagus! diff --git a/listings/ch07-managing-growing-projects/quick-reference-example/src/garden.rs b/listings/ch07-managing-growing-projects/quick-reference-example/src/garden.rs new file mode 100644 index 000000000..6c7f9b1cb --- /dev/null +++ b/listings/ch07-managing-growing-projects/quick-reference-example/src/garden.rs @@ -0,0 +1 @@ +pub mod vegetables; diff --git a/listings/ch07-managing-growing-projects/quick-reference-example/src/garden/vegetables.rs b/listings/ch07-managing-growing-projects/quick-reference-example/src/garden/vegetables.rs new file mode 100644 index 000000000..b00f785ef --- /dev/null +++ b/listings/ch07-managing-growing-projects/quick-reference-example/src/garden/vegetables.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct Asparagus {} diff --git a/listings/ch07-managing-growing-projects/quick-reference-example/src/main.rs b/listings/ch07-managing-growing-projects/quick-reference-example/src/main.rs new file mode 100644 index 000000000..7a024a9a0 --- /dev/null +++ b/listings/ch07-managing-growing-projects/quick-reference-example/src/main.rs @@ -0,0 +1,8 @@ +use crate::garden::vegetables::Asparagus; + +pub mod garden; + +fn main() { + let plant = Asparagus {}; + println!("I'm growing {:?}!", plant); +} diff --git a/src/ch07-00-managing-growing-projects-with-packages-crates-and-modules.md b/src/ch07-00-managing-growing-projects-with-packages-crates-and-modules.md index 77ed82d97..415f39404 100644 --- a/src/ch07-00-managing-growing-projects-with-packages-crates-and-modules.md +++ b/src/ch07-00-managing-growing-projects-with-packages-crates-and-modules.md @@ -4,44 +4,43 @@ # 肥大化していくプロジェクトをパッケージ、クレート、モジュールを利用して管理する -大きなプログラムを書く時、そのすべてを頭の中に入れておくのは不可能になるため、コードのまとまりを良くすることが重要になります。 +書いているプログラムが大きいときほど、コードを整理しておくことはますます重要になります。 関係した機能をまとめ、異なる特徴を持つコードを分割することにより、特定の機能を実装しているコードを見つけたり、機能を変更したりするためにどこを探せば良いのかを明確にできます。 私達がこれまでに書いてきたプログラムは、一つのファイル内の一つのモジュール内にありました。 -プロジェクトが大きくなるにつれて、これを複数のモジュールに、ついで複数のファイルに分割することで、プログラムを整理することができます。 +プロジェクトが大きくなるにつれて、これを複数のモジュールに、ついで複数のファイルに分割することで、プログラムを整理するべきです。 パッケージは複数のバイナリクレートからなり、またライブラリクレートを1つもつこともできます。 パッケージが大きくなるにつれて、その一部を抜き出して分離したクレートにし、外部依存とするのもよいでしょう。 この章ではそれらのテクニックすべてを学びます。 相互に関係し合い、同時に成長するパッケージの集まりからなる巨大なプロジェクトには、 -Cargoがワークスペースという機能を提供します。これは14章の[Cargoワークスペース][workspaces]で解説します。 +Cargoが*ワークスペース*という機能を提供します。これは14章の[Cargoワークスペース][workspaces]で解説します。 -機能をグループにまとめられることに加え、実装の詳細がカプセル化されることにより、コードをより高いレベルで再利用できるようになります: -手続きを実装し終えてしまえば、他のコードはそのコードの公開されたインターフェースを通じて、実装の詳細を知ることなくそのコードを呼び出すことができるのです。 +実装の詳細をカプセル化することについても議論します。カプセル化によって、コードをより高いレベルで再利用できるようになります: +手続きを実装し終えてしまえば、他のコードはその公開されたインターフェースを通じて、実装の詳細を知る必要なくそのコードを呼び出すことができるのです。 コードをどう書くかによって、どの部分が他のコードにも使える公開のものになるのか、それとも自分だけが変更できる非公開のものになるのかが決定されます。 これもまた、記憶しておくべき細部を制限してくれる方法のひとつです。 diff --git a/src/ch07-01-packages-and-crates.md b/src/ch07-01-packages-and-crates.md index 05320c41e..fd5417e1d 100644 --- a/src/ch07-01-packages-and-crates.md +++ b/src/ch07-01-packages-and-crates.md @@ -4,29 +4,80 @@ ## パッケージとクレート 最初に学ぶモジュールシステムの要素は、パッケージとクレートです。 -クレートはバイナリかライブラリのどちらかです。 -*クレートルート (crate root)* とは、Rustコンパイラの開始点となり、クレートのルートモジュールを作るソースファイルのことです(モジュールについて詳しくは[「モジュールを定義して、スコープとプライバシーを制御する」][modules]のセクションで説明します)。 -*パッケージ* はある機能群を提供する1つ以上のクレートです。 + + +*クレート (crate)* は、Rustコンパイラが一度に考慮する最小限のコードです。 +`cargo`を実行するのではなく、(ちょうど第1章の「Rustプログラムを書いて走らせる」節でやったように)単一のソースコードファイルを渡して`rustc`を実行した場合でも、 +コンパイラはそのファイルをクレートとしてみなします。 +クレートはモジュールを含むことができ、モジュールは、クレートとともにコンパイルされる他のファイル内で定義することができます。 +このことについてはこれからの節で見ていきます。 + + +クレートは2種類の形態のうちいずれかです: バイナリクレートか、ライブラリクレートです。 +*バイナリクレート (binary crate)* は、コマンドラインプログラムやサーバなどの実行可能形式にコンパイルされ、実行することができるプログラムです。 +どのバイナリクレートも、その実行可能形式が実行されたときに何が起きるかを定義する`main`と呼ばれる関数を持たなくてはなりません。 +今まで作ってきたクレートはすべてバイナリクレートでした。 + + +*ライブラリクレート (library crate)* は`main`関数を持たず、実行可能形式へとコンパイルされません。 +代わりに、複数のプロジェクトで共有されることを想定した機能を定義するものです。 +例えば、[第2章][rand]で使用した`rand`クレートは乱数を生成する機能を提供します。 +Rustaceanが「クレート」と言うときの、ほとんどの場合それはライブラリクレートのことであり、 +Rustaceanは「クレート」を一般的なプログラミング概念の「ライブラリ」と同じ意味で使用します。 + + +*クレートルート (crate root)* とは、Rustコンパイラの開始点となり、クレートのルートモジュールを作るソースファイルのことです(モジュールについて詳しくは[「モジュールを定義して、スコープとプライバシーを制御する」][modules]のセクションで説明します)。 + + +*パッケージ (package)* はある機能群を提供する1つ以上のクレートのまとまりです。 パッケージは *Cargo.toml* という、それらのクレートをどのようにビルドするかを説明するファイルを持っています。 +Cargoは実のところパッケージで、今までコードをビルドするために使ってきたコマンドラインツールのためのバイナリクレートを含んでいます。 +Cargoパッケージは、このバイナリクレートが依存するライブラリクレートも含んでいます。 +他のプロジェクトはCargoライブラリクレートに依存することで、Cargoコマンドラインツールが使用するのと同じロジックを使用することもできます。 -パッケージが何を持ってよいかはいくつかのルールで決まっています。 -パッケージは0個か1個のライブラリクレートを持っていないといけません。それ以上は駄目です。 -バイナリクレートはいくらでも持って良いですが、少なくとも(ライブラリでもバイナリでも良いですが)1つのクレートを持っていないといけません。 +パッケージは好きなだけバイナリクレートを持つことができますが、ライブラリクレートは最大で1個しか持つことができません。 +パッケージはライブラリクレートかバイナリクレートを問わず、少なくとも1個のクレートを持っていないといけません。 -このコマンドを入力したとき、Cargoは *Cargo.toml* ファイルを作り、パッケージを作ってくれました。 -*Cargo.toml* の中身を見ても、*src/main.rs* については何も書いてありません。これは、Cargoは *src/main.rs* が、パッケージと同じ名前を持つバイナリクレートのクレートルートであるという慣習に従っているためです。 +`cargo new`を実行した後、Cargoが作成したものを確認するために`ls`を使っています。 +プロジェクトディレクトリ内には *Cargo.toml* ファイルがあり、これがパッケージを構成します。 +また、*main.rs* を含む *src* ディレクトリもあります。 +*Cargo.toml* をテキストエディタで開くと、*src/main.rs* については何も書いていないことに気づくでしょう。 +Cargoは *src/main.rs* が、パッケージと同じ名前を持つバイナリクレートのクレートルートであるという慣習に従っています。 同じように、Cargoはパッケージディレクトリに *src/lib.rs* が含まれていたら、パッケージにはパッケージと同じ名前のライブラリクレートが含まれており、*src/lib.rs* がそのクレートルートなのだと判断します。 Cargoはクレートルートファイルを `rustc`に渡し、ライブラリやバイナリをビルドします。 今、このパッケージには *src/main.rs* しか含まれておらず、つまりこのパッケージは`my-project`という名前のバイナリクレートのみを持っているということです。 -もしパッケージが *src/main.rs* と *src/lib.rs* を持っていたら、クレートは2つになります:どちらもパッケージと同じ名前を持つ、ライブラリクレートとバイナリクレートです。 +もしパッケージが *src/main.rs* と *src/lib.rs* を持っていたら、クレートは2つになります:どちらもパッケージと同じ名前を持つ、バイナリクレートとライブラリクレートです。 ファイルを *src/bin* ディレクトリに置くことで、パッケージは複数のバイナリクレートを持つことができます。それぞれのファイルが別々のバイナリクレートになります。 - - -クレートは、関連した機能を一つのスコープにまとめることで、その機能が複数のプロジェクト間で共有しやすいようにします。 -例えば、[2章][rand]で使った`rand`クレートは、乱数を生成する機能を提供します。 -`rand`クレートを私達のプロジェクトのスコープに持ち込むことで、この機能を私達のプロジェクトで使うことができます。 -`rand`クレートが提供する機能にはすべて、クレートの名前`rand`を使ってアクセスできます。 - - -クレートの機能をそれ自身のスコープの中に入れたままにしておくことは、ある機能が私達のクレートで定義されたのか`rand`クレートで定義されたのかを明確にし、名前の衝突を予防してくれます。 -例えば、`rand`クレートは`Rng`という名前のトレイトを提供しています。 -更に、私達のクレートで`Rng`という名前の`struct`を定義することもできます。 -クレートの機能はそのスコープ内の名前空間に位置づけられているので、`rand`を依存先として追加しても、コンパイラは`Rng`という名前が何を意味するのかについて混乱することはないのです。 -私達のクレートでは、私達の定義した`struct Rng`のことであり、`rand`クレートの`Rng`トレイトには`rand::Rng`でアクセスするというわけです。 - -では、モジュールシステムの話に移りましょう! - [modules]: ch07-02-defining-modules-to-control-scope-and-privacy.html [rand]: ch02-00-guessing-game-tutorial.html#乱数を生成する diff --git a/src/ch07-02-defining-modules-to-control-scope-and-privacy.md b/src/ch07-02-defining-modules-to-control-scope-and-privacy.md index 87c77098d..4ced90bcc 100644 --- a/src/ch07-02-defining-modules-to-control-scope-and-privacy.md +++ b/src/ch07-02-defining-modules-to-control-scope-and-privacy.md @@ -7,86 +7,238 @@ In this section, we’ll talk about modules and other parts of the module system, namely *paths* that allow you to name items; the `use` keyword that brings a path into scope; and the `pub` keyword to make items public. We’ll also discuss -the `as` keyword, external packages, and the glob operator. For now, let’s -focus on modules! +the `as` keyword, external packages, and the glob operator. --> この節では、モジュールと、その他のモジュールシステムの要素 ――すなわち、要素に名前をつけるための *パス* 、パスをスコープに持ち込む`use`キーワード、要素を公開する`pub`キーワード―― について学びます。 また、`as`キーワード、外部パッケージ、glob演算子についても話します。 -とりあえず、今はモジュールに集中しましょう! -*モジュール* はクレート内のコードをグループ化し、可読性と再利用性を上げるのに役に立ちます。 -モジュールは要素の *プライバシー* も制御できます。プライバシーとは、要素がコードの外側で使える *(公開 public)* のか、内部の実装の詳細であり外部では使えない *(非公開 private)* のかです。 +まずは、将来コードを整理するときの簡単なリファレンスとして、規則の一覧を示します。 +その後で各規則を詳細に説明します。 + + +### モジュールのチートシート + + +以下に、モジュール、パス、`use`キーワード、そして`pub`キーワードがコンパイラ内でどう機能するか、そして多くの開発者はどのようにコードを整理するかについての、クイックリファレンスを提供します。 +この章ではこれらの各規則の実例を見ていきますが、ここはモジュールがどう機能するか思い出すために見直すのに良い場所となるでしょう。 + + +- **クレートルートから始める**: クレートをコンパイルするとき、 + コンパイラはまずコンパイル対象のコードとしてクレートルートファイル(通常は、ライブラリクレートでは *src/lib.rs*、バイナリクレートでは *src/main.rs*)の中を探します。 +- **モジュールを宣言する**: クレートルートファイルの中で、新しいモジュールを宣言することができます; + 例えば、`mod garden;`として“garden”モジュールを宣言したとします。コンパイラは以下の場所からモジュールのコードを探します: + - インライン。`mod garden`の後のセミコロンが波かっこで置き換えられているとき、その中 + - *src/garden.rs* ファイルの中 + - *src/garden/mod.rs* ファイルの中 +- **サブモジュールを宣言する**: クレートルート以外のすべてのファイルの中で、サブモジュールを宣言することができます。 + 例えば、*src/garden.rs* 内で`mod vegetables;`と宣言することができます。コンパイラはサブモジュールのコードを、親モジュールに対応するディレクトリ内の以下の場所から探します: + - インライン。`mod vegetables`のすぐ後にセミコロンの代わりに波かっこがあるとき、その中 + - *src/garden/vegetables.rs* ファイルの中 + - *src/garden/vegetables/mod.rs* ファイルの中 +- **モジュール内のコードへのパス**: モジュールがクレートの一部となったら、プライバシー規則が許す限り同じクレート内のどこからでも、そのモジュール内のコードをコードへのパスを使用して参照できます。 + 例えば、garden vegetablesモジュール内の`Asparagus`型は`crate::garden::vegetables::Asparagus`で参照できます。 +- **非公開と公開**: モジュール内のコードはデフォルトでは非公開で、親モジュールからアクセスすることができません。 + モジュールを公開にするには、`mod`ではなく`pub mod`で宣言してください。 + 公開モジュール内の要素も公開にするには、それらの宣言の前に`pub`を付けてください。 +- **`use`キーワード**: `use`キーワードは、長いパスの繰り返しを減らすために、要素へのショートカットをスコープ内に作成します。 + `crate::garden::vegetables::Asparagus`を参照できるスコープ内であれば、`use crate::garden::vegetables::Asparagus;`でショートカットを作成でき、 + 以降はそのスコープ内ではその型を使用するためには`Asparagus`とだけ書けばよくなります。 + + +これらの規則を説明するための例として、ここに`backyard`という名前のバイナリクレートを作成します。 +クレートのディレクトリは、同じく`backyard`と名付けられ、以下のファイルとディレクトリを含んでいます: + +```text +backyard +├── Cargo.lock +├── Cargo.toml +└── src + ├── garden + │   └── vegetables.rs + ├── garden.rs + └── main.rs +``` + + +この場合のクレートルートファイルは *src/main.rs* であり、以下の内容を含んでいます: + + +ファイル名: src/main.rs + +```rust,noplayground,ignore +{{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/main.rs}} +``` + + +`pub mod garden;`の行は、コンパイラに*src/garden.rs*で見つかるコードを含めるように指示します。 +その内容は: + + +ファイル名: src/garden.rs + +```rust,noplayground,ignore +{{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/garden.rs}} +``` + + +この`pub mod vegetables;`は *src/garden/vegetables.rs* のコードも含めると言う意味です。 +そのコードは: + +```rust,noplayground,ignore +{{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/garden/vegetables.rs}} +``` + + +それでは、これらのルールの詳細を知り、実際に試してみましょう! + + +### 関連するコードをモジュールにまとめる + + +*モジュール (module)* はクレート内のコードを整理し、可読性と再利用性を上げるのに役に立ちます。 +モジュール内のコードはデフォルトでは非公開なので、モジュールは要素の*プライバシー (priavacy)* の制御も可能にします。 +非公開の要素は、外部からの使用ができない内部的な実装の詳細です。 +モジュールとそれらの中の要素は公開にするかどうかを選ぶことができ、公開にすると、外部のコードがそれを使用し、それに依存できるようになります。 + 例えば、レストランの機能を提供するライブラリクレートを書いてみましょう。 -実際にレストランを実装することではなく、コードの関係性に注目したいので、関数にシグネチャをつけますが中身は空白のままにします。 +レストランの実装ではなくコードの関係性に注目したいので、関数にシグネチャをつけますが中身は空白のままにします。 -レストラン業界では、レストランの一部を *接客部門 (front of house)* といい、その他を *後方部門 (back of house)* といいます。 +レストラン業界では、レストランの一部を*接客部門 (front of house)* といい、その他を*後方部門 (back of house)* といいます。 接客部門とはお客さんがいるところです。接客係がお客様を席に案内し、給仕係が注文と支払いを受け付け、バーテンダーが飲み物を作ります。 後方部門とはシェフや料理人がキッチンで働き、皿洗い係が食器を片付け、マネージャが管理業務をする場所です。 -私達のクレートを現実のレストランと同じような構造にするために、関数をネストしたモジュールにまとめましょう。 -`restaurant`という名前の新しいライブラリを`cargo new --lib restaurant`と実行することで作成し、Listing 7-1 のコードを *src/lib.rs* に書き込み、モジュールと関数のシグネチャを定義してください。 +私達のクレートをこのような構造にするために、関数をネストしたモジュールにまとめましょう。 +`restaurant`という名前の新しいライブラリを`cargo new --lib restaurant`と実行することで作成し、リスト7-1のコードを *src/lib.rs* に書き込み、モジュールと関数のシグネチャを定義してください。 +以下が接客部門です: ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-01/src/lib.rs:here}} +```rust,noplayground +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-01/src/lib.rs}} ``` -Listing 7-1: `front_of_house`モジュールにその他のモジュールが含まれ、さらにそれらが関数を含んでいる +リスト7-1: `front_of_house`モジュールにその他のモジュールが含まれ、さらにそれらが関数を含んでいる -モジュールは、`mod`キーワードを書き、次にモジュールの名前(今回の場合、`front_of_house`)を指定することで定義されます。 +モジュールは、`mod`キーワードと、それに続くモジュールの名前(今回の場合、`front_of_house`)によって定義されます。 +次にモジュールの本体が波かっこの中に入ります。 モジュールの中には、今回だと`hosting`と`serving`のように、他のモジュールをおくこともできます。 -モジュールにはその他の要素の定義も置くことができます。例えば、構造体、enum、定数、トレイト、そして(Listing 7-1のように)関数です。 +モジュールにはその他の要素の定義も置くことができます。例えば、構造体、enum、定数、トレイト、そして(リスト7-1のように)関数です。 モジュールを使うことで、関連する定義を一つにまとめ、関連する理由を名前で示せます。 このコードを使うプログラマーは、定義を全部読むことなく、グループ単位でコードを読み進められるので、欲しい定義を見つけ出すのが簡単になるでしょう。 @@ -104,7 +256,7 @@ known as the *module tree*. -Listing 7-2は、Listing 7-1の構造のモジュールツリーを示しています。 +リスト7-2は、リスト7-1の構造のモジュールツリーを示しています。 ```text crate @@ -122,21 +274,20 @@ crate Listing 7-2: The module tree for the code in Listing 7-1 --> -Listing 7-2: Listing 7-1 のコードのモジュールツリー +リスト7-2: リスト7-1 のコードのモジュールツリー -このツリーを見ると、どのモジュールがどのモジュールの中にネストしているのかがわかります(例えば、`hosting`は`front_of_house`の中にネストしています)。 -また、いくつかのモジュールはお互いに *兄弟* の関係にある、つまり、同じモジュール内で定義されていることもわかります(例えば`hosting`と`serving`は`front_of_house`で定義されています)。 -他にも、家族関係の比喩を使って、モジュールAがモジュールBの中に入っている時、AはBの *子* であるといい、BはAの *親* であるといいます。 +このツリーを見ると、どのモジュールがどのモジュールの中にネストしているのかがわかります; 例えば、`hosting`は`front_of_house`の中にネストしています。 +また、いくつかのモジュールはお互いに*兄弟 (siblings)* の関係にある、つまり、同じモジュール内で定義されていることもわかります; 例えば`hosting`と`serving`は`front_of_house`で定義されている兄弟同士です。 +他にも、モジュールAがモジュールBの中に入っている時、AはBの*子 (child)* であるといい、BはAの*親 (parent)* であるといいます。 モジュールツリー全体が、暗黙のうちに作られた`crate`というモジュールの下にあることにも注目してください。 ファイルシステムの中を移動する時と同じように、Rustにモジュールツリー内の要素を見つけるためにはどこを探せばいいのか教えるためにパスを使います。 -関数を呼び出したいなら、そのパスを知っていなければなりません。 +関数を呼び出すためには、そのパスを知っていなければなりません。 -* *絶対パス* は、クレートの名前か`crate`という文字列を使うことで、クレートルートからスタートします。 -* *相対パス* は、`self`、`super`または今のモジュール内の識別子を使うことで、現在のモジュールからスタートします。 +* *絶対パス* は、クレートルートを起点とするフルパスです; + 絶対パスは、外部のクレートに属するコードに関してはそのクレート名で始まり、現在のクレートに属するコードに関してはリテラル`crate`で始まります。 +* *相対パス* は、現在のモジュールを起点とし、`self`、`super`、または今のモジュール内の識別子を使います。 -Listing 7-1の例に戻ってみましょう。 -`add_to_waitlist`関数をどうやって呼べばいいでしょうか? -すなわち、`add_to_waitlist`のパスは何でしょうか? -Listing 7-3 は、モジュールと関数をいくつか取り除いてコードをやや簡潔にしています。 -これを使って、クレートルートに定義された新しい`eat_at_restaurant`という関数から、`add_to_waitlist`関数を呼びだす2つの方法を示しましょう。 +Returning to Listing 7-1, say we want to call the `add_to_waitlist` function. +This is the same as asking: what’s the path of the `add_to_waitlist` function? +Listing 7-3 contains Listing 7-1 with some of the modules and functions +removed. +--> +リスト7-1に戻ってみて、例えば`add_to_waitlist`関数を呼びたいとしましょう。 +これはこう聞くのと同じです: `add_to_waitlist`のパスは何でしょうか? +リスト7-3は、リスト7-1からいくつかのモジュールと関数を削除したものを含んでいます。 + + +これを使って、クレートルートに定義された新しい`eat_at_restaurant`という関数から、`add_to_waitlist`関数を呼び出す2つの方法を示しましょう。 +これらのパスは正しいものですが、この例をこのままではコンパイルできなくしている問題が他に残っています。 +理由はすぐに説明します。 + + `eat_at_restaurant`関数はこのライブラリクレートの公開 (public) APIの1つなので、`pub`キーワードをつけておきます。 -`pub`については、[パスを`pub`キーワードで公開する][pub]の節でより詳しく学びます。 -この例はまだコンパイルできないことに注意してください。理由はすぐに説明します。 +`pub`については、[「パスを`pub`キーワードで公開する」][pub]の節でより詳しく学びます。 -Listing 7-3: `add_to_waitlist` 関数を絶対パスと相対パスで呼び出す +リスト7-3: `add_to_waitlist` 関数を絶対パスと相対パスで呼び出す `eat_at_restaurant`で最初に`add_to_waitlist`関数を呼び出す時、絶対パスを使っています。 `add_to_waitlist`関数は`eat_at_restaurant`と同じクレートで定義されているので、`crate`キーワードで絶対パスを始めることができます。 - - -`crate`の後は、`add_to_waitlist`にたどり着くまで、後に続くモジュールを書き込んでいます。 -同じ構造のファイルシステムを想像すれば、`/front_of_house/hosting/add_to_waitlist`とパスを指定して`add_to_waitlist`を実行していることに相当します。 +続けて、`add_to_waitlist`にたどり着くまで、後に続くモジュールを書き込んでいます。 +同じ構造のファイルシステムを想像してもよいでしょう: `/front_of_house/hosting/add_to_waitlist`とパスを指定して`add_to_waitlist`を実行していることに相当します。 `crate`という名前を使ってクレートルートからスタートするというのは、`/`を使ってファイルシステムのルートからスタートするようなものです。 `eat_at_restaurant`で2回目に`add_to_waitlist`関数を呼び出す時、相対パスを使っています。 パスは、モジュールツリーにおいて`eat_at_restaurant`と同じ階層で定義されているモジュールである`front_of_house`からスタートします。 これはファイルシステムで`front_of_house/hosting/add_to_waitlist`というパスを使っているのに相当します。 -名前から始めるのは、パスが相対パスであることを意味します。 +モジュール名から始めるのは、パスが相対パスであることを意味します。 相対パスを使うか絶対パスを使うかは、プロジェクトによって決めましょう。 要素を定義するコードを、その要素を使うコードと別々に動かすか一緒に動かすか、どちらが起こりそうかによって決めるのが良いです。 例えば、`front_of_house`モジュールと`eat_at_restaurant`関数を`customer_experience`というモジュールに移動させると、`add_to_waitlist`への絶対パスを更新しないといけませんが、相対パスは有効なままです。 しかし、`eat_at_restaurant`関数だけを`dining`というモジュールに移動させると、`add_to_waitlist`への絶対パスは同じままですが、相対パスは更新しないといけないでしょう。 -コードの定義と、その要素の呼び出しは独立に動かしそうなので、絶対パスのほうが好ましいです。 +一般論としては、コードの定義と、その要素の呼び出しは独立に動かしたいことが多いと思われるので、絶対パスのほうが好ましいです。 -では、Listing 7-3 をコンパイルしてみて、どうしてこれはまだコンパイルできないのか考えてみましょう! -エラーをListing 7-4 に示しています。 +では、リスト7-3をコンパイルしてみて、どうしてこれはまだコンパイルできないのか考えてみましょう! +エラーをリスト7-4に示しています。 ```console {{#include ../listings/ch07-managing-growing-projects/listing-07-03/output.txt}} @@ -134,16 +139,21 @@ error we get is shown in Listing 7-4. Listing 7-4: Compiler errors from building the code in Listing 7-3 --> -Listing 7-4: Listing 7-3のコードをビルドしたときのコンパイルエラー +リスト7-4: リスト7-3のコードをビルドしたときのコンパイルエラー エラーメッセージは、`hosting`は非公開 (private) だ、と言っています。 言い換えるなら、`hosting`モジュールと`add_to_waitlist`関数へのパスは正しいが、非公開な部分へのアクセスは許可されていないので、Rustがそれを使わせてくれないということです。 +Rustでは、すべての要素(関数、メソッド、構造体、enum、モジュール、そして定数)はデフォルトでは親モジュールに対して非公開です。 +関数や構造体などの要素を非公開にしたければ、モジュールの中に置いてください。 -Rustにおけるプライバシーは、「あらゆる要素(関数、メソッド、構造体、enum、モジュールおよび定数)は標準では非公開」というやり方で動いています。 親モジュールの要素は子モジュールの非公開要素を使えませんが、子モジュールの要素はその祖先モジュールの要素を使えます。 これは、子モジュールは実装の詳細を覆い隠しますが、子モジュールは自分の定義された文脈を見ることができるためです。 -レストランの喩えを続けるなら、レストランの後方部門になったつもりでプライバシーのルールを考えてみてください。レストランの顧客にはそこで何が起こっているのかは非公開ですが、そこで働くオフィスマネージャには、レストランのことは何でも見えるし何でもできるのです。 +レストランの喩えを続けるなら、レストランの後方部門になったつもりでプライバシーのルールを考えてみてください。レストランの顧客にはそこで何が起こっているのかは非公開ですが、そこを運営するオフィスマネージャには、レストランのことは何でも見えるし何でもできるのです。 Rustは、内部実装の詳細を隠すことが標準であるようにモジュールシステムを機能させることを選択しました。 こうすることで、内部のコードのどの部分が、外部のコードを壊すことなく変更できるのかを知ることができます。 -しかし、`pub`キーワードを使って要素を公開することで、子モジュールの内部部品を外部の祖先モジュールに見せることができます。 +しかし、Rustは`pub`キーワードを使って要素を公開することで、子モジュールの内部部品を外部の祖先モジュールに見せるという選択肢も与えています。 -Listing 7-4の、`hosting`モジュールが非公開だと言ってきていたエラーに戻りましょう。 -親モジュールの`eat_at_restaurant`関数が子モジュールの`add_to_waitlist`関数にアクセスできるようにしたいので、`hosting`モジュールに`pub`キーワードをつけます。Listing 7-5のようになります。 +リスト7-4の、`hosting`モジュールが非公開だと言ってきていたエラーに戻りましょう。 +親モジュールの`eat_at_restaurant`関数が子モジュールの`add_to_waitlist`関数にアクセスできるようにしたいので、`hosting`モジュールに`pub`キーワードをつけます。リスト7-5のようになります。 -Listing 7-5: `hosting` モジュールを `pub` として宣言することで`eat_at_restaurant`から使う +リスト7-5: `hosting` モジュールを `pub` として宣言することで`eat_at_restaurant`から使う -残念ながら、Listing 7-5 のコードもListing 7-6 に示されるようにエラーとなります。 +残念ながら、リスト7-5のコードもリスト7-6に示されるようにエラーとなります。 ```console {{#include ../listings/ch07-managing-growing-projects/listing-07-05/output.txt}} @@ -226,27 +233,31 @@ Listing 7-6. Listing 7-6: Compiler errors from building the code in Listing 7-5 --> -Listing 7-6: Listing 7-5 のコードをビルドしたときのコンパイルエラー +リスト7-6: リスト7-5のコードをビルドしたときのコンパイルエラー 何が起きたのでしょう?`pub`キーワードを`mod hosting`の前に追加したことで、このモジュールは公開されました。 この変更によって、`front_of_house`にアクセスできるなら、`hosting`にもアクセスできるようになりました。 しかし`hosting`の *中身* はまだ非公開です。モジュールを公開してもその中身は公開されないのです。 -モジュールに`pub`キーワードがついていても、祖先モジュールのコードはモジュールを参照できるようになるだけです。 - +モジュールに`pub`キーワードがついていても、祖先モジュールのコードはモジュールを参照できるようになるだけで、その内部のコードへのアクセスは許可されません。 +モジュールはコンテナなので、モジュールを公開しただけでは、できることはあまりありません; +さらに先へ進み、モジュール内のひとつまたは複数の要素も公開することを選択する必要があります。 -Listing 7-6 のエラーは`add_to_waitlist`関数が非公開だと言っています。 +リスト7-6のエラーは`add_to_waitlist`関数が非公開だと言っています。 プライバシーのルールは、モジュール同様、構造体、enum、関数、メソッドにも適用されるのです。 ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs:here}} +```rust,noplayground,test_harness +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs}} ``` -Listing 7-7: `pub`キーワードを`mod hosting`と`fn add_to_waitlist`に追加することで、`eat_at_restaurant`からこの関数を呼べるようになる +リスト7-7: `pub`キーワードを`mod hosting`と`fn add_to_waitlist`に追加することで、`eat_at_restaurant`からこの関数を呼べるようになる これでこのコードはコンパイルできます! -絶対パスと相対パスをもう一度確認して、どうして`pub`キーワードを追加することで`add_to_waitlist`のそれらのパスを使えるようになるのか、プライバシールールの観点からもう一度確認してみてみましょう。 +どうして`pub`キーワードを追加することで`add_to_waitlist`のそれらのパスを使えるようになるのか、 +プライバシールールの観点から確認するために、絶対パスと相対パスを見てみましょう。 絶対パスは、クレートのモジュールツリーのルートである`crate`から始まります。 クレートルートの中に`front_of_house`が定義されています。 @@ -310,59 +322,119 @@ function call is valid! `front_of_house`モジュールは`eat_at_restaurant`と同じモジュールで定義されているので、`eat_at_restaurant`が定義されている場所からの相対パスが使えます。 そして、`hosting`と`add_to_waitlist`は`pub`が付いていますから、残りのパスについても問題はなく、この関数呼び出しは有効というわけです。 + +他のプロジェクトからあなたのコードを利用できるようにライブラリクレートを共有するつもりなら、 +公開APIは、クレート利用者があなたのコードとどう相互作用できるかを決定する、クレート利用者との契約となります。 +人々があなたのクレートに依存しやすくするためには、公開APIへの変更の管理に関する多数の考慮事項があります。 +これらの考慮事項はこの本のスコープ外です; このトピックに興味がある場合は、[The Rust API Guidelines][api-guidelines]を参照してください。 + + + +> #### バイナリとライブラリの両方を持つパッケージでのベストプラクティス +> +> パッケージは*src/main.rs*バイナリクレートルートと*src/lib.rs*ライブラリクレートルートの両方を含むことができ、 +> デフォルトでは両方のクレートがパッケージ名を持つことを説明しました。 +> 典型的には、ライブラリとバイナリのクレート両方を含むこのパターンのパッケージでは、バイナリクレートには +> ライブラリクレートのコードを呼び出して、実行可能形式を開始するために必要な最低限のコードを持たせます。 +> こうすることで、ライブラリクレートのコードは共有できるので、 +> 他のプロジェクトはこのパッケージが提供するほとんどの機能を活用することができます。 +> +> モジュールツリーは*src/lib.rs*内に定義してください。 +> その場合、バイナリクレートからは、パッケージ名でから始まるパスを使って公開された要素を使用することができます。 +> バイナリクレートは、そのライブラリクレートを利用する完全に外部のクレートとまったく同じように、 +> ライブラリクレートの利用者になります: 公開APIしか使用することができません。 +> これは良いAPIを設計する助けになります; あなたは作者であるだけでなく、利用者にもなるのです! +> +> [第12章][ch12]では、バイナリクレートとライブラリクレートの両方を含むコマンドラインプログラムを使って、 +> この整理法の実践を示します。 + ### 相対パスを`super`で始める -親モジュールから始まる相対パスなら、`super`を最初につけることで構成できます。 +現在のモジュールやクレートルートではなく、親モジュールから始まる相対パスなら、`super`を最初につけることで構成できます。 ファイルシステムパスを`..`構文で始めるのに似ています。 -どのようなときにこの機能が使いたくなるのでしょう? +`super`を使用することで、親モジュールにあることを知っている要素を参照することができます。 +これにより、そのモジュールが親と密接に関連しているが、いつか親がモジュールツリー内のどこかに移動されるかもしれないという場合に、モジュールツリーを再編成するのがより簡単になるかもしれません。 -シェフが間違った注文を修正し、自分でお客さんに持っていくという状況をモデル化している、Listing 7-8 を考えてみてください。 -`fix_incorrect_order`関数は`serve_order`関数を呼び出すために、`super`から始まる`serve_order`関数へのパスを使っています。 +シェフが間違った注文を修正し、自分でお客さんに持っていくという状況をモデル化している、リスト7-8を考えてみてください。 +`back_of_house`モジュールで定義されている`fix_incorrect_order`関数は、親モジュールで定義されている`deliver_order`関数を呼び出すために、`super`から始まる`deliver_order`関数へのパスを使っています。 ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs:here}} +```rust,noplayground,test_harness +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs}} ``` -Listing 7-8: `super` で始まる相対パスを使って関数を呼び出す +リスト7-8: `super` で始まる相対パスを使って関数を呼び出す `fix_incorrect_order`関数は`back_of_house`モジュールの中にあるので、`super`を使って`back_of_house`の親モジュールにいけます。親モジュールは、今回の場合ルートである`crate`です。 -そこから、`serve_order`を探し、見つけ出します。 +そこから、`deliver_order`を探し、見つけ出します。 成功! -もしクレートのモジュールツリーを再編成することにした場合でも、`back_of_house`モジュールと`serve_order`関数は同じ関係性で有り続け、一緒に動くように思われます。 +もしクレートのモジュールツリーを再編成することにした場合でも、`back_of_house`モジュールと`deliver_order`関数は同じ関係性で有り続け、一緒に動くように思われます。 そのため、`super`を使うことで、将来このコードが別のモジュールに移動するとしても、更新する場所が少なくて済むようにしました。 -構造体やenumも`pub`を使って公開するよう指定できますが、追加の細目がいくつかあります。 +few details extra to the usage of `pub` with structs and enums. If we use `pub` +before a struct definition, we make the struct public, but the struct’s fields +will still be private. We can make each field public or not on a case-by-case +basis. In Listing 7-9, we’ve defined a public `back_of_house::Breakfast` struct +with a public `toast` field but a private `seasonal_fruit` field. This models +the case in a restaurant where the customer can pick the type of bread that +comes with a meal, but the chef decides which fruit accompanies the meal based +on what’s in season and in stock. The available fruit changes quickly, so +customers can’t choose the fruit or even see which fruit they’ll get. +--> +構造体やenumも`pub`を使って公開するよう指定できますが、構造体とenumでの`pub`の使用に関しては追加の細目がいくつかあります。 構造体定義の前に`pub`を使うと、構造体は公開されますが、構造体のフィールドは非公開のままなのです。 それぞれのフィールドを公開するか否かを個々に決められます。 -Listing 7-9 では、公開の`toast`フィールドと、非公開の`seasonal_fruit`フィールドをもつ公開の`back_of_house::Breakfast`構造体を定義しました。 +リスト7-9では、公開の`toast`フィールドと、非公開の`seasonal_fruit`フィールドをもつ公開の`back_of_house::Breakfast`構造体を定義しました。 これは、例えば、レストランで、お客さんが食事についてくるパンの種類は選べるけれど、食事についてくるフルーツは季節と在庫に合わせてシェフが決める、という状況をモデル化しています。 提供できるフルーツはすぐに変わるので、お客さんはフルーツを選ぶどころかどんなフルーツが提供されるのか知ることもできません。 @@ -394,7 +466,7 @@ Listing 7-9 では、公開の`toast`フィールドと、非公開の`seasonal_ --> ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-09/src/lib.rs}} ``` @@ -402,7 +474,7 @@ Listing 7-9 では、公開の`toast`フィールドと、非公開の`seasonal_ Listing 7-9: A struct with some public fields and some private fields --> -Listing 7-9: 公開のフィールドと非公開のフィールドとを持つ構造体 +リスト7-9: 公開のフィールドと非公開のフィールドとを持つ構造体 一方で、enumを公開すると、そのヴァリアントはすべて公開されます。 -Listing 7-10 に示されているように、`pub`は`enum`キーワードの前にだけおけばよいのです。 +リスト7-10に示されているように、`pub`は`enum`キーワードの前にだけおけばよいのです。 ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-10/src/lib.rs}} ``` @@ -446,17 +518,21 @@ Listing 7-10 に示されているように、`pub`は`enum`キーワードの Listing 7-10: Designating an enum as public makes all its variants public --> -Listing 7-10: enumを公開に指定することはそのヴァリアントをすべて公開にする +リスト7-10: enumを公開に指定することはそのヴァリアントをすべて公開にする `Appetizer`というenumを公開したので、`Soup`と`Salad`というヴァリアントも`eat_at_restaurant`で使えます。 + + enumはヴァリアントが公開されてないとあまり便利ではないのですが、毎回enumのすべてのヴァリアントに`pub`をつけるのは面倒なので、enumのヴァリアントは標準で公開されるようになっているのです。 構造体はフィールドが公開されていなくても便利なことが多いので、構造体のフィールドは、`pub`がついてない限り標準で非公開という通常のルールに従うわけです。 @@ -468,4 +544,11 @@ first, and then we’ll show how to combine `pub` and `use`. まだ勉強していない、`pub`の関わるシチュエーションがもう一つあります。モジュールシステムの最後の機能、`use`キーワードです。 `use`自体の勉強をした後、`pub`と`use`を組み合わせる方法についてお見せします。 -[pub]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#%E3%83%91%E3%82%B9%E3%82%92pub%E3%82%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%89%E3%81%A7%E5%85%AC%E9%96%8B%E3%81%99%E3%82%8B + +[pub]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#パスをpubキーワードで公開する +[api-guidelines]: https://rust-lang.github.io/api-guidelines/ +[ch12]: ch12-00-an-io-project.html diff --git a/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md b/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md index 3048b18a5..c18f17263 100644 --- a/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md +++ b/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md @@ -4,18 +4,17 @@ ## `use`キーワードでパスをスコープに持ち込む -これまで関数呼び出しのために書いてきたパスは、長く、繰り返しも多くて不便なものでした。 -例えば、Listing 7-7 においては、絶対パスを使うか相対パスを使うかにかかわらず、`add_to_waitlist`関数を呼ぼうと思うたびに`front_of_house`と`hosting`も指定しないといけませんでした。 -ありがたいことに、この手続きを簡単化する方法があります。 -`use`キーワードを使うことで、パスを一度スコープに持ち込んでしまえば、それ以降はパス内の要素がローカルにあるかのように呼び出すことができるのです。 +関数を呼び出すためにパスを略さずに書かなくてはならないのは、繰り返しも多くて不便に感じられるでしょう。 +リスト7-7においては、絶対パスを使うか相対パスを使うかにかかわらず、`add_to_waitlist`関数を呼ぼうと思うたびに`front_of_house`と`hosting`も指定しないといけませんでした。 +ありがたいことに、この手続きを簡単化する方法があります: +一度`use`キーワードを使ってショートカットを作成すれば、そのスコープ内であればどこでも、より短い名前を使用できます。 -Listing 7-11 では、`crate::front_of_house::hosting`モジュールを`eat_at_restaurant`関数のスコープに持ち込むことで、`eat_at_restaurant`において、`hosting::add_to_waitlist`と指定するだけで`add_to_waitlist`関数を呼び出せるようにしています。 +リスト7-11では、`crate::front_of_house::hosting`モジュールを`eat_at_restaurant`関数のスコープに持ち込むことで、`eat_at_restaurant`において、`hosting::add_to_waitlist`と指定するだけで`add_to_waitlist`関数を呼び出せるようにしています。 ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-11/src/lib.rs:here}} +```rust,noplayground,test_harness +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-11/src/lib.rs}} ``` -Listing 7-11: `use` でモジュールをスコープに持ち込む +リスト7-11: `use` でモジュールをスコープに持ち込む -`use`と相対パスで要素をスコープに持ち込むこともできます。 -Listing 7-12 はListing 7-11 と同じふるまいを得るためにどう相対パスを書けば良いかを示しています。 +`use`は、`use`が出現した特定のスコープでのみ使えるショートカットを作成することに注意してください。 +リスト7-12は`eat_at_restaurant`関数を新しい子モジュール`customer`の中に移動していますが、このモジュールは`use`文とは異なるスコープなので、この関数本体はコンパイルできないでしょう: ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-12/src/lib.rs:here}} +```rust,noplayground,test_harness,does_not_compile,ignore +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-12/src/lib.rs}} +``` + + +リスト7-12: `use`文はそれが属するスコープ内にのみ適用される + + +コンパイルエラーは`customer`モジュール内ではショートカットが適用されないことを示しています: + +```console +{{#include ../listings/ch07-managing-growing-projects/listing-07-12/output.txt}} ``` -Listing 7-12: モジュールを`use`と相対パスを使ってスコープに持ち込む +`use`がそのスコープ内で使用されていないという警告も出ていることに気づくでしょう! +この問題を修正するには、`use`も`customer`モジュールの中に移動するか、`customer`子モジュールの中で`super::hosting`によって親モジュールにあるショートカットを参照してください。 -Listing 7-11 を見て、なぜ`use crate::front_of_house::hosting`と書いて`eat_at_restaurant`内で`hosting::add_to_waitlist`と呼び出したのか不思議に思っているかもしれません。Listing 7-13 のように、`use`で`add_to_waitlist`までのパスをすべて指定しても同じ結果が得られるのに、と。 +リスト7-11を見て、なぜ`use crate::front_of_house::hosting`と書いて`eat_at_restaurant`内で`hosting::add_to_waitlist`と呼び出したのか不思議に思っているかもしれません。リスト7-13のように、`use`で`add_to_waitlist`までのパスをすべて指定しても同じ結果が得られるのに、と。 ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-13/src/lib.rs:here}} +```rust,noplayground,test_harness +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-13/src/lib.rs}} ``` -Listing 7-13: `add_to_waitlist` 関数を`use` でスコープに持ち込む。このやりかたは慣例的ではない +リスト7-13: `add_to_waitlist` 関数を`use` でスコープに持ち込む。このやりかたは慣例的ではない -Listing 7-11 も 7-13 もおなじ仕事をしてくれますが、関数をスコープに`use`で持ち込む場合、Listing 7-11 のほうが慣例的なやり方です。 -関数の親モジュールを`use`で持ち込むことで、関数を呼び出す際、毎回親モジュールを指定しなければならないようにすれば、フルパスを繰り返して書くことを抑えつつ、関数がローカルで定義されていないことを明らかにできます。 -Listing 7-13 のコードではどこで`add_to_waitlist`が定義されたのかが不明瞭です。 +リスト7-11も7-13もおなじ仕事をしてくれますが、関数をスコープに`use`で持ち込む場合、リスト7-11のほうが慣例的なやり方です。 +関数の親モジュールを`use`で持ち込むということは、関数を呼び出す際、毎回親モジュールを指定しなければならないということです。 +関数を呼び出すときに親モジュールを指定することで、フルパスを繰り返して書くことを抑えつつ、関数がローカルで定義されていないことを明らかにできます。 +リスト7-13のコードではどこで`add_to_waitlist`が定義されたのかが不明瞭です。 一方で、構造体やenumその他の要素を`use`で持ち込むときは、フルパスを書くのが慣例的です。 -Listing 7-14 は標準ライブラリの`HashMap`構造体をバイナリクレートのスコープに持ち込む慣例的なやり方を示しています。 +リスト7-14は標準ライブラリの`HashMap`構造体をバイナリクレートのスコープに持ち込む慣例的なやり方を示しています。 -Listing 7-14: `HashMap`を慣例的なやり方でスコープに持ち込む +リスト7-14: `HashMap`を慣例的なやり方でスコープに持ち込む 同じ名前の2つの要素を`use`でスコープに持ち込むのはRustでは許されないので、そのときこの慣例は例外的に不可能です。 -Listing 7-15は、同じ名前を持つけれど異なる親モジュールを持つ2つの`Result`型をスコープに持ち込み、それらを参照するやり方を示しています。 +リスト7-15は、同じ名前を持つけれど異なる親モジュールを持つ2つの`Result`型をスコープに持ち込み、それらを参照するやり方を示しています。 ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-15/src/lib.rs:here}} ``` @@ -167,7 +188,7 @@ Listing 7-15は、同じ名前を持つけれど異なる親モジュールを Listing 7-15: Bringing two types with the same name into the same scope requires using their parent modules. --> -Listing 7-15: 同じ名前を持つ2つの型を同じスコープに持ち込むには親モジュールを使わないといけない。 +リスト7-15: 同じ名前を持つ2つの型を同じスコープに持ち込むには親モジュールを使わないといけない。 -同じ名前の2つの型を`use`を使って同じスコープに持ち込むという問題には、もう一つ解決策があります。パスの後に、`as`と型の新しいローカル名、即ちエイリアスを指定すればよいのです。 -Listing 7-16 は、Listing 7-15 のコードを、2つの`Result`型のうち一つを`as`を使ってリネームするという別のやり方で書いたものを表しています。 +同じ名前の2つの型を`use`を使って同じスコープに持ち込むという問題には、もう一つ解決策があります。パスの後に、`as`と型の新しいローカル名、即ち*エイリアス*を指定すればよいのです。 +リスト7-16は、リスト7-15のコードを、2つの`Result`型のうち一つを`as`を使ってリネームするという別のやり方で書いたものを表しています。 ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-16/src/lib.rs:here}} ``` @@ -205,7 +226,7 @@ Listing 7-16 は、Listing 7-15 のコードを、2つの`Result`型のうち一 Listing 7-16: Renaming a type when it’s brought into scope with the `as` keyword --> -Listing 7-16: 型がスコープに持ち込まれた時、`as`キーワードを使ってその名前を変えている +リスト7-16: 型がスコープに持ち込まれた時、`as`キーワードを使ってその名前を変えている 2つめの`use`文では、`std::io::Result`に、`IoResult`という新たな名前を選んでやります。`std::fmt`の`Result`もスコープに持ち込んでいますが、この名前はこれとは衝突しません。 -Listing 7-15もListing 7-16も慣例的とみなされているので、どちらを使っても構いませんよ! +リスト7-15もリスト7-16も慣例的とみなされているので、どちらを使っても構いませんよ! -Listing 7-17 は Listing 7-11 のコードのルートモジュールでの`use`を`pub use`に変更したものを示しています。 +リスト7-17はリスト7-11のコードのルートモジュールでの`use`を`pub use`に変更したものを示しています。 ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-17/src/lib.rs:here}} +```rust,noplayground,test_harness +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-17/src/lib.rs}} ``` -Listing 7-17: `pub use`で、新たなスコープのコードがその名前を使えるようにする +リスト7-17: `pub use`で、新たなスコープのコードがその名前を使えるようにする -`pub use`を使うことで、外部のコードが`hosting::add_to_waitlist`を使って`add_to_waitlist`関数を呼び出せるようになりました。 -`pub use`を使っていなければ、`eat_at_restaurant`関数は`hosting::add_to_waitlist`を自らのスコープ内で使えるものの、外部のコードはこの新しいパスを利用することはできないでしょう。 +この変更を行う前の状態では、外部のコードはパス`restaurant::front_of_house::hosting::add_to_waitlist()`を使用して`add_to_wishlist`関数を呼ばなくてはなりませんでした。 +この`pub use`によってルートモジュールから`hosting`モジュールを再公開された今、外部のコードはパス`restaurant::hosting::add_to_waitlist()`を使用できるようになりました。 再公開は、あなたのコードの内部構造と、あなたのコードを呼び出すプログラマーたちのその領域に関しての見方が異なるときに有用です。 例えば、レストランの比喩では、レストランを経営している人は「接客部門 (front of house)」と「後方部門 (back of house)」のことについて考えるでしょう。 しかし、レストランを訪れるお客さんは、そのような観点からレストランの部門について考えることはありません。 `pub use`を使うことで、ある構造でコードを書きつつも、別の構造で公開するということが可能になります。 こうすることで、私達のライブラリを、ライブラリを開発するプログラマにとっても、ライブラリを呼び出すプログラマにとっても、よく整理されたものとすることができます。 +第14章の[「`pub use`で便利な公開APIをエクスポートする」][ch14-pub-use]の節で、`pub use`の別の例と、それがクレートのドキュメンテーションにどう影響するかを見ることにしましょう。 -標準ライブラリ (`std`) も、私達のパッケージの外部にあるクレートだということに注意してください。 +標準`std`ライブラリも、私達のパッケージの外部にあるクレートだということに注意してください。 標準ライブラリはRust言語に同梱されているので、 *Cargo.toml* を `std`を含むように変更する必要はありません。 しかし、その要素をそこから私達のパッケージのスコープに持ち込むためには、`use`を使って参照する必要はあります。 例えば、`HashMap`には次の行を使います。 @@ -370,7 +396,7 @@ files. For example, these two `use` statements we had in the Guessing Game in Listing 2-4 bring items from `std` into scope: --> 同じクレートか同じモジュールで定義された複数の要素を使おうとする時、それぞれの要素を一行一行並べると、縦に大量のスペースを取ってしまいます。 -例えば、Listing 2-4の数当てゲームで使った次の2つの`use`文が`std`からスコープへ要素を持ち込みました。 +例えば、リスト2-4の数当てゲームで使った次の2つの`use`文が`std`からスコープへ要素を持ち込みました。 代わりに、ネストしたパスを使うことで、同じ一連の要素を1行でスコープに持ち込めます。 -これをするには、Listing 7-18 に示されるように、パスの共通部分を書き、2つのコロンを続け、そこで波括弧で互いに異なる部分のパスのリストを囲みます。 +これをするには、リスト7-18に示されるように、パスの共通部分を書き、2つのコロンを続け、そこで波括弧で互いに異なる部分のパスのリストを囲みます。 -Listing 7-18: 同じプレフィックスをもつ複数の要素をスコープに持ち込むためにネストしたパスを指定する +リスト7-18: 同じプレフィックスをもつ複数の要素をスコープに持ち込むためにネストしたパスを指定する ネストしたパスはパスのどの階層においても使うことができます。これはサブパスを共有する2つの`use`文を合体させるときに有用です。 -例えば、Listing 7-19 は2つの`use`文を示しています:1つは`std::io`をスコープに持ち込み、もう一つは`std::io::Write`をスコープに持ち込んでいます。 +例えば、リスト7-19は2つの`use`文を示しています:1つは`std::io`をスコープに持ち込み、もう一つは`std::io::Write`をスコープに持ち込んでいます。 ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-19/src/lib.rs}} ``` @@ -434,21 +460,21 @@ two `use` statements that share a subpath. For example, Listing 7-19 shows two Listing 7-19: Two `use` statements where one is a subpath of the other --> -Listing 7-19: 片方がもう片方のサブパスである2つの`use`文 +リスト7-19: 片方がもう片方のサブパスである2つの`use`文 -これらの2つのパスの共通部分は`std::io`であり、そしてこれは最初のパスにほかなりません。これらの2つのパスを1つの`use`文へと合体させるには、Listing 7-20 に示されるように、ネストしたパスに`self`を使いましょう。 +これらの2つのパスの共通部分は`std::io`であり、そしてこれは最初のパスにほかなりません。これらの2つのパスを1つの`use`文へと合体させるには、リスト7-20に示されるように、ネストしたパスに`self`を使いましょう。 ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-20/src/lib.rs}} ``` @@ -456,7 +482,7 @@ the nested path, as shown in Listing 7-20. Listing 7-20: Combining the paths in Listing 7-19 into one `use` statement --> -Listing 7-20: Listing 7-19 のパスを一つの `use` 文に合体させる +リスト7-20: リスト7-19のパスを一つの `use` 文に合体させる パスにおいて定義されているすべての公開要素をスコープに持ち込みたいときは、glob演算子 `*` をそのパスの後ろに続けて書きましょう: @@ -499,5 +525,11 @@ for more information on that pattern. glob演算子はしばしば、テストの際、テストされるあらゆるものを`tests`モジュールに持ち込むために使われます。これについては11章[テストの書き方][writing-tests]の節で話します。 glob演算子はプレリュードパターンの一部としても使われることがあります:そのようなパターンについて、より詳しくは[標準ライブラリのドキュメント](https://doc.rust-lang.org/std/prelude/index.html#other-preludes)をご覧ください。 + +[ch14-pub-use]: ch14-02-publishing-to-crates-io.html#pub-useで便利な公開apiをエクスポートする [rand]: ch02-00-guessing-game-tutorial.html#乱数を生成する [writing-tests]: ch11-01-writing-tests.html#テストの記述法 diff --git a/src/ch07-05-separating-modules-into-different-files.md b/src/ch07-05-separating-modules-into-different-files.md index 2c45efc91..099d05888 100644 --- a/src/ch07-05-separating-modules-into-different-files.md +++ b/src/ch07-05-separating-modules-into-different-files.md @@ -12,21 +12,33 @@ file to make the code easier to navigate. モジュールが大きくなる時、コードを読み進めやすくするため、それらの定義を別のファイルへ移動させたくなるかもしれません。 -例えば、Listing 7-17 のコードからはじめましょう。クレートルートのファイルをListing 7-21 のコードを持つように変更して、`front_of_house`モジュールをそれ専用のファイル`src/front_of_house.rs`に動かしましょう。 +For example, let’s start from the code in Listing 7-17 that had multiple +restaurant modules. We’ll extract modules into files instead of having all the +modules defined in the crate root file. In this case, the crate root file is +*src/lib.rs*, but this procedure also works with binary crates whose crate root +file is *src/main.rs*. +--> +例として、複数のレストランモジュールを持つリスト7-17のコードからはじめましょう。 +すべてのモジュールをクレートルートファイルで定義するのをやめて、複数のファイルにモジュールを抽出することにします。 今回、クレートルートファイルは`src/lib.rs`ですが、この手続きはクレートルートファイルが`src/main.rs`であるバイナリクレートでもうまく行きます。 + +まず、`front_of_house`モジュールをそれ専用のファイルに抽出しましょう。 +`front_of_house`モジュールの波かっこの中のコードを削除し、`mod front_of_house;`宣言だけを残して、 *src/lib.rs* がリスト7-21に示すコードを含むようにしてください。 +リスト7-22で *src/front_of_house.rs* ファイルを作成するまで、このコードはコンパイルできないことに注意してください。 + ファイル名: src/lib.rs -```rust,ignore +```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-21-and-22/src/lib.rs}} ``` @@ -34,13 +46,16 @@ crates whose crate root file is *src/main.rs*. Listing 7-21: Declaring the `front_of_house` module whose body will be in *src/front_of_house.rs* --> -Listing 7-21: `front_of_house`モジュールを宣言する。その中身は`src/front_of_house.rs`内にある +リスト7-21: `front_of_house`モジュールを宣言する。その中身は`src/front_of_house.rs`内にある -そして、 Listing 7-22 のように、*src/front_of_house.rs* には`front_of_house` モジュールの中身の定義を与えます。 +次に リスト7-22に示すように、*src/front_of_house.rs* という名前の新しいファイルに、波かっこの中にあったコードを配置してください。 +コンパイラは、クレートルートで`front_of_house`という名前のモジュール宣言を見つけたときは、このファイルを探せばいいということを知っています。 -Listing 7-22: *src/front_of_house.rs*における、`front_of_house`モジュール内部の定義 +リスト7-22: *src/front_of_house.rs*における、`front_of_house`モジュール内部の定義 + + +`mod`宣言を使用したファイルのロードは、モジュールツリー内で*一回*のみ行う必要があることに注意してください。 +一度コンパイラが、そのファイルがプロジェクトの一部であることを認識したら(そして、`mod`文を書いた場所に応じてモジュールツリー内のどこにコードがあることになるかを認識したら)、[「モジュールツリーの要素を示すためのパス」][paths]節で扱ったように、プロジェクト内の他のファイルは、モジュールが宣言された場所へのパスを使用してロードされたファイルのコードを参照するべきです。 +別の言い方をすれば、`mod`は他のプログラミング言語で見られるような“include”操作では*ありません*。 + + +つづけて`hosting`モジュールをそれ専用のファイルに抽出します。 +`hosting`はルートモジュールの子ではなく`front_of_house`の子モジュールなので、このプロセスは少し異なります。 +`hosting`のためのファイルを、モジュールツリー上での祖先に対応して名付けられた新しいディレクトリ(今回の場合は *src/front_of_house/*)内に配置しましょう。 -`mod front_of_house`の後にブロックではなくセミコロンを使うと、Rustにモジュールの中身をモジュールと同じ名前をした別のファイルから読み込むように命令します。 -私達の例で、つづけて`hosting`モジュールをそれ専用のファイルに抽出するには、`src/front_of_house.rs`が`hosting`モジュールの宣言のみを含むように変更します: +`hosting`の移動を開始するために、`src/front_of_house.rs`が`hosting`モジュールの宣言のみを含むように変更します: -さらに*src/front_of_house* ディレクトリと*src/front_of_house/hosting.rs* ファイルを作って、`hosting`モジュール内でなされていた定義を持つようにします。 +さらに*src/front_of_house* ディレクトリと*hosting.rs* ファイルを作って、`hosting`モジュール内でなされていた定義を持つようにします。 ファイル名: src/front_of_house/hosting.rs -```rust +```rust,ignore {{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/front_of_house/hosting.rs}} ``` -定義は別のファイルにあるにもかかわらず、モジュールツリーは同じままであり、`eat_at_restaurant`内での関数呼び出しもなんの変更もなくうまく行きます。 +If we instead put *hosting.rs* in the *src* directory, the compiler would +expect the *hosting.rs* code to be in a `hosting` module declared in the crate +root, and not declared as a child of the `front_of_house` module. The +compiler’s rules for which files to check for which modules’ code means the +directories and files more closely match the module tree. +--> +もし*src*ディレクトリ内に*hosting.rs*を置いた場合は、コンパイラは*hosting.rs*のコードは`front_of_house`モジュールの子としてではなく、クレートルート内で宣言された`hosting`モジュールにあると期待するでしょう。 +コンパイラがどのモジュールのコードのためにどのファイルをチェックするかの規則は、ディレクトリとファイルがモジュールツリーと密接に一致することを意味します。 + + +> ### 別のファイルパス +> +> ここまでRustコンパイラが使用するもっとも慣例的なファイルパスについて扱ってきましたが、Rustは古いスタイルのファイルパスもサポートしています。 +> クレートルート内で宣言された`front_of_house`という名前のモジュールに対して、コンパイラは以下の場所からコードを探します: +> +> * *src/front_of_house.rs* (ここまで扱ってきたもの) +> * *src/front_of_house/mod.rs* (古いスタイルの、今もサポートされているパス) +> +> `front_of_house`のサブモジュールである、`hosting`という名前のモジュールに対しては、コンパイラは以下の場所からコードを探します: +> +> * *src/front_of_house/hosting.rs* (ここまで扱ってきたもの) +> * *src/front_of_house/hosting/mod.rs* (古いスタイルの、今もサポートされているパス) +> +> 同一のモジュールに対して両方のスタイルを使用するとコンパイルエラーになります。 +> 異なるモジュールに対して両方のスタイルを混ぜて使用することは許可されていますが、プロジェクトを見て回る人たちにとって混乱を招くかもしれません。 +> +> *mod.rs* という名前のファイルを使用するスタイルの主な欠点は、プロジェクト内に *mod.rs* という名前のファイルが大量にできることになり、エディタで同時に開いたときに混乱を招きやすいことです。 + + +各モジュールのコードを独立したファイルに移動しましたが、モジュールツリーは同じままです。 +定義が別のファイルにあるにもかかわらず、`eat_at_restaurant`内での関数呼び出しもなんの変更もなくうまく行きます。 このテクニックのおかげで、モジュールが大きくなってきた段階で新しいファイルへ動かす、ということができます。 次の章では、きちんと整理されたあなたのコードで使うことができる、標準ライブラリのいくつかのコレクションデータ構造を見ていきます。 + +[paths]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html From d2d9bbb72f2b94499176cd2413466d863f655166 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:03 +0900 Subject: [PATCH 09/22] =?UTF-8?q?ch08=20=E4=B8=80=E8=88=AC=E7=9A=84?= =?UTF-8?q?=E3=81=AA=E3=82=B3=E3=83=AC=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3?= =?UTF-8?q?=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88?= =?UTF-8?q?=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-08-01/Cargo.toml | 3 +- .../listing-08-02/Cargo.toml | 3 +- .../listing-08-03/Cargo.toml | 3 +- .../listing-08-04/Cargo.toml | 3 +- .../listing-08-04/src/main.rs | 18 +- .../listing-08-05/Cargo.toml | 3 +- .../listing-08-05/src/main.rs | 11 +- .../listing-08-06/Cargo.toml | 3 +- .../output.txt | 16 +- .../listing-08-06/src/main.rs | 10 +- .../listing-08-07/Cargo.toml | 3 +- .../listing-08-07/src/main.rs | 11 +- .../listing-08-08/Cargo.toml | 3 +- .../listing-08-08/src/main.rs | 6 +- .../listing-08-09/Cargo.toml | 3 +- .../listing-08-09/src/main.rs | 13 +- .../listing-08-10/Cargo.toml | 3 +- .../listing-08-10/src/main.rs | 16 +- .../listing-08-11/Cargo.toml | 3 +- .../listing-08-12/Cargo.toml | 3 +- .../listing-08-13/Cargo.toml | 3 +- .../listing-08-14/Cargo.toml | 3 +- .../listing-08-15/Cargo.toml | 3 +- .../listing-08-16/Cargo.toml | 3 +- .../listing-08-16/src/main.rs | 2 +- .../listing-08-17/Cargo.toml | 3 +- .../listing-08-18/Cargo.toml | 3 +- .../listing-08-18/src/main.rs | 2 +- .../listing-08-19/Cargo.toml | 3 +- .../listing-08-19/output.txt | 25 +- .../listing-08-20/Cargo.toml | 3 +- .../listing-08-21/Cargo.toml | 3 +- .../listing-08-21/src/main.rs | 10 +- .../listing-08-22/Cargo.toml | 3 +- .../listing-08-22/src/main.rs | 2 + .../listing-08-23/Cargo.toml | 3 +- .../listing-08-23/src/main.rs | 5 +- .../listing-08-24/Cargo.toml | 3 +- .../listing-08-24/src/main.rs | 5 +- .../listing-08-25/Cargo.toml | 3 +- .../listing-08-25/src/main.rs | 13 +- .../listing-08-26/Cargo.lock | 6 - .../listing-08-26/Cargo.toml | 7 - .../listing-08-26/src/main.rs | 16 - .../Cargo.toml | 3 +- .../no-listing-02-format/Cargo.toml | 3 +- .../no-listing-02-format/src/main.rs | 2 +- .../Cargo.toml | 3 +- .../src/main.rs | 2 +- .../Cargo.toml | 3 +- .../output.txt | 7 +- src/ch08-00-common-collections.md | 12 +- src/ch08-01-vectors.md | 370 +++++++-------- src/ch08-02-strings.md | 399 ++++++++-------- src/ch08-03-hash-maps.md | 424 ++++++++---------- 55 files changed, 685 insertions(+), 812 deletions(-) rename listings/ch08-common-collections/{listing-08-07 => listing-08-06}/output.txt (61%) delete mode 100644 listings/ch08-common-collections/listing-08-26/Cargo.lock delete mode 100644 listings/ch08-common-collections/listing-08-26/Cargo.toml delete mode 100644 listings/ch08-common-collections/listing-08-26/src/main.rs diff --git a/listings/ch08-common-collections/listing-08-01/Cargo.toml b/listings/ch08-common-collections/listing-08-01/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-01/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-02/Cargo.toml b/listings/ch08-common-collections/listing-08-02/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-02/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-03/Cargo.toml b/listings/ch08-common-collections/listing-08-03/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-03/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-04/Cargo.toml b/listings/ch08-common-collections/listing-08-04/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-04/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-04/src/main.rs b/listings/ch08-common-collections/listing-08-04/src/main.rs index bae2b87e0..8dc674de9 100644 --- a/listings/ch08-common-collections/listing-08-04/src/main.rs +++ b/listings/ch08-common-collections/listing-08-04/src/main.rs @@ -1,9 +1,17 @@ fn main() { // ANCHOR: here - { - let v = vec![1, 2, 3, 4]; + let v = vec![1, 2, 3, 4, 5]; - // vで作業をする - } // <- vはここでスコープを抜け、解放される - // ANCHOR_END: here + let third: &i32 = &v[2]; + // "3つ目の要素は{third}です" + println!("The third element is {third}"); + + let third: Option<&i32> = v.get(2); + match third { + // "3つ目の要素は{third}です" + Some(third) => println!("The third element is {third}"), + // "3つ目の要素はありません。" + None => println!("There is no third element."), + } + // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-05/Cargo.toml b/listings/ch08-common-collections/listing-08-05/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-05/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-05/src/main.rs b/listings/ch08-common-collections/listing-08-05/src/main.rs index 185ed8eae..783d9b110 100644 --- a/listings/ch08-common-collections/listing-08-05/src/main.rs +++ b/listings/ch08-common-collections/listing-08-05/src/main.rs @@ -2,14 +2,7 @@ fn main() { // ANCHOR: here let v = vec![1, 2, 3, 4, 5]; - let third: &i32 = &v[2]; - println!("The third element is {}", third); - - match v.get(2) { - // "3つ目の要素は{}です" - Some(third) => println!("The third element is {}", third), - // "3つ目の要素はありません。" - None => println!("There is no third element."), - } + let does_not_exist = &v[100]; + let does_not_exist = v.get(100); // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-06/Cargo.toml b/listings/ch08-common-collections/listing-08-06/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-06/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-07/output.txt b/listings/ch08-common-collections/listing-08-06/output.txt similarity index 61% rename from listings/ch08-common-collections/listing-08-07/output.txt rename to listings/ch08-common-collections/listing-08-06/output.txt index a46e34ee7..4bdfb3152 100644 --- a/listings/ch08-common-collections/listing-08-07/output.txt +++ b/listings/ch08-common-collections/listing-08-06/output.txt @@ -7,18 +7,14 @@ error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immuta 4 | let first = &v[0]; | - immutable borrow occurs here | (不変借用はここで発生しています) -5 | +5 | 6 | v.push(6); | ^^^^^^^^^ mutable borrow occurs here | (可変借用はここで発生しています) -7 | -8 | println!("The first element is: {}", first); - | ----- immutable borrow later used here - | (その後、不変借用はここで使われています) - -error: aborting due to previous error +7 | +8 | println!("The first element is: {first}"); + | ------- immutable borrow later used here + | (その後、不変借用はここで使われています) For more information about this error, try `rustc --explain E0502`. -error: could not compile `collections`. - -To learn more, run the command again with --verbose. +error: could not compile `collections` (bin "collections") due to 1 previous error diff --git a/listings/ch08-common-collections/listing-08-06/src/main.rs b/listings/ch08-common-collections/listing-08-06/src/main.rs index 783d9b110..b84d49e52 100644 --- a/listings/ch08-common-collections/listing-08-06/src/main.rs +++ b/listings/ch08-common-collections/listing-08-06/src/main.rs @@ -1,8 +1,12 @@ fn main() { // ANCHOR: here - let v = vec![1, 2, 3, 4, 5]; + let mut v = vec![1, 2, 3, 4, 5]; - let does_not_exist = &v[100]; - let does_not_exist = v.get(100); + let first = &v[0]; + + v.push(6); + + // "最初の要素は: {first}" + println!("The first element is: {first}"); // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-07/Cargo.toml b/listings/ch08-common-collections/listing-08-07/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-07/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-07/src/main.rs b/listings/ch08-common-collections/listing-08-07/src/main.rs index 1b42274a6..aebf855a9 100644 --- a/listings/ch08-common-collections/listing-08-07/src/main.rs +++ b/listings/ch08-common-collections/listing-08-07/src/main.rs @@ -1,11 +1,8 @@ fn main() { // ANCHOR: here - let mut v = vec![1, 2, 3, 4, 5]; - - let first = &v[0]; - - v.push(6); - - println!("The first element is: {}", first); + let v = vec![100, 32, 57]; + for i in &v { + println!("{i}"); + } // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-08/Cargo.toml b/listings/ch08-common-collections/listing-08-08/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-08/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-08/src/main.rs b/listings/ch08-common-collections/listing-08-08/src/main.rs index 38b97784b..c62ba21b4 100644 --- a/listings/ch08-common-collections/listing-08-08/src/main.rs +++ b/listings/ch08-common-collections/listing-08-08/src/main.rs @@ -1,8 +1,8 @@ fn main() { // ANCHOR: here - let v = vec![100, 32, 57]; - for i in &v { - println!("{}", i); + let mut v = vec![100, 32, 57]; + for i in &mut v { + *i += 50; } // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-09/Cargo.toml b/listings/ch08-common-collections/listing-08-09/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-09/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-09/src/main.rs b/listings/ch08-common-collections/listing-08-09/src/main.rs index c62ba21b4..c2198883b 100644 --- a/listings/ch08-common-collections/listing-08-09/src/main.rs +++ b/listings/ch08-common-collections/listing-08-09/src/main.rs @@ -1,8 +1,15 @@ fn main() { // ANCHOR: here - let mut v = vec![100, 32, 57]; - for i in &mut v { - *i += 50; + enum SpreadsheetCell { + Int(i32), + Float(f64), + Text(String), } + + let row = vec![ + SpreadsheetCell::Int(3), + SpreadsheetCell::Text(String::from("blue")), + SpreadsheetCell::Float(10.12), + ]; // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-10/Cargo.toml b/listings/ch08-common-collections/listing-08-10/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-10/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-10/src/main.rs b/listings/ch08-common-collections/listing-08-10/src/main.rs index c2198883b..bae2b87e0 100644 --- a/listings/ch08-common-collections/listing-08-10/src/main.rs +++ b/listings/ch08-common-collections/listing-08-10/src/main.rs @@ -1,15 +1,9 @@ fn main() { // ANCHOR: here - enum SpreadsheetCell { - Int(i32), - Float(f64), - Text(String), - } + { + let v = vec![1, 2, 3, 4]; - let row = vec![ - SpreadsheetCell::Int(3), - SpreadsheetCell::Text(String::from("blue")), - SpreadsheetCell::Float(10.12), - ]; - // ANCHOR_END: here + // vで作業をする + } // <- vはここでスコープを抜け、解放される + // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-11/Cargo.toml b/listings/ch08-common-collections/listing-08-11/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-11/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-12/Cargo.toml b/listings/ch08-common-collections/listing-08-12/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-12/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-13/Cargo.toml b/listings/ch08-common-collections/listing-08-13/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-13/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-14/Cargo.toml b/listings/ch08-common-collections/listing-08-14/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-14/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-14/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-15/Cargo.toml b/listings/ch08-common-collections/listing-08-15/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-15/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-16/Cargo.toml b/listings/ch08-common-collections/listing-08-16/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-16/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-16/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-16/src/main.rs b/listings/ch08-common-collections/listing-08-16/src/main.rs index 8938dc143..db57cddba 100644 --- a/listings/ch08-common-collections/listing-08-16/src/main.rs +++ b/listings/ch08-common-collections/listing-08-16/src/main.rs @@ -3,6 +3,6 @@ fn main() { let mut s1 = String::from("foo"); let s2 = "bar"; s1.push_str(s2); - println!("s2 is {}", s2); + println!("s2 is {s2}"); // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-17/Cargo.toml b/listings/ch08-common-collections/listing-08-17/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-17/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-17/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-18/Cargo.toml b/listings/ch08-common-collections/listing-08-18/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-18/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-18/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-18/src/main.rs b/listings/ch08-common-collections/listing-08-18/src/main.rs index 93939a69f..1b01c3990 100644 --- a/listings/ch08-common-collections/listing-08-18/src/main.rs +++ b/listings/ch08-common-collections/listing-08-18/src/main.rs @@ -2,6 +2,6 @@ fn main() { // ANCHOR: here let s1 = String::from("Hello, "); let s2 = String::from("world!"); - let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used + let s3 = s1 + &s2; // s1はムーブされ、もう使用できないことに注意 // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-19/Cargo.toml b/listings/ch08-common-collections/listing-08-19/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-19/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-19/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-19/output.txt b/listings/ch08-common-collections/listing-08-19/output.txt index c239f7189..2553303df 100644 --- a/listings/ch08-common-collections/listing-08-19/output.txt +++ b/listings/ch08-common-collections/listing-08-19/output.txt @@ -1,16 +1,23 @@ $ cargo run Compiling collections v0.1.0 (file:///projects/collections) -error[E0277]: the type `std::string::String` cannot be indexed by `{integer}` - --> src/main.rs:3:13 +error[E0277]: the type `String` cannot be indexed by `{integer}` +(エラー: 型`String`は`{Integer}`で添え字アクセスできませんん) + --> src/main.rs:3:16 | 3 | let h = s1[0]; - | ^^^^^ `std::string::String` cannot be indexed by `{integer}` + | ^ `String` cannot be indexed by `{integer}` + | (`String`は`{Integer}`で添え字アクセスできません) | - = help: the trait `std::ops::Index<{integer}>` is not implemented for `std::string::String` - -error: aborting due to previous error + = help: the trait `Index<{integer}>` is not implemented for `String` + (ヘルプ: `Index<{Integer}>`というトレイトが`String`に対して実装されていません) + = help: the following other types implement trait `Index`: + (ヘルプ: 以下の型であればトレイト`Index`を実装しています:) + > + >> + >> + >> + >> + >> For more information about this error, try `rustc --explain E0277`. -error: could not compile `collections`. - -To learn more, run the command again with --verbose. +error: could not compile `collections` (bin "collections") due to 1 previous error diff --git a/listings/ch08-common-collections/listing-08-20/Cargo.toml b/listings/ch08-common-collections/listing-08-20/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-20/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-20/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-21/Cargo.toml b/listings/ch08-common-collections/listing-08-21/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-21/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-21/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-21/src/main.rs b/listings/ch08-common-collections/listing-08-21/src/main.rs index 0ebd20d4e..07551549d 100644 --- a/listings/ch08-common-collections/listing-08-21/src/main.rs +++ b/listings/ch08-common-collections/listing-08-21/src/main.rs @@ -2,10 +2,12 @@ fn main() { // ANCHOR: here use std::collections::HashMap; - let teams = vec![String::from("Blue"), String::from("Yellow")]; - let initial_scores = vec![10, 50]; + let mut scores = HashMap::new(); - let mut scores: HashMap<_, _> = - teams.into_iter().zip(initial_scores.into_iter()).collect(); + scores.insert(String::from("Blue"), 10); + scores.insert(String::from("Yellow"), 50); + + let team_name = String::from("Blue"); + let score = scores.get(&team_name).copied().unwrap_or(0); // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-22/Cargo.toml b/listings/ch08-common-collections/listing-08-22/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-22/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-22/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-22/src/main.rs b/listings/ch08-common-collections/listing-08-22/src/main.rs index 2b2a73f94..647538c80 100644 --- a/listings/ch08-common-collections/listing-08-22/src/main.rs +++ b/listings/ch08-common-collections/listing-08-22/src/main.rs @@ -9,5 +9,7 @@ fn main() { map.insert(field_name, field_value); // field_name and field_value are invalid at this point, try using them and // see what compiler error you get! + // field_nameとfield_valueはこの時点で無効になる。試しに使ってみて + // どんなコンパイルエラーが出るか確認してみて! // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-23/Cargo.toml b/listings/ch08-common-collections/listing-08-23/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-23/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-23/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-23/src/main.rs b/listings/ch08-common-collections/listing-08-23/src/main.rs index 508e33cbb..e8684cf2b 100644 --- a/listings/ch08-common-collections/listing-08-23/src/main.rs +++ b/listings/ch08-common-collections/listing-08-23/src/main.rs @@ -5,9 +5,8 @@ fn main() { let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); - scores.insert(String::from("Yellow"), 50); + scores.insert(String::from("Blue"), 25); - let team_name = String::from("Blue"); - let score = scores.get(&team_name); + println!("{:?}", scores); // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-24/Cargo.toml b/listings/ch08-common-collections/listing-08-24/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-24/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-24/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-24/src/main.rs b/listings/ch08-common-collections/listing-08-24/src/main.rs index e8684cf2b..3ad97b57a 100644 --- a/listings/ch08-common-collections/listing-08-24/src/main.rs +++ b/listings/ch08-common-collections/listing-08-24/src/main.rs @@ -3,9 +3,10 @@ fn main() { use std::collections::HashMap; let mut scores = HashMap::new(); - scores.insert(String::from("Blue"), 10); - scores.insert(String::from("Blue"), 25); + + scores.entry(String::from("Yellow")).or_insert(50); + scores.entry(String::from("Blue")).or_insert(50); println!("{:?}", scores); // ANCHOR_END: here diff --git a/listings/ch08-common-collections/listing-08-25/Cargo.toml b/listings/ch08-common-collections/listing-08-25/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/listing-08-25/Cargo.toml +++ b/listings/ch08-common-collections/listing-08-25/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/listing-08-25/src/main.rs b/listings/ch08-common-collections/listing-08-25/src/main.rs index 3ad97b57a..f3f6aa166 100644 --- a/listings/ch08-common-collections/listing-08-25/src/main.rs +++ b/listings/ch08-common-collections/listing-08-25/src/main.rs @@ -2,12 +2,15 @@ fn main() { // ANCHOR: here use std::collections::HashMap; - let mut scores = HashMap::new(); - scores.insert(String::from("Blue"), 10); + let text = "hello world wonderful world"; - scores.entry(String::from("Yellow")).or_insert(50); - scores.entry(String::from("Blue")).or_insert(50); + let mut map = HashMap::new(); - println!("{:?}", scores); + for word in text.split_whitespace() { + let count = map.entry(word).or_insert(0); + *count += 1; + } + + println!("{:?}", map); // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-26/Cargo.lock b/listings/ch08-common-collections/listing-08-26/Cargo.lock deleted file mode 100644 index d3daeff7d..000000000 --- a/listings/ch08-common-collections/listing-08-26/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "collections" -version = "0.1.0" - diff --git a/listings/ch08-common-collections/listing-08-26/Cargo.toml b/listings/ch08-common-collections/listing-08-26/Cargo.toml deleted file mode 100644 index b36871bec..000000000 --- a/listings/ch08-common-collections/listing-08-26/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "collections" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch08-common-collections/listing-08-26/src/main.rs b/listings/ch08-common-collections/listing-08-26/src/main.rs deleted file mode 100644 index f3f6aa166..000000000 --- a/listings/ch08-common-collections/listing-08-26/src/main.rs +++ /dev/null @@ -1,16 +0,0 @@ -fn main() { - // ANCHOR: here - use std::collections::HashMap; - - let text = "hello world wonderful world"; - - let mut map = HashMap::new(); - - for word in text.split_whitespace() { - let count = map.entry(word).or_insert(0); - *count += 1; - } - - println!("{:?}", map); - // ANCHOR_END: here -} diff --git a/listings/ch08-common-collections/no-listing-01-concat-multiple-strings/Cargo.toml b/listings/ch08-common-collections/no-listing-01-concat-multiple-strings/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/no-listing-01-concat-multiple-strings/Cargo.toml +++ b/listings/ch08-common-collections/no-listing-01-concat-multiple-strings/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/no-listing-02-format/Cargo.toml b/listings/ch08-common-collections/no-listing-02-format/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/no-listing-02-format/Cargo.toml +++ b/listings/ch08-common-collections/no-listing-02-format/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/no-listing-02-format/src/main.rs b/listings/ch08-common-collections/no-listing-02-format/src/main.rs index 4a38e63d2..db408e2b7 100644 --- a/listings/ch08-common-collections/no-listing-02-format/src/main.rs +++ b/listings/ch08-common-collections/no-listing-02-format/src/main.rs @@ -4,6 +4,6 @@ fn main() { let s2 = String::from("tac"); let s3 = String::from("toe"); - let s = format!("{}-{}-{}", s1, s2, s3); + let s = format!("{s1}-{s2}-{s3}"); // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/Cargo.toml b/listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/Cargo.toml +++ b/listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/src/main.rs b/listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/src/main.rs index 2e7dc02e6..bb13c86f1 100644 --- a/listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/src/main.rs +++ b/listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/src/main.rs @@ -8,7 +8,7 @@ fn main() { scores.insert(String::from("Yellow"), 50); for (key, value) in &scores { - println!("{}: {}", key, value); + println!("{key}: {value}"); } // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/output-only-01-not-char-boundary/Cargo.toml b/listings/ch08-common-collections/output-only-01-not-char-boundary/Cargo.toml index b36871bec..fe4959823 100644 --- a/listings/ch08-common-collections/output-only-01-not-char-boundary/Cargo.toml +++ b/listings/ch08-common-collections/output-only-01-not-char-boundary/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "collections" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch08-common-collections/output-only-01-not-char-boundary/output.txt b/listings/ch08-common-collections/output-only-01-not-char-boundary/output.txt index e05d33233..52263e818 100644 --- a/listings/ch08-common-collections/output-only-01-not-char-boundary/output.txt +++ b/listings/ch08-common-collections/output-only-01-not-char-boundary/output.txt @@ -2,5 +2,8 @@ $ cargo run Compiling collections v0.1.0 (file:///projects/collections) Finished dev [unoptimized + debuginfo] target(s) in 0.43s Running `target/debug/collections` -thread 'main' panicked at 'byte index 1 is not a char boundary; it is inside 'З' (bytes 0..2) of `Здравствуйте`', src/libcore/str/mod.rs:2069:5 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'main' panicked at src/main.rs:4:19: +byte index 1 is not a char boundary; it is inside 'З' (bytes 0..2) of `Здравствуйте` +('main'スレッドはsrc/main:4:19でパニックしました: +バイト添え字1は文字の境界ではありません; `Здравствуйте`の'З'(バイト0..2)の中です) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/src/ch08-00-common-collections.md b/src/ch08-00-common-collections.md index e90c5ffcf..9bd408a74 100644 --- a/src/ch08-00-common-collections.md +++ b/src/ch08-00-common-collections.md @@ -24,11 +24,11 @@ Rustの標準ライブラリは、*コレクション*と呼ばれる多くの Rustのプログラムにおいて、非常に頻繁に使用される3つのコレクションについて議論しましょう。 * *ベクタ型*は、可変長の値を並べて保持できる。 @@ -45,11 +45,11 @@ see [the documentation][collections]. 標準ライブラリで提供されている他の種のコレクションについて学ぶには、 [ドキュメント][collections]を参照されたし。 -[collections]: https://doc.rust-lang.org/std/collections/index.html - ベクタ型、文字列、ハッシュマップの生成と更新方法や、各々が特別な点について議論していきましょう。 + +[collections]: https://doc.rust-lang.org/std/collections/index.html diff --git a/src/ch08-01-vectors.md b/src/ch08-01-vectors.md index ed7d41633..57ee7a6c2 100644 --- a/src/ch08-01-vectors.md +++ b/src/ch08-01-vectors.md @@ -12,11 +12,10 @@ of the same type. They are useful when you have a list of items, such as the lines of text in a file or the prices of items in a shopping cart. --> -最初に見るコレクション型は`Vec`であり、これは*ベクタ*としても知られています。 -ベクタは単体のデータ構造でありながら複数の値を保持でき、それらの値をメモリ上に隣り合わせに並べます。 -ベクタには同じ型の値しか保持できません。 -要素のリストがある場合にベクタは有用です。 -例えば、テキストファイルの各行とか、ショッピングカートのアイテムの価格などです。 +最初に見るコレクション型は`Vec`です。*ベクタ*とも呼ばれます。 +ベクタを使用することで、複数の値をメモリ上で互いに隣り合うように単一のデータ構造に保持することができます。 +ベクタは同じ型の値のみ保持することができます。 +テキストファイルの各行や、ショッピングカートのアイテムの価格などのような、要素のリストがある場合にベクタは有用です。 -空のベクタを新たに作るには、リスト8-1に示すように`Vec::new`関数を呼びます。 +空のベクタを新たに作成するには、リスト8-1に示すように`Vec::new`関数を呼びます。 ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-01/src/main.rs:here}} @@ -40,44 +39,42 @@ Listing 8-1. of type `i32` --> -リスト8-1:新しい空のベクタを生成して`i32`型の値を保持する +リスト8-1:`i32`型の値を保持する新しい空のベクタを作成する -ここで、型注釈を付けていることに注目してください。 -なぜなら、このベクタに対して何も値を挿入していないので、コンパイラには私たちがどんなデータを保持させるつもりか推測できないからです。 +ここで型注釈を付けていることに注目してください。 +このベクタには何も値を挿入していないので、コンパイラには私たちがどんなデータを保持させるつもりか分かりません。 これは重要な点です。 -ベクタはジェネリクスを使用して実装されています。 -あなた自身の型でどうジェネリクスを使用するかついては第10章で解説します。 -現時点では標準ライブラリで提供される`Vec`型は、どんな型でも保持でき、ある特定のベクタがある型を保持するとき、その型は山かっこ内に指定されることを知っておいてください。 -リスト8-1では、コンパイラに`v`の`Vec`は`i32`型の要素を保持すると指示しました。 +ベクタはジェネリクスを使用して実装されています; ジェネリクスを使用する自身の型をどう使用するかついては第10章で解説します。 +今のところは、標準ライブラリで提供される`Vec`型は、どんな型でも保持できると理解しておいてください。 +特定の型を保持するベクタを作成するときには、その型を山かっこ内に指定すればよいです。 +リスト8-1では、コンパイラに`v`の`Vec`は`i32`型の要素を保持すると指示していたのです。 -いったん値を挿入すると、多くの場合、コンパイラは保持させたい値の型を推論できるようになります。 -ですから、より現実的なコードでは、型注釈を付ける必要はあまりないでしょう。 -また、初期値を持つ`Vec`を生成する方が一般的ですし、Rustには`vec!`という便利なマクロも用意されています。 -このマクロは与えた値を保持する新しいベクタを生成します。 -リスト8-2では、`1`、`2`、`3`という値を持つ新しい`Vec`を生成しています。 -整数型を`i32`にしているのは、3章の[「データ型」][data-types]節で学んだように、これが標準の整数型だからです。 +`Vec`を作成する場合は初期値を持たせることのほうが多いでしょう。 +その場合コンパイラは保持したい値の型を推論するでしょうから、このように型注釈を付ける必要はほとんどありません。 +Rustには`vec!`という便利なマクロが用意されていて、これは与えた値を保持する新しいベクタを作成します。 +リスト8-2では、`1`、`2`、`3`という値を持つ新しい`Vec`を作成しています。 +整数の型が`i32`になっているのは、3章の[「データ型」][data-types]節で学んだように、これがデフォルトの整数型だからです。 ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-02/src/main.rs:here}} @@ -88,7 +85,7 @@ section of Chapter 3. values --> -リスト8-2: 値を含む新しいベクタを生成する +リスト8-2: 値を含む新しいベクタを作成する -ベクタを生成し、それから要素を追加するには、リスト8-3に示すように`push`メソッドを使います。 +ベクタを作成し、それから要素を追加するには、リスト8-3に示すように`push`メソッドを使います。 ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-03/src/main.rs:here}} @@ -133,43 +130,6 @@ we don’t need the `Vec` annotation. 第3章で説明したとおり、どんな変数でも、その値を変更したかったら`mut`キーワードで可変にする必要があります。 中に配置する数値は全て`i32`型であり、Rustはこのことをデータから推論するので、`Vec`という注釈は不要です。 - - -### ベクタをドロップすれば、要素もドロップする - - - -他のあらゆる`struct`(構造体)と同様に、ベクタもスコープを抜ければ解放されます。 -その様子をリスト8-4に示します。 - -```rust -{{#rustdoc_include ../listings/ch08-common-collections/listing-08-04/src/main.rs:here}} -``` - - - -リスト8-4:ベクタとその要素がドロップされる箇所を示す - - - -ベクタがドロップされると、その中身もドロップされます。 -つまり、保持されていた整数値が片付けられるということです。 -これは一見単純そうですが、ベクタの要素に対する参照を使い始めると少し複雑になり得ます。 -次はそれに挑戦しましょう! - @@ -177,69 +137,67 @@ introduce references to the elements of the vector. Let’s tackle that next! ### ベクタの要素を読む -ベクタを生成し、更新し、破棄する方法がわかったので、次のステップでは中身を読む方法について学ぶのが良いでしょう。 -ベクタに保持された値を参照する方法は2つあります。 +ベクタに保持された値を参照する方法は2つあります: 添え字を使用する方法と、`get`メソッドを使用する方法です。 これから示す例では、理解を助けるために、それらの関数からの戻り値型を注釈しています。 リスト8-5はベクタの値にアクセスする両方の方法として、添え字記法と`get`メソッドが示されています。 ```rust -{{#rustdoc_include ../listings/ch08-common-collections/listing-08-05/src/main.rs:here}} +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-04/src/main.rs:here}} ``` -リスト8-5:添え字記法か`get`メソッドを使用してベクタの要素にアクセスする +リスト8-4:添え字記法か`get`メソッドを使用してベクタの要素にアクセスする -ここでは2つのことに注目してください。 -1つ目は、3番目の要素を得るのに`2`という添え字の値を使用していることです。 -ベクタは番号で索引化されますが、その番号は0から始まります。 -2つ目は、3番目の要素を得る2つの方法とは、`&`と`[]`を使用して参照を得るものと、`get`メソッドに引数として添え字を渡して`Option<&T>`を得るものだということです。 +ここでいくつか注意があります。 +ベクタは0から始まる番号で添え字アクセスされるので、3番目の要素を得るのに`2`という添え字の値を使用しています。 +`&`と`[]`を使用することで、その添え字の値にある要素への参照が得られます。 +`get`メソッドに引数として添え字を渡して使用すると、`Option<&T>`が得られ、これは`match`で使用することができます。 -Rustのベクタには要素を参照する方法が2通りあるので、ベクタに含まれない要素の添え字を使おうとしたときのプログラムの振る舞いを選択できます。 -例として、ベクタに5つ要素があるとして、添え字100の要素にアクセスを試みた場合、プログラムがどうなるのか確認しましょう。 -リスト8-6に示します。 +Rustが要素を参照するためにこれらの2通りの方法を提供している理由は、存在する要素の範囲外の添え字の値を使おうとしたときのプログラムの振る舞いを選択できるようにするためです。 +例として、5要素のベクタがあるとして、それぞれの手法で添え字100の要素にアクセスを試みた場合、何が起こるのか確認しましょう。 +リスト8-5に示します。 ```rust,should_panic,panics -{{#rustdoc_include ../listings/ch08-common-collections/listing-08-06/src/main.rs:here}} +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-05/src/main.rs:here}} ``` -リスト8-6:5つの要素を含むベクタの添え字100の要素にアクセスしようとする +リスト8-5:5つの要素を含むベクタの添え字100の要素にアクセスしようとする `get`メソッドにベクタ外の添え字を渡すと、パニックすることなく`None`を返します。 @@ -276,27 +235,28 @@ When the program has a valid reference, the borrow checker enforces the ownership and borrowing rules (covered in Chapter 4) to ensure this reference and any other references to the contents of the vector remain valid. Recall the rule that states you can’t have mutable and immutable references in the same -scope. That rule applies in Listing 8-7, where we hold an immutable reference to -the first element in a vector and try to add an element to the end, which won’t -work if we also try to refer to that element later in the function: +scope. That rule applies in Listing 8-6, where we hold an immutable reference +to the first element in a vector and try to add an element to the end. This +program won’t work if we also try to refer to that element later in the +function: --> プログラムに有効な参照がある場合、借用チェッカー (borrow checker) は、(第4章で解説しましたが)所有権と借用規則を強制し、ベクタの中身へのこの参照や他のいかなる参照も有効であり続けることを保証してくれます。 同一スコープ上では、可変と不変な参照を同時には存在させられないというルールを思い出してください。 -このルールはリスト8-7でも適用されています。 -リスト8-7ではベクタの最初の要素への不変参照を保持しつつ、終端に要素を追加しようとしています。 -関数内のここ以降で、この要素(訳注:`first`のこと)を参照しようとすると失敗します。 +このルールはリスト8-6でも適用されています。 +リスト8-6ではベクタの最初の要素への不変参照を保持しつつ、終端に要素を追加しようとしています。 +このプログラムは、関数内のここ以降で、この要素(訳注:`first`のこと)を参照しようとすると失敗します。 ```rust,ignore,does_not_compile -{{#rustdoc_include ../listings/ch08-common-collections/listing-08-07/src/main.rs:here}} +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-06/src/main.rs:here}} ``` -リスト8-7:要素への参照を保持しつつ、ベクタに要素を追加しようとする +リスト8-6:要素への参照を保持しつつ、ベクタに要素を追加しようとする -リスト8-7のコードは、一見動きそうに見えるかもしれません。 +リスト8-6のコードは、一見動きそうに見えるかもしれません。 なぜ最初の要素への参照が、ベクタの終端への変更を気にかける必要があるのでしょうか? -このエラーはベクタが動作するしくみによるものです。 -新たな要素をベクタの終端に追加するとき、いまベクタのある場所に全要素を隣り合わせに配置するだけのスペースがないなら、新しいメモリを割り当て、古い要素を新しいスペースにコピーする必要があります。 +このエラーはベクタが動作するしくみによるものです: +ベクタはメモリ上に値同士を隣り合うように配置するため、新たな要素をベクタの終端に追加するとき、いまベクタが置かれている場所に全要素を隣り合わせに配置するだけのスペースがないなら、新しいメモリを割り当て、古い要素を新しいスペースにコピーする必要があります。 その場合、最初の要素を指す参照は、解放されたメモリを指すことになるでしょう。 借用規則がそのような状況に陥らないよう防いでくれるのです。 @@ -342,29 +303,29 @@ programs from ending up in that situation. ### ベクタ内の値を順に処理する -ベクタの要素に順番にアクセスしたいなら、添え字で1要素ごとにアクセスするのではなく、全要素を走査することができます。 -リスト8-8で`for`ループを使い、`i32`のベクタの各要素に対する不変な参照を得て、それらを表示する方法を示します。 +ベクタの要素に順番にアクセスするには、添え字で1要素ごとにアクセスするのではなく、全要素を走査することになるでしょう。 +リスト8-7で`for`ループを使い、`i32`のベクタの各要素に対する不変な参照を得て、それらを表示する方法を示します。 ```rust -{{#rustdoc_include ../listings/ch08-common-collections/listing-08-08/src/main.rs:here}} +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-07/src/main.rs:here}} ``` -リスト8-8:`for`ループで要素を走査し、ベクタの各要素を表示する +リスト8-7:`for`ループで要素を走査し、ベクタの各要素を表示する @@ -372,27 +333,40 @@ will add `50` to each element. リスト8-9の`for`ループでは各要素に`50`を足しています。 ```rust -{{#rustdoc_include ../listings/ch08-common-collections/listing-08-09/src/main.rs:here}} +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-08/src/main.rs:here}} ``` -リスト8-9:ベクタの要素への可変な参照を走査する +リスト8-8:ベクタの要素への可変な参照を走査する -可変参照が参照している値を変更するには、`+=`演算子を使用する前に、参照外し演算子(`*`)を使用して`i`の値にたどり着かないといけません。 +可変参照が参照している値を変更するには、`+=`演算子を使用する前に、`*`参照外し演算子を使用して`i`の値にたどり着かないといけません。 参照外し演算子については、第15章の[「参照外し演算子で値までポインタを追いかける」][deref]節でより詳しく扱います。 + + +借用チェッカーの規則のおかげで、ベクタを走査するのは不変であっても可変であっても安全です。 +もしリスト8-7やリスト8-8の`for`ループ本体の中で要素を挿入または削除しようとすると、リスト8-6のコードで発生したのと同じようなコンパイルエラーになるでしょう。 +`for`ループがベクタへの参照をつかんでいるために、それと同時にベクタ全体の変更が起こらないようになっています。 + @@ -400,92 +374,130 @@ section of Chapter 15. ### Enumを使って複数の型を保持する -この章の冒頭で、ベクタは同じ型の値しか保持できないと述べました。 -これは不便なこともあります。 +ベクタは同じ型の値しか保持できません。これは不便なこともあります。 異なる型の要素を保持する必要のあるユースケースは必ず存在します。 -幸運なことに、enumの列挙子は同じenumの型の中に定義されるので、ベクタに異なる型の要素を保持する必要が出たら、enumを定義して使用すればよいのです! +幸運なことに、enumの列挙子は同じenumの型の中に定義されるので、異なる型の要素を表現する単一の型が必要になったら、enumを定義して使用すればよいのです! 例えば、スプレッドシートのある行から値を得ることを考えます。 ここで、その行の中の列には、整数を含むもの、浮動小数点数を含むもの、文字列を含むものがあるとします。 列挙子ごとに異なる値の型を保持するenumが定義できます。 そして、このenumの列挙子は全て同じ型、つまりenumの型、と考えられるわけです。 -ですから、そのenumを保持するベクタを作成でき、結果的に異なる型を保持できるようになるわけです。 -リスト8-10でこれを実演しています。 +ですから、そのenumを保持するためのベクタを作成でき、結果的に異なる型を保持できるようになるわけです。 +リスト8-9でこれを実演しています。 ```rust -{{#rustdoc_include ../listings/ch08-common-collections/listing-08-10/src/main.rs:here}} +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-09/src/main.rs:here}} ``` -リスト8-10:`enum`を定義して、一つのベクタに異なる型の値を保持する +リスト8-9:`enum`を定義して、一つのベクタに異なる型の値を保持する 個々の要素を格納するのにヒープ上で必要となるメモリの量を正確に把握するめに、Rustコンパイラはコンパイル時にベクタに入る型を知る必要があります。 -また、このベクタではどんな型が許容されるのか明示できるという副次的な利点があります。 +また、このベクタではどんな型が許容されるのか明示しなくてはなりません。 もしRustが、ベクタにどんな型でも保持できることを許していたら、ベクタの要素に対して行われる処理に対して、いくつかの型がエラーを引き起こすかもしれません。 enumに加えて`match`式を使うことで、第6章で説明したとおり、あらゆるケースが処理できることを、Rustがコンパイル時に保証することになります。 -プログラムを書いている時点で、プログラムが実行時に取得し、ベクタに格納し得る全ての型を網羅できない場合には、このenumを使ったテクニックはうまくいかないでしょう。 +プログラムが実行時に取得し、ベクタに格納し得る全ての型を網羅できない場合には、このenumを使ったテクニックはうまくいかないでしょう。 代わりにトレイトオブジェクトを使用できます。 こちらは第17章で取り上げます。 これまでにベクタの代表的な使い方をいくつか紹介しました。 標準ライブラリで`Vec`に定義されている多くの有益なメソッドについて、[APIドキュメント][vec-api]を必ず確認するようにしてください。 例えば、`push`に加えて、`pop`というメソッドがあり、これは最後の要素を削除して返します。 + + + +### ベクタをドロップすれば、要素もドロップする + + + +他のあらゆる`struct`(構造体)と同様に、ベクタもスコープを抜ければ解放されます。 +その様子をリスト8-10に示します。 + +```rust +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-10/src/main.rs:here}} +``` + + + +リスト8-10:ベクタとその要素がドロップされる箇所を示す + + + +ベクタがドロップされると、その中身もドロップされます。 +つまり、保持されていた整数値が片付けられるということです。 +借用チェッカーは、ベクタの内容へのいかなる参照も、ベクタ自体が有効な間のみ使用されることを保証します。 + + + それでは次のコレクション型である`String`に移りましょう! [data-types]: ch03-02-data-types.html#データ型 -[nomicon]: ../nomicon/vec.html +[nomicon]: ../nomicon/vec/vec.html [vec-api]: ../std/vec/struct.Vec.html [deref]: ch15-02-deref.html#参照外し演算子で値までポインタを追いかける diff --git a/src/ch08-02-strings.md b/src/ch08-02-strings.md index c04e598c2..dad5d6164 100644 --- a/src/ch08-02-strings.md +++ b/src/ch08-02-strings.md @@ -7,20 +7,20 @@ 第4章で文字列について語りましたが、今度はより掘り下げていきましょう。新参者のRustaceanは、 -3つの概念の組み合わせにより、文字列でよく行き詰まります: Rustのありうるエラーを晒す性質、 +3つの理由の組み合わせにより、文字列でよく行き詰まります: Rustのありうるエラーを晒す性質、 多くのプログラマが思っている以上に文字列が複雑なデータ構造であること、そしてUTF-8です。 これらの要因が、他のプログラミング言語から移ってきた場合、一見困難に見えるように絡み合うわけです。 -コレクションの文脈で文字列を議論することは、有用なことです。なぜなら、文字列はテキストとして解釈された時に有用になる機能を提供するメソッドと、 -バイトのコレクションで実装されているからです。この節では、生成、更新、読み込みのような全コレクションが持つ`String`の処理について語ります。 +文字列は、バイトのコレクションに、そのバイトをテキストとして解釈するときに便利な機能を提供するメソッドを足したものとして実装されているため、コレクションの文脈で文字列を議論していきます。 +この節では、生成、更新、読み込みのような全コレクションが持つ`String`の処理について語ります。 また、`String`が他のコレクションと異なる点についても議論します。具体的には、人間とコンピュータが`String`データを解釈する方法の差異により、 `String`に添え字アクセスする方法がどう複雑なのかということです。 @@ -45,48 +45,30 @@ We’ll first define what we mean by the term *string*. Rust has only one string type in the core language, which is the string slice `str` that is usually seen in its borrowed form `&str`. In Chapter 4, we talked about *string slices*, which are references to some UTF-8 encoded string data stored elsewhere. String -literals, for example, are stored in the binary output of the program and are -therefore string slices. +literals, for example, are stored in the program’s binary and are therefore +string slices. --> まずは、*文字列*という用語の意味を定義しましょう。Rustには、言語の核として1種類しか文字列型が存在しません。 文字列スライスの`str`で、通常借用された形態`&str`で見かけます。第4章で、*文字列スライス*について語りました。 これは、別の場所に格納されたUTF-8エンコードされた文字列データへの参照です。例えば、文字列リテラルは、 -プログラムのバイナリ出力に格納されるので、文字列スライスになります。 +プログラムのバイナリに格納されるので、文字列スライスになります。 -`String`型は、言語の核として組み込まれるのではなく、Rustの標準ライブラリで提供されますが、伸長可能、 -可変、所有権のあるUTF-8エンコードされた文字列型です。RustaceanがRustにおいて「文字列」を指したら、 -どちらかではなく、`String`と文字列スライスの`&str`のことを通常意味します。この節は、大方、 +`String`型は、言語の核として組み込まれるのではなく、Rustの標準ライブラリによって提供されますが、伸長可能、 +可変、所有権のあるUTF-8エンコードされた文字列型です。RustaceanがRustにおいて「文字列」と言うとき、`String`型または文字列スライスの`&str`型のいずれかを指しているかもしれません。この節は、大方、 `String`についてですが、どちらの型もRustの標準ライブラリで重宝されており、 どちらもUTF-8エンコードされています。 - - -また、Rustの標準ライブラリには、他の文字列型も含まれています。`OsString`、`OsStr`、`CString`、`CStr`などです。 -ライブラリクレートにより、文字列データを格納する選択肢はさらに増えます。 -それらの名前が全て`String`か`Str`で終わっているのがわかりますか?所有権ありと借用されたバージョンを指しているのです。 -ちょうど以前見かけた`String`と`&str`のようですね。例えば、これらの文字列型は、異なるエンコード方法でテキストを格納していたり、 -メモリ上の表現が異なったりします。この章では、これらの他の種類の文字列については議論しません; -使用方法やどれが最適かについては、APIドキュメントを参照してください。 - @@ -95,15 +77,18 @@ API documentation for more about how to use them and when each is appropriate. -`Vec`で使用可能な処理の多くが`String`でも使用できます。文字列を生成する`new`関数から始めましょうか。 +`String`は実際のところ、いくつか追加の保障と制限と機能を持つバイトのベクタのラッパーとして実装されているので、`Vec`で使用可能な操作の多くが`String`でも使用できます。 +`Vec`と`String`で同様に機能する関数の例としては、それぞれのインスタンスを作成する`new`関数があります。 リスト8-11に示したようにですね。 ```rust -let mut s = String::new(); +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-11/src/main.rs:here}} ``` 文字列は、非常に多くのものに使用されるので、多くの異なる一般的なAPIを使用でき、たくさんの選択肢があるわけです。 冗長に思われるものもありますが、適材適所です!今回の場合、`String::from`と`to_string`は全く同じことをします。 -従って、どちらを選ぶかは、スタイル次第です。 +従って、どちらを選ぶかは、スタイルと可読性次第です。 @@ -243,8 +214,7 @@ as shown in Listing 8-15. リスト8-15の通りです。 ```rust -let mut s = String::from("foo"); -s.push_str("bar"); +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-15/src/main.rs:here}} ``` この2行の後、`s`は`foobar`を含むことになります。`push_str`メソッドは、必ずしも引数の所有権を得なくていいので、 -文字列スライスを取ります。例えば、リスト8-16のコードは、中身を`s1`に追加した後、 -`s2`を使えなかったら残念だということを示しています。 +文字列スライスを取ります。例えば、リスト8-16のコードで、中身を`s1`に追加した後も`s2`を使いたいとします。 ```rust -let mut s1 = String::from("foo"); -let s2 = "bar"; -s1.push_str(s2); -println!("s2 is {}", s2); +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-16/src/main.rs:here}} ``` `push`メソッドは、1文字を引数として取り、`String`に追加します。リスト8-15は、 -`push`メソッドで*l*を`String`に追加するコードを呈示しています。 +`push`メソッドで“l”を`String`に追加しています。 ```rust -let mut s = String::from("lo"); -s.push('l'); +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-17/src/main.rs:here}} ``` -このコードの結果、`s`は`lol`を含むことになるでしょう。 +この結果、`s`は`lol`を含むことになるでしょう。 > 編者注: `lol`は`laughing out loud`(大笑いする)の頭文字からできたスラングです。 > 日本語の`www`みたいなものですね。 @@ -324,25 +289,15 @@ As a result of this code, `s` will contain `lol`. #### `+`演算子、または`format!`マクロで連結 -2つのすでにある文字列を組み合わせたくなることがよくあります。リスト8-18に示したように、 -一つ目の方法は、`+`演算子を使用することです。 +2つのすでにある文字列を組み合わせたくなることがよくあります。 +これを行うための方法の一つは、リスト8-18に示したように、`+`演算子を使用することです。 - - -```rust -let s1 = String::from("Hello, "); -let s2 = String::from("world!"); -let s3 = s1 + &s2; // s1はムーブされ、もう使用できないことに注意 +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-18/src/main.rs:here}} ``` -このコードの結果、`s3`という文字列は、`Hello, world!`を含むことになるでしょう。 +`s3`という文字列は、`Hello, world!`を含むことになるでしょう。 追記の後、`s1`がもう有効でなくなった理由と、`s2`への参照を使用した理由は、 `+`演算子を使用した時に呼ばれるメソッドのシグニチャと関係があります。`+`演算子は、`add`メソッドを使用し、 そのシグニチャは以下のような感じです: @@ -370,28 +325,28 @@ fn add(self, s: &str) -> String { ``` -これは、標準ライブラリにあるシグニチャそのものではありません: 標準ライブラリでは、`add`はジェネリクスで定義されています。 -ここでは、ジェネリックな型を具体的な型に置き換えた`add`のシグニチャを見ており、これは、 -このメソッドを`String`値とともに呼び出した時に起こることです。ジェネリクスについては、第10章で議論します。 +標準ライブラリでは、`add`はジェネリクスと関連型を使用して定義されているのがわかるでしょう。 +ここでは具体的な型で置き換えていますが、これはこのメソッドを`String`値とともに呼び出した時に起こることです。 +ジェネリクスについては、第10章で議論します。 このシグニチャが、`+`演算子の巧妙な部分を理解するのに必要な手がかりになるのです。 -まず、`s2`には`&`がついてます。つまり、`add`関数の`s`引数のために最初の文字列に2番目の文字列の参照を追加するということです: +まず、`s2`には`&`がついてます。つまり、最初の文字列に2番目の文字列の参照を追加するということです。 +これは`add`関数の`s`引数のためのものです: `String`には`&str`を追加することしかできません。要するに2つの`String`値を追加することはできないのです。 でも待ってください。`add`の第2引数で指定されているように、`&s2`の型は、`&str`ではなく、 `&String`ではないですか。では、なぜ、リスト8-18は、コンパイルできるのでしょうか? @@ -413,12 +368,12 @@ after this operation. 2番目に、シグニチャから`add`は`self`の所有権をもらうことがわかります。`self`には`&`がついてい*ない*からです。 @@ -428,47 +383,39 @@ than copying. たくさんのコピーをしているように見えますが、違います; 実装は、コピーよりも効率的です。 複数の文字列を連結する必要が出ると、`+`演算子の振る舞いは扱いにくくなります: ```rust -let s1 = String::from("tic"); -let s2 = String::from("tac"); -let s3 = String::from("toe"); - -let s = s1 + "-" + &s2 + "-" + &s3; +{{#rustdoc_include ../listings/ch08-common-collections/no-listing-01-concat-multiple-strings/src/main.rs:here}} ``` ここで、`s`は`tic-tac-toe`になるでしょう。`+`と`"`文字のせいで何が起きているのかわかりにくいです。 -もっと複雑な文字列の連結には、`format!`マクロを使用することができます: +もっと複雑な文字列の連結には、代わりに`format!`マクロを使用することができます: ```rust -let s1 = String::from("tic"); -let s2 = String::from("tac"); -let s3 = String::from("toe"); - -let s = format!("{}-{}-{}", s1, s2, s3); +{{#rustdoc_include ../listings/ch08-common-collections/no-listing-02-format/src/main.rs:here}} ``` -このコードでも、`s`は`tic-tac-toe`になります。`format!`マクロは、`println!`と同様の動作をしますが、 -出力をスクリーンに行う代わりに、中身を`String`で返すのです。`format!`を使用したコードの方がはるかに読みやすく、 -引数の所有権を奪いません。 +このコードでも、`s`は`tic-tac-toe`になります。`format!`マクロは、`println!`と似た動作をしますが、 +出力をスクリーンに行う代わりに、中身を`String`で返すのです。`format!`を使用したコードの方がはるかに読みやすく、`format!` マクロによって生成されたコードはは参照を使用するので、この呼び出しは引数の所有権を奪いません。 この場合、`len`は4になり、これは、文字列"Hola"を保持するベクタの長さが4バイトであることを意味します。 -これらの各文字は、UTF-8でエンコードすると、1バイトになるのです。しかし、以下の行ではどうでしょうか? -(この文字列は大文字のキリル文字Zeで始まり、アラビア数字の3では始まっていないことに注意してください) +これらの各文字は、UTF-8でエンコードすると、1バイトになるのです。しかし、次の行にはびっくりするかもしれません。 +(この文字列は大文字のキリル文字ゼーで始まり、数字の3では始まっていないことに注意してください) ```rust -let len = String::from("Здравствуйте").len(); +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-14/src/main.rs:russian}} ``` -文字列の長さはと問われたら、あなたは12と答えるかもしれません。ところが、Rustの答えは、24です: -“Здравствуйте”をUTF-8でエンコードすると、この長さになります。各Unicodeスカラー値は、2バイトの領域を取るからです。 +文字列の長さはと問われたら、あなたは12と答えるかもしれません。実際には、Rustの答えは、24です: +“Здравствуйте”をUTF-8でエンコードすると、この長さになります。この文字列に含まれる各Unicodeスカラー値は、2バイトの領域を取るからです。 それ故に、文字列のバイトの添え字は、必ずしも有効なUnicodeのスカラー値とは相互に関係しないのです。 デモ用に、こんな非合法なRustコードを考えてください: -```rust,ignore +```rust,ignore,does_not_compile let hello = "Здравствуйте"; let answer = &hello[0]; ``` -`answer`の値は何になるべきでしょうか?最初の文字の`З`になるべきでしょうか?UTF-8エンコードされた時、 -`З`の最初のバイトは`208`、2番目は`151`になるので、`answer`は実際、`208`になるべきですが、 +`answer`の値は、最初の文字の`З`にはならないことを知っているでしょう。UTF-8エンコードされた時、 +`З`の最初のバイトは`208`、2番目は`151`になるので、`answer`は実際には`208`になりそうですが、 `208`は単独では有効な文字ではありません。この文字列の最初の文字を求めている場合、`208`を返すことは、 ユーザの望んでいるものではないでしょう; しかしながら、Rustには、バイト添え字0の位置には、そのデータしかないのです。 文字列がラテン文字のみを含む場合でも、ユーザは一般的にバイト値が返ることを望みません: `&"hello"[0]`がバイト値を返す有効なコードだったら、`h`ではなく、`104`を返すでしょう。 -予期しない値を返し、すぐには判明しないバグを引き起こさないために、Rustはこのコードを全くコンパイルせず、 + + +答えは、予期しない値を返し、すぐには判明しないバグを引き起こさないために、Rustはこのコードを全くコンパイルせず、 開発過程の早い段階で誤解を防いでくれるのです。 文字列に添え字アクセスするのは、しばしば悪い考えです。文字列添え字処理の戻り値の型が明瞭ではないからです: バイト値、文字、書記素クラスタ、あるいは文字列スライスにもなります。故に、文字列スライスを生成するのに、 -添え字を使う必要が本当に出た場合にコンパイラは、もっと特定するよう求めてきます。添え字アクセスを特定し、 -文字列スライスが欲しいと示唆するためには、`[]`で1つの数値により添え字アクセスするのではなく、 +添え字を使う必要が本当に出た場合にコンパイラは、もっと特定するよう求めてきます。 + + + +`[]`で1つの数値により添え字アクセスするのではなく、 範囲とともに`[]`を使って、特定のバイトを含む文字列スライスを作ることができます: ```rust @@ -714,16 +659,16 @@ Earlier, we mentioned that each of these characters was 2 bytes, which means `s`は`Зд`になります。 -`&hello[0..1]`と使用したら、何が起きるでしょうか?答え: Rustはベクタの非合法な添え字にアクセスしたかのように、 -実行時にパニックするでしょう: +`&hello[0..1]`のようにして、文字を構成するバイトの一部のみをスライスしようとすると、 +Rustはベクタの非合法な添え字にアクセスしたかのように実行時にパニックするでしょう: -```text -thread 'main' panicked at 'byte index 1 is not a char boundary; it is inside 'З' (bytes 0..2) of `Здравствуйте`', src/libcore/str/mod.rs:2188:4 -('main'スレッドは「バイト添え字1は文字の境界ではありません; `Здравствуйте`の'З'(バイト番号0から2)の中です」でパニックしました) +```console +{{#include ../listings/ch08-common-collections/output-only-01-not-char-boundary/output.txt}} ``` -もし、個々のUnicodeスカラー値に対して処理を行う必要があったら、最適な方法は`chars`メソッドを使用するものです。 -“नमस्ते”に対して`chars`を呼び出したら、分解して6つの`char`型の値を返すので、各要素にアクセスするには、 +文字列の部分に対して操作を行うための最良の方法は、文字に対して操作したいのかバイトに対して操作したいのかを明示することです。 +個々のUnicodeスカラー値に対しては、`chars`メソッドを使用してください。 +“Зд”に対して`chars`を呼び出したら、分解して2つの`char`型の値を返すので、各要素にアクセスするには、 その結果を走査すればいいわけです: ```rust -for c in "नमस्ते".chars() { - println!("{}", c); +for c in "Зд".chars() { + println!("{c}"); } ``` @@ -769,39 +715,34 @@ This code will print the following: このコードは、以下のように出力します: ```text -न -म -स -् -त -े +З +д ``` -`bytes`メソッドは、各バイトをそのまま返すので、最適になることもあるかもしれません: +あるいは、`bytes`メソッドは各バイトをそのまま返すので、ドメインによってはこちらが適切かもしれません: ```rust -for b in "नमस्ते".bytes() { - println!("{}", b); +for b in "Зд".bytes() { + println!("{b}"); } ``` -このコードは、`String`をなす18バイトを出力します: +このコードは、この文字列をなす4バイトを出力します: ```text -224 -164 -// --snip-- -165 -135 +208 +151 +208 +180 ``` -書記素クラスタを文字列から得る方法は複雑なので、この機能は標準ライブラリでは提供されていません。 +デーヴァナーガリー文字を含むような文字列から書記素クラスタを得る方法は複雑なので、この機能は標準ライブラリでは提供されていません。 この機能が必要なら、[crates.io](https://crates.io)でクレートを入手可能です。 + +一方で良い面としては、こうした複雑な状況に正しく対処するために、標準ライブラリが`String`と`&str`型の上に構築された多数の機能を提供していることです。 +文字列内の検索のための`contains`や、文字列の一部を別の文字列で置換するための`replace`などの便利なメソッドについて、ドキュメントを確認してみてください。 + diff --git a/src/ch08-03-hash-maps.md b/src/ch08-03-hash-maps.md index f468130b9..23d8bbc41 100644 --- a/src/ch08-03-hash-maps.md +++ b/src/ch08-03-hash-maps.md @@ -1,25 +1,25 @@ ## キーとそれに紐づいた値をハッシュマップに格納する 一般的なコレクションのトリを飾るのは、*ハッシュマップ*です。型`HashMap`は、 -`K`型のキーと`V`型の値の対応関係を保持します。これを*ハッシュ関数*を介して行います。 +`K`型のキーと`V`型の値の対応関係を*ハッシュ関数*を使用して保持します。 ハッシュ関数は、キーと値のメモリ配置方法を決めるものです。多くのプログラミング言語でもこの種のデータ構造はサポートされていますが、 -しばしば名前が違います。hash、map、object、ハッシュテーブル、連想配列など、枚挙に(いとま)はありません。 +しばしば名前が違います。hash、map、object、ハッシュテーブル、辞書、連想配列など、枚挙に(いとま)はありません。 -空のハッシュマップを`new`で作り、要素を`insert`で追加することができます。リスト8-20では、 -名前がブルーとイエローの2チームのスコアを追いかけています。ブルーチームは10点から、イエローチームは50点から始まります。 +空のハッシュマップを作成する方法のひとつは`new`を使用する方法で、その後要素を`insert`で追加することができます。 +リスト8-20では、名前が*ブルー*と*イエロー*の2チームのスコアを追いかけています。 +ブルーチームは10点から、イエローチームは50点から始まります。 ```rust -use std::collections::HashMap; - -let mut scores = HashMap::new(); - -scores.insert(String::from("Blue"), 10); -scores.insert(String::from("Yellow"), 50); +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-20/src/main.rs:here}} ``` 最初に標準ライブラリのコレクション部分から`HashMap`を`use`する必要があることに注意してください。 @@ -87,57 +83,74 @@ standard library; there's no built-in macro to construct them, for example. ベクタと全く同様に、ハッシュマップはデータをヒープに保持します。この`HashMap`はキーが`String`型、 -値は`i32`型です。ベクタのように、ハッシュマップは均質です: キーは全て同じ型でなければならず、 +値は`i32`型です。ベクタのように、ハッシュマップは均質です: すべてのキーは互いに同じ型でなければならず、 値も全て同じ型でなければなりません。 -ハッシュマップを生成する別の方法は、タプルのベクタに対して`collect`メソッドを使用するものです。 -ここで、各タプルは、キーと値から構成されています。`collect`メソッドはいろんなコレクション型にデータをまとめ上げ、 -そこには`HashMap`も含まれています。例として、チーム名と初期スコアが別々のベクタに含まれていたら、 -`zip`メソッドを使ってタプルのベクタを作り上げることができ、そこでは「ブルー」は10とペアになるなどします。 -リスト8-21に示したように、それから`collect`メソッドを使って、そのタプルのベクタをハッシュマップに変換することができるわけです。 +### ハッシュマップの値にアクセスする -```rust -use std::collections::HashMap; + -let teams = vec![String::from("Blue"), String::from("Yellow")]; -let initial_scores = vec![10, 50]; +リスト8-21に示したように、キーを`get`メソッドに提供することで、ハッシュマップから値を取り出すことができます。 -let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect(); +```rust +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-21/src/main.rs:here}} ``` + +リスト8-21: ハッシュマップに保持されたブルーチームのスコアにアクセスする + + + +ここで、`score`はブルーチームに紐づけられた値になり、結果は`10`となるでしょう。 +`get`メソッドは`Option<&V>`を返します; +キーに対応する値がハッシュマップになかったら、`get`は`None`を返すでしょう。 +このプログラムはこの`Option`に対して、`Option<&i32>`ではなく`Option`を得るために`copied`を呼び出し、 +その後、`scores`がそのキーに対応するエントリを持たない場合は`score`を0に設定するために、`unwrap_or`を呼び出して対処します。 + + -リスト8-21: チームのリストとスコアのリストからハッシュマップを作る +ベクタのように、`for`ループでハッシュマップのキーと値のペアを走査することができます: + +```rust +{{#rustdoc_include ../listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/src/main.rs:here}} +``` -ここでは、`HashMap<_, _>`という型注釈が必要になります。なぜなら、いろんなデータ構造に`まとめ上げる`ことができ、 -コンパイラは指定しない限り、どれを所望なのかわからないからです。ところが、キーと値の型引数については、 -アンダースコアを使用しており、コンパイラはベクタのデータ型に基づいてハッシュマップが含む型を推論することができるのです。 +このコードは、各ペアを任意の順番で出力します: + +```text +Yellow: 50 +Blue: 10 +``` 値への参照をハッシュマップに挿入したら、値はハッシュマップにムーブされません。参照が指している値は、 最低でもハッシュマップが有効な間は、有効でなければなりません。これらの問題について詳細には、 -第10章の「ライフタイムで参照を有効化する」節で語ります。 - - - -### ハッシュマップの値にアクセスする - - - -リスト8-23に示したように、キーを`get`メソッドに提供することで、ハッシュマップから値を取り出すことができます。 - -```rust -use std::collections::HashMap; - -let mut scores = HashMap::new(); - -scores.insert(String::from("Blue"), 10); -scores.insert(String::from("Yellow"), 50); - -let team_name = String::from("Blue"); -let score = scores.get(&team_name); -``` - - - -リスト8-23: ハッシュマップに保持されたブルーチームのスコアにアクセスする +第10章の[「ライフタイムで参照を有効化する」][validating-references-with-lifetimes]節で語ります。 - -ここで、`score`はブルーチームに紐づけられた値になり、結果は`Some(&10)`となるでしょう。 -結果は`Some`に包まれます。というのも、`get`は`Option<&V>`を返すからです; キーに対応する値がハッシュマップになかったら、 -`get`は`None`を返すでしょう。プログラムは、この`Option`を第6章で講義した方法のどれかで扱う必要があるでしょう。 - - -ベクタのように、`for`ループでハッシュマップのキーと値のペアを走査することができます: - -```rust -use std::collections::HashMap; - -let mut scores = HashMap::new(); - -scores.insert(String::from("Blue"), 10); -scores.insert(String::from("Yellow"), 50); - -for (key, value) in &scores { - println!("{}: {}", key, value); -} -``` +### ハッシュマップを更新する -このコードは、各ペアを任意の順番で出力します: - -```text -Yellow: 50 -Blue: 10 -``` +キーと値のペアの数は伸長可能ですが、それぞれの一意なキーには同時に1つの値しか紐づけることができません(ただし逆は可能です: +例えば、`scores`ハッシュマップ内にブルーチームとイエローチームはともに値10を保存することができます)。 -### ハッシュマップを更新する - - - -キーと値の数は伸長可能なものの、各キーには1回に1つの値しか紐づけることができません。 ハッシュマップ内のデータを変えたい時は、すでにキーに値が紐づいている場合の扱い方を決めなければなりません。 古い値を新しい値で置き換えて、古い値を完全に無視することもできます。古い値を保持して、 新しい値を無視し、キーにまだ値が*ない*場合に新しい値を追加するだけにすることもできます。 @@ -302,32 +239,25 @@ of these! キーと値をハッシュマップに挿入し、同じキーを異なる値で挿入したら、そのキーに紐づけられている値は置換されます。 -リスト8-24のコードは、`insert`を二度呼んでいるものの、ハッシュマップには一つのキーと値の組しか含まれません。 +リスト8-23のコードは、`insert`を二度呼んでいるものの、ハッシュマップには一つのキーと値の組しか含まれません。 なぜなら、ブルーチームキーに対する値を2回とも挿入しているからです。 ```rust -use std::collections::HashMap; - -let mut scores = HashMap::new(); - -scores.insert(String::from("Blue"), 10); -scores.insert(String::from("Blue"), 25); - -println!("{:?}", scores); +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-23/src/main.rs:here}} ``` -リスト8-24: 特定のキーで保持された値を置き換える +リスト8-23: 特定のキーで保持された値を置き換える + + -#### キーに値がなかった時のみ値を挿入する +#### キーが存在しない場合のみキーと値を追加する + +特定のキーがハッシュマップ内に値とともに存在しているか確認して、以下のアクションを取ることは一般的でしょう: +キーがハッシュマップに存在する場合は、既存の値はそのままにします。 +キーが存在しない場合は、そのキーとそれに対応する値を挿入します。 + + -特定のキーに値があるか確認することは一般的であり、存在しない時に値を挿入することも一般的です。 ハッシュマップには、これを行う`entry`と呼ばれる特別なAPIがあり、これは、引数としてチェックしたいキーを取ります。 この`entry`メソッドの戻り値は、`Entry`と呼ばれるenumであり、これは存在したりしなかったりする可能性のある値を表します。 イエローチームに対するキーに値が紐づけられているか否か確認したくなったとしましょう。存在しなかったら、 -50という値を挿入したく、ブルーチームに対しても同様です。`entry`APIを使用すれば、コードはリスト8-25のようになります。 +50という値を挿入したく、ブルーチームに対しても同様です。`entry`APIを使用すれば、コードはリスト8-24のようになります。 ```rust -use std::collections::HashMap; - -let mut scores = HashMap::new(); -scores.insert(String::from("Blue"), 10); - -scores.entry(String::from("Yellow")).or_insert(50); -scores.entry(String::from("Blue")).or_insert(50); - -println!("{:?}", scores); +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-24/src/main.rs:here}} ``` -リスト8-25: `entry`メソッドを使ってキーに値がない場合だけ挿入する +リスト8-24: `entry`メソッドを使ってキーに値がない場合だけ挿入する `Entry`上の`or_insert`メソッドは、対応する`Entry`キーが存在した時にそのキーに対する値への可変参照を返すために定義されており、 @@ -391,14 +326,14 @@ logic ourselves, and in addition, plays more nicely with the borrow checker. そのロジックを自分で書くよりもはるかに綺麗な上に、borrow checkerとも親和性が高くなります。 -リスト8-25のコードを実行すると、`{"Yellow": 50, "Blue": 10}`と出力するでしょう。 +リスト8-24のコードを実行すると、`{"Yellow": 50, "Blue": 10}`と出力するでしょう。 最初の`entry`呼び出しは、まだイエローチームに対する値がないので、値50でイエローチームのキーを挿入します。 `entry`の2回目の呼び出しはハッシュマップを変更しません。なぜなら、ブルーチームには既に10という値があるからです。 @@ -410,83 +345,88 @@ value 10. ハッシュマップの別の一般的なユースケースは、キーの値を探し、古い値に基づいてそれを更新することです。 -例えば、リスト8-26は、各単語があるテキストに何回出現するかを数え上げるコードを示しています。 +例えば、リスト8-25は、各単語があるテキストに何回出現するかを数え上げるコードを示しています。 キーに単語を入れたハッシュマップを使用し、その単語を何回見かけたか追いかけるために値を増やします。 -ある単語を見かけたのが最初だったら、まず0という値を挿入します: +ある単語を見かけたのが最初だったら、まず0という値を挿入します。 ```rust -use std::collections::HashMap; - -let text = "hello world wonderful world"; - -let mut map = HashMap::new(); - -for word in text.split_whitespace() { - let count = map.entry(word).or_insert(0); - *count += 1; -} - -println!("{:?}", map); +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-25/src/main.rs:here}} ``` -リスト8-26: 単語とカウントを保持するハッシュマップを使って単語の出現数をカウントする +リスト8-25: 単語とカウントを保持するハッシュマップを使って単語の出現数をカウントする section that +iterating over a hash map happens in an arbitrary order. --> このコードは、`{"world": 2, "hello": 1, "wonderful": 1}`と出力するでしょう。 -`or_insert`関数は実際、このキーに対する値への可変参照(`&mut V`)を返すのです。 +同じキー/値ペアが、異なる順で印字されるかもしれません: +[「ハッシュマップの値にアクセスする」][access]の節で説明した、 +ハッシュマップの走査は任意の順で起こるということを思い出してください。 + + + +`split_whitespace`メソッドは、`text`の値から、ホワイトスペースによって区切られた部分スライスを走査するイテレータを返します。 +`or_insert`関数は、指定されたキーに対する値への可変参照(`&mut V`)を返すのです。 ここでその可変参照を`count`変数に保持しているので、その値に代入するには、 まずアスタリスク(`*`)で`count`を参照外ししなければならないのです。この可変参照は、 `for`ループの終端でスコープを抜けるので、これらの変更は全て安全であり、借用規則により許可されるのです。 ### ハッシュ関数 -標準では、`HashMap`はサービス拒否(DoS)アタックに対して抵抗を示す暗号学的に安全なハッシュ関数を使用します。 +`HashMap`はデフォルトでは、ハッシュテーブルに関するサービス拒否(DoS)攻撃に対する耐性を提供する、*SipHash*と呼ばれるハッシュ関数を使用します[^siphash]。 これは、利用可能な最速のハッシュアルゴリズムではありませんが、パフォーマンスの欠落と引き換えに安全性を得るというトレードオフは、 価値があります。自分のコードをプロファイリングして、自分の目的では標準のハッシュ関数は遅すぎると判明したら、 -異なる*hasher*を指定することで別の関数に切り替えることができます。hasherとは、 +異なるhasherを指定することで別の関数に切り替えることができます。*hasher*とは、 `BuildHasher`トレイトを実装する型のことです。トレイトについてとその実装方法については、第10章で語ります。 -必ずしも独自のhasherを1から作り上げる必要はありません; [crates.io](https://crates.io)には、 +必ずしも独自のhasherを1から作り上げる必要はありません; [crates.io](https://crates.io/)には、 他のRustユーザによって共有された多くの一般的なハッシュアルゴリズムを実装したhasherを提供するライブラリがあります。 +[^siphash]: [https://en.wikipedia.org/wiki/SipHash](https://en.wikipedia.org/wiki/SipHash) + @@ -503,21 +443,21 @@ some exercises you should now be equipped to solve: 多くの機能を提供してくれるでしょう。今なら解決可能なはずの練習問題を用意しました: -* 整数のリストが与えられ、ベクタを使ってmean(平均値)、median(ソートされた時に真ん中に来る値)、 +* 整数のリストが与えられ、ベクタを使ってmedian(ソートされた時に真ん中に来る値)、 mode(最も頻繁に出現する値; ハッシュマップがここでは有効活用できるでしょう)を返してください。 * 文字列をピッグ・ラテン(`訳注`: 英語の言葉遊びの一つ)に変換してください。各単語の最初の子音は、 単語の終端に移り、"ay"が足されます。従って、"first"は"irst-fay"になります。ただし、 @@ -535,9 +475,19 @@ and hash maps have that will be helpful for these exercises! 標準ライブラリのAPIドキュメントには、この練習問題に有用な、ベクタ、文字列、ハッシュマップのメソッドが解説されています。 + +処理が失敗することもあるような、より複雑なプログラムに入り込んできています。 +ということは、エラーの処理法について議論するのにぴったりということです。次はそれをします! + + -処理が失敗することもあるような、より複雑なプログラムに入り込んできています; ということは、 -エラーの処理法について議論するのにぴったりということです。次はそれをします! +[validating-references-with-lifetimes]: +ch10-03-lifetime-syntax.html#ライフタイムで参照を検証する +[access]: #ハッシュマップの値にアクセスする From 0f629e71976ff8885797451abe08bbf42cb23ded Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:04 +0900 Subject: [PATCH 10/22] =?UTF-8?q?ch09=20=E3=82=A8=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E5=87=A6=E7=90=86=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-09-01/Cargo.toml | 3 +- .../listing-09-01/output.txt | 7 +- .../listing-09-03/Cargo.toml | 3 +- .../listing-09-03/src/main.rs | 2 +- .../listing-09-04/Cargo.toml | 3 +- .../listing-09-04/output.txt | 7 +- .../listing-09-04/src/main.rs | 5 +- .../listing-09-05/Cargo.toml | 3 +- .../listing-09-05/src/main.rs | 8 +- .../listing-09-06/Cargo.toml | 3 +- .../listing-09-06/src/main.rs | 13 +- .../listing-09-07/Cargo.toml | 3 +- .../listing-09-07/src/main.rs | 11 +- .../listing-09-08/Cargo.toml | 3 +- .../listing-09-08/src/main.rs | 9 +- .../listing-09-09/Cargo.toml | 3 +- .../listing-09-10/Cargo.lock | 83 +- .../listing-09-10/Cargo.toml | 6 +- .../listing-09-10/output.txt | 18 + .../listing-09-10/src/main.rs | 54 +- .../Cargo.lock | 3 +- .../Cargo.toml | 3 +- .../listing-09-11/src/main.rs | 15 + .../Cargo.lock | 0 .../Cargo.toml | 3 +- .../src/main.rs | 2 +- .../listing-09-13/Cargo.lock | 75 ++ .../listing-09-13/Cargo.toml | 7 + .../listing-09-13/src/main.rs | 56 + .../no-listing-01-panic/Cargo.toml | 3 +- .../no-listing-01-panic/output.txt | 7 +- .../no-listing-01-panic/src/main.rs | 1 + .../output.txt | 19 - .../src/main.rs | 7 - .../no-listing-03-closures/Cargo.lock | 6 - .../no-listing-03-closures/src/main.rs | 14 - .../no-listing-04-unwrap/Cargo.toml | 3 +- .../no-listing-04-unwrap/src/main.rs | 2 +- .../no-listing-05-expect/Cargo.toml | 3 +- .../no-listing-05-expect/src/main.rs | 4 +- .../Cargo.lock | 6 - .../Cargo.toml | 7 - .../output.txt | 20 - .../src/main.rs | 5 - .../Cargo.toml | 7 - .../Cargo.toml | 3 +- .../src/main.rs | 5 +- .../Cargo.lock | 84 +- .../Cargo.toml | 5 +- .../src/main.rs | 2 +- src/SUMMARY.md | 2 +- src/ch09-00-error-handling.md | 38 +- ...ch09-01-unrecoverable-errors-with-panic.md | 276 +++-- src/ch09-02-recoverable-errors-with-result.md | 953 +++++++++++------- src/ch09-03-to-panic-or-not-to-panic.md | 285 +++--- 55 files changed, 1138 insertions(+), 1040 deletions(-) create mode 100644 listings/ch09-error-handling/listing-09-10/output.txt rename listings/ch09-error-handling/{no-listing-07-main-returning-result => listing-09-11}/Cargo.lock (92%) rename listings/ch09-error-handling/{no-listing-02-ask-compiler-for-type => listing-09-11}/Cargo.toml (53%) create mode 100644 listings/ch09-error-handling/listing-09-11/src/main.rs rename listings/ch09-error-handling/{no-listing-02-ask-compiler-for-type => listing-09-12}/Cargo.lock (100%) rename listings/ch09-error-handling/{no-listing-03-closures => listing-09-12}/Cargo.toml (53%) rename listings/ch09-error-handling/{no-listing-07-main-returning-result => listing-09-12}/src/main.rs (66%) create mode 100644 listings/ch09-error-handling/listing-09-13/Cargo.lock create mode 100644 listings/ch09-error-handling/listing-09-13/Cargo.toml create mode 100644 listings/ch09-error-handling/listing-09-13/src/main.rs delete mode 100644 listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/output.txt delete mode 100644 listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/src/main.rs delete mode 100644 listings/ch09-error-handling/no-listing-03-closures/Cargo.lock delete mode 100644 listings/ch09-error-handling/no-listing-03-closures/src/main.rs delete mode 100644 listings/ch09-error-handling/no-listing-06-question-mark-in-main/Cargo.lock delete mode 100644 listings/ch09-error-handling/no-listing-06-question-mark-in-main/Cargo.toml delete mode 100644 listings/ch09-error-handling/no-listing-06-question-mark-in-main/output.txt delete mode 100644 listings/ch09-error-handling/no-listing-06-question-mark-in-main/src/main.rs delete mode 100644 listings/ch09-error-handling/no-listing-07-main-returning-result/Cargo.toml diff --git a/listings/ch09-error-handling/listing-09-01/Cargo.toml b/listings/ch09-error-handling/listing-09-01/Cargo.toml index 310342cd3..660e2c819 100644 --- a/listings/ch09-error-handling/listing-09-01/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "panic" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/listing-09-01/output.txt b/listings/ch09-error-handling/listing-09-01/output.txt index 36aef5049..192859280 100644 --- a/listings/ch09-error-handling/listing-09-01/output.txt +++ b/listings/ch09-error-handling/listing-09-01/output.txt @@ -2,5 +2,8 @@ $ cargo run Compiling panic v0.1.0 (file:///projects/panic) Finished dev [unoptimized + debuginfo] target(s) in 0.27s Running `target/debug/panic` -thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/slice/mod.rs:2806:10 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'main' panicked at src/main.rs:4:6: +index out of bounds: the len is 3 but the index is 99 +('main'スレッドはsrc/main.rs:4:6でパニックしました: +境界外番号: 長さは3なのに、添え字は99です) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/listings/ch09-error-handling/listing-09-03/Cargo.toml b/listings/ch09-error-handling/listing-09-03/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/listing-09-03/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/listing-09-03/src/main.rs b/listings/ch09-error-handling/listing-09-03/src/main.rs index 0dfd10b5e..2342904ed 100644 --- a/listings/ch09-error-handling/listing-09-03/src/main.rs +++ b/listings/ch09-error-handling/listing-09-03/src/main.rs @@ -1,5 +1,5 @@ use std::fs::File; fn main() { - let f = File::open("hello.txt"); + let greeting_file_result = File::open("hello.txt"); } diff --git a/listings/ch09-error-handling/listing-09-04/Cargo.toml b/listings/ch09-error-handling/listing-09-04/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/listing-09-04/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/listing-09-04/output.txt b/listings/ch09-error-handling/listing-09-04/output.txt index acc4f0c74..3e41d1f52 100644 --- a/listings/ch09-error-handling/listing-09-04/output.txt +++ b/listings/ch09-error-handling/listing-09-04/output.txt @@ -2,5 +2,8 @@ $ cargo run Compiling error-handling v0.1.0 (file:///projects/error-handling) Finished dev [unoptimized + debuginfo] target(s) in 0.73s Running `target/debug/error-handling` -thread 'main' panicked at 'Problem opening the file: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/main.rs:8:23 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'main' panicked at src/main.rs:8:23: +Problem opening the file: Os { code: 2, kind: NotFound, message: "No such file or directory" } +('main'スレッドは、src/main.rs:8:23でパニックしました: +ファイルを開く際に問題がありました: Os { code: 2, kind: NotFound, message: "そのようなファイルやディレクトリはありません" }) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/listings/ch09-error-handling/listing-09-04/src/main.rs b/listings/ch09-error-handling/listing-09-04/src/main.rs index 070fc3380..dc1ef3cdd 100644 --- a/listings/ch09-error-handling/listing-09-04/src/main.rs +++ b/listings/ch09-error-handling/listing-09-04/src/main.rs @@ -1,10 +1,11 @@ use std::fs::File; fn main() { - let f = File::open("hello.txt"); + let greeting_file_result = File::open("hello.txt"); - let f = match f { + let greeting_file = match greeting_file_result { Ok(file) => file, + // "ファイルを開くのに問題がありました: {:?}" Err(error) => panic!("Problem opening the file: {:?}", error), }; } diff --git a/listings/ch09-error-handling/listing-09-05/Cargo.toml b/listings/ch09-error-handling/listing-09-05/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/listing-09-05/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/listing-09-05/src/main.rs b/listings/ch09-error-handling/listing-09-05/src/main.rs index 8c4f773b9..25dac5c47 100644 --- a/listings/ch09-error-handling/listing-09-05/src/main.rs +++ b/listings/ch09-error-handling/listing-09-05/src/main.rs @@ -2,17 +2,19 @@ use std::fs::File; use std::io::ErrorKind; fn main() { - let f = File::open("hello.txt"); + let greeting_file_result = File::open("hello.txt"); - let f = match f { + let greeting_file = match greeting_file_result { Ok(file) => file, Err(error) => match error.kind() { ErrorKind::NotFound => match File::create("hello.txt") { Ok(fc) => fc, + // "ファイルを作成するのに問題がありました: {:?}" Err(e) => panic!("Problem creating the file: {:?}", e), }, other_error => { - panic!("Problem opening the file: {:?}", other_error) + // "ファイルを開くのに問題がありました: {:?}" + panic!("Problem opening the file: {:?}", other_error); } }, }; diff --git a/listings/ch09-error-handling/listing-09-06/Cargo.toml b/listings/ch09-error-handling/listing-09-06/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/listing-09-06/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/listing-09-06/src/main.rs b/listings/ch09-error-handling/listing-09-06/src/main.rs index 437d858f4..a70734cb5 100644 --- a/listings/ch09-error-handling/listing-09-06/src/main.rs +++ b/listings/ch09-error-handling/listing-09-06/src/main.rs @@ -1,20 +1,19 @@ // ANCHOR: here use std::fs::File; -use std::io; -use std::io::Read; +use std::io::{self, Read}; fn read_username_from_file() -> Result { - let f = File::open("hello.txt"); + let username_file_result = File::open("hello.txt"); - let mut f = match f { + let mut username_file = match username_file_result { Ok(file) => file, Err(e) => return Err(e), }; - let mut s = String::new(); + let mut username = String::new(); - match f.read_to_string(&mut s) { - Ok(_) => Ok(s), + match username_file.read_to_string(&mut username) { + Ok(_) => Ok(username), Err(e) => Err(e), } } diff --git a/listings/ch09-error-handling/listing-09-07/Cargo.toml b/listings/ch09-error-handling/listing-09-07/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/listing-09-07/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/listing-09-07/src/main.rs b/listings/ch09-error-handling/listing-09-07/src/main.rs index b9f6172cb..0295949d2 100644 --- a/listings/ch09-error-handling/listing-09-07/src/main.rs +++ b/listings/ch09-error-handling/listing-09-07/src/main.rs @@ -1,13 +1,12 @@ // ANCHOR: here use std::fs::File; -use std::io; -use std::io::Read; +use std::io::{self, Read}; fn read_username_from_file() -> Result { - let mut f = File::open("hello.txt")?; - let mut s = String::new(); - f.read_to_string(&mut s)?; - Ok(s) + let mut username_file = File::open("hello.txt")?; + let mut username = String::new(); + username_file.read_to_string(&mut username)?; + Ok(username) } // ANCHOR_END: here diff --git a/listings/ch09-error-handling/listing-09-08/Cargo.toml b/listings/ch09-error-handling/listing-09-08/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/listing-09-08/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/listing-09-08/src/main.rs b/listings/ch09-error-handling/listing-09-08/src/main.rs index f36e4d021..ca672caad 100644 --- a/listings/ch09-error-handling/listing-09-08/src/main.rs +++ b/listings/ch09-error-handling/listing-09-08/src/main.rs @@ -1,14 +1,13 @@ // ANCHOR: here use std::fs::File; -use std::io; -use std::io::Read; +use std::io::{self, Read}; fn read_username_from_file() -> Result { - let mut s = String::new(); + let mut username = String::new(); - File::open("hello.txt")?.read_to_string(&mut s)?; + File::open("hello.txt")?.read_to_string(&mut username)?; - Ok(s) + Ok(username) } // ANCHOR_END: here diff --git a/listings/ch09-error-handling/listing-09-09/Cargo.toml b/listings/ch09-error-handling/listing-09-09/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/listing-09-09/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/listing-09-10/Cargo.lock b/listings/ch09-error-handling/listing-09-10/Cargo.lock index c346748e5..1fa96b797 100644 --- a/listings/ch09-error-handling/listing-09-10/Cargo.lock +++ b/listings/ch09-error-handling/listing-09-10/Cargo.lock @@ -1,87 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "guessing_game" +name = "error-handling" version = "0.1.0" -dependencies = [ - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.53" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -[metadata] -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)" = "ec350a9417dfd244dc9a6c4a71e13895a4db6b92f0b106f07ebbc3f3bc580cee" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/listings/ch09-error-handling/listing-09-10/Cargo.toml b/listings/ch09-error-handling/listing-09-10/Cargo.toml index ad5ca696d..c496db783 100644 --- a/listings/ch09-error-handling/listing-09-10/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-10/Cargo.toml @@ -1,8 +1,6 @@ [package] -name = "guessing_game" +name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] -rand = "0.5.5" diff --git a/listings/ch09-error-handling/listing-09-10/output.txt b/listings/ch09-error-handling/listing-09-10/output.txt new file mode 100644 index 000000000..2ed180943 --- /dev/null +++ b/listings/ch09-error-handling/listing-09-10/output.txt @@ -0,0 +1,18 @@ +$ cargo run + Compiling error-handling v0.1.0 (file:///projects/error-handling) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) +(エラー: `?`演算子は`Result`または`Option`(あるいはその他`FromResidual`を実装する型)を返す関数内でのみ使用できます + --> src/main.rs:4:48 + | +3 | fn main() { + | --------- this function should return `Result` or `Option` to accept `?` + (`?`を使えるようにするには、この関数は`Result`または`Option`を返すべきです) +4 | let greeting_file = File::open("hello.txt")?; + | ^ cannot use the `?` operator in a function that returns `()` + (`()`を返す関数内では`?`演算子を使用できません) + | + = help: the trait `FromResidual>` is not implemented for `()` + (ヘルプ: トレイト`FromResidual>`は`()`に対して実装されていません) + +For more information about this error, try `rustc --explain E0277`. +error: could not compile `error-handling` (bin "error-handling") due to 1 previous error diff --git a/listings/ch09-error-handling/listing-09-10/src/main.rs b/listings/ch09-error-handling/listing-09-10/src/main.rs index 7448979a0..38b005480 100644 --- a/listings/ch09-error-handling/listing-09-10/src/main.rs +++ b/listings/ch09-error-handling/listing-09-10/src/main.rs @@ -1,55 +1,5 @@ -use rand::Rng; -use std::cmp::Ordering; -use std::io; - -// ANCHOR: here -pub struct Guess { - value: i32, -} - -impl Guess { - pub fn new(value: i32) -> Guess { - if value < 1 || value > 100 { - panic!("Guess value must be between 1 and 100, got {}.", value); - } - - Guess { value } - } - - pub fn value(&self) -> i32 { - self.value - } -} -// ANCHOR_END: here +use std::fs::File; fn main() { - println!("Guess the number!"); - - let secret_number = rand::thread_rng().gen_range(1, 101); - - loop { - println!("Please input your guess."); - - let mut guess = String::new(); - - io::stdin() - .read_line(&mut guess) - .expect("Failed to read line"); - - let guess: i32 = match guess.trim().parse() { - Ok(num) => num, - Err(_) => continue, - }; - - let guess = Guess::new(guess); - - match guess.value().cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => { - println!("You win!"); - break; - } - } - } + let greeting_file = File::open("hello.txt")?; } diff --git a/listings/ch09-error-handling/no-listing-07-main-returning-result/Cargo.lock b/listings/ch09-error-handling/listing-09-11/Cargo.lock similarity index 92% rename from listings/ch09-error-handling/no-listing-07-main-returning-result/Cargo.lock rename to listings/ch09-error-handling/listing-09-11/Cargo.lock index 1fa96b797..7320ae639 100644 --- a/listings/ch09-error-handling/no-listing-07-main-returning-result/Cargo.lock +++ b/listings/ch09-error-handling/listing-09-11/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "error-handling" version = "0.1.0" - diff --git a/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/Cargo.toml b/listings/ch09-error-handling/listing-09-11/Cargo.toml similarity index 53% rename from listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/Cargo.toml rename to listings/ch09-error-handling/listing-09-11/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/listing-09-11/src/main.rs b/listings/ch09-error-handling/listing-09-11/src/main.rs new file mode 100644 index 000000000..bd5322786 --- /dev/null +++ b/listings/ch09-error-handling/listing-09-11/src/main.rs @@ -0,0 +1,15 @@ +// ANCHOR: here +fn last_char_of_first_line(text: &str) -> Option { + text.lines().next()?.chars().last() +} +// ANCHOR_END: here + +fn main() { + assert_eq!( + last_char_of_first_line("Hello, world\nHow are you today?"), + Some('d') + ); + + assert_eq!(last_char_of_first_line(""), None); + assert_eq!(last_char_of_first_line("\nhi"), None); +} diff --git a/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/Cargo.lock b/listings/ch09-error-handling/listing-09-12/Cargo.lock similarity index 100% rename from listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/Cargo.lock rename to listings/ch09-error-handling/listing-09-12/Cargo.lock diff --git a/listings/ch09-error-handling/no-listing-03-closures/Cargo.toml b/listings/ch09-error-handling/listing-09-12/Cargo.toml similarity index 53% rename from listings/ch09-error-handling/no-listing-03-closures/Cargo.toml rename to listings/ch09-error-handling/listing-09-12/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/no-listing-03-closures/Cargo.toml +++ b/listings/ch09-error-handling/listing-09-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/no-listing-07-main-returning-result/src/main.rs b/listings/ch09-error-handling/listing-09-12/src/main.rs similarity index 66% rename from listings/ch09-error-handling/no-listing-07-main-returning-result/src/main.rs rename to listings/ch09-error-handling/listing-09-12/src/main.rs index 7f16b8e99..b0f7445f4 100644 --- a/listings/ch09-error-handling/no-listing-07-main-returning-result/src/main.rs +++ b/listings/ch09-error-handling/listing-09-12/src/main.rs @@ -2,7 +2,7 @@ use std::error::Error; use std::fs::File; fn main() -> Result<(), Box> { - let f = File::open("hello.txt")?; + let greeting_file = File::open("hello.txt")?; Ok(()) } diff --git a/listings/ch09-error-handling/listing-09-13/Cargo.lock b/listings/ch09-error-handling/listing-09-13/Cargo.lock new file mode 100644 index 000000000..2ae9e459e --- /dev/null +++ b/listings/ch09-error-handling/listing-09-13/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "guessing_game" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "libc" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/listings/ch09-error-handling/listing-09-13/Cargo.toml b/listings/ch09-error-handling/listing-09-13/Cargo.toml new file mode 100644 index 000000000..d508e9578 --- /dev/null +++ b/listings/ch09-error-handling/listing-09-13/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "guessing_game" +version = "0.1.0" +edition = "2021" + +[dependencies] +rand = "0.8.5" diff --git a/listings/ch09-error-handling/listing-09-13/src/main.rs b/listings/ch09-error-handling/listing-09-13/src/main.rs new file mode 100644 index 000000000..ad832a423 --- /dev/null +++ b/listings/ch09-error-handling/listing-09-13/src/main.rs @@ -0,0 +1,56 @@ +use rand::Rng; +use std::cmp::Ordering; +use std::io; + +// ANCHOR: here +pub struct Guess { + value: i32, +} + +impl Guess { + pub fn new(value: i32) -> Guess { + if value < 1 || value > 100 { + // "予想の値は1から100の範囲でなければなりませんが、{}でした。" + panic!("Guess value must be between 1 and 100, got {}.", value); + } + + Guess { value } + } + + pub fn value(&self) -> i32 { + self.value + } +} +// ANCHOR_END: here + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1..=100); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin() + .read_line(&mut guess) + .expect("Failed to read line"); + + let guess: i32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, + }; + + let guess = Guess::new(guess); + + match guess.value().cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => { + println!("You win!"); + break; + } + } + } +} diff --git a/listings/ch09-error-handling/no-listing-01-panic/Cargo.toml b/listings/ch09-error-handling/no-listing-01-panic/Cargo.toml index 310342cd3..660e2c819 100644 --- a/listings/ch09-error-handling/no-listing-01-panic/Cargo.toml +++ b/listings/ch09-error-handling/no-listing-01-panic/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "panic" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/no-listing-01-panic/output.txt b/listings/ch09-error-handling/no-listing-01-panic/output.txt index 1bc3dc729..c197671a6 100644 --- a/listings/ch09-error-handling/no-listing-01-panic/output.txt +++ b/listings/ch09-error-handling/no-listing-01-panic/output.txt @@ -2,5 +2,8 @@ $ cargo run Compiling panic v0.1.0 (file:///projects/panic) Finished dev [unoptimized + debuginfo] target(s) in 0.25s Running `target/debug/panic` -thread 'main' panicked at 'crash and burn', src/main.rs:2:5 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'main' panicked at src/main.rs:2:5: +crash and burn +('main'スレッドはsrc/main.rs:2:5でパニックしました: +クラッシュして炎上) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/listings/ch09-error-handling/no-listing-01-panic/src/main.rs b/listings/ch09-error-handling/no-listing-01-panic/src/main.rs index 32a4c243d..3e482809d 100644 --- a/listings/ch09-error-handling/no-listing-01-panic/src/main.rs +++ b/listings/ch09-error-handling/no-listing-01-panic/src/main.rs @@ -1,3 +1,4 @@ fn main() { + // "クラッシュして炎上" panic!("crash and burn"); } diff --git a/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/output.txt b/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/output.txt deleted file mode 100644 index 18262cbc4..000000000 --- a/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/output.txt +++ /dev/null @@ -1,19 +0,0 @@ -$ cargo run - Compiling error-handling v0.1.0 (file:///projects/error-handling) -error[E0308]: mismatched types - --> src/main.rs:4:18 - | -4 | let f: u32 = File::open("hello.txt"); - | --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found enum `std::result::Result` - | | - | expected due to this - | - = note: expected type `u32` - found enum `std::result::Result` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. -error: could not compile `error-handling`. - -To learn more, run the command again with --verbose. diff --git a/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/src/main.rs b/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/src/main.rs deleted file mode 100644 index a637f5f95..000000000 --- a/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/src/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -use std::fs::File; - -fn main() { - // ANCHOR: here - let f: u32 = File::open("hello.txt"); - // ANCHOR_END: here -} diff --git a/listings/ch09-error-handling/no-listing-03-closures/Cargo.lock b/listings/ch09-error-handling/no-listing-03-closures/Cargo.lock deleted file mode 100644 index 1fa96b797..000000000 --- a/listings/ch09-error-handling/no-listing-03-closures/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "error-handling" -version = "0.1.0" - diff --git a/listings/ch09-error-handling/no-listing-03-closures/src/main.rs b/listings/ch09-error-handling/no-listing-03-closures/src/main.rs deleted file mode 100644 index c6682cd23..000000000 --- a/listings/ch09-error-handling/no-listing-03-closures/src/main.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::fs::File; -use std::io::ErrorKind; - -fn main() { - let f = File::open("hello.txt").unwrap_or_else(|error| { - if error.kind() == ErrorKind::NotFound { - File::create("hello.txt").unwrap_or_else(|error| { - panic!("Problem creating the file: {:?}", error); - }) - } else { - panic!("Problem opening the file: {:?}", error); - } - }); -} diff --git a/listings/ch09-error-handling/no-listing-04-unwrap/Cargo.toml b/listings/ch09-error-handling/no-listing-04-unwrap/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/no-listing-04-unwrap/Cargo.toml +++ b/listings/ch09-error-handling/no-listing-04-unwrap/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/no-listing-04-unwrap/src/main.rs b/listings/ch09-error-handling/no-listing-04-unwrap/src/main.rs index 7b6b13ae7..92e9452f1 100644 --- a/listings/ch09-error-handling/no-listing-04-unwrap/src/main.rs +++ b/listings/ch09-error-handling/no-listing-04-unwrap/src/main.rs @@ -1,5 +1,5 @@ use std::fs::File; fn main() { - let f = File::open("hello.txt").unwrap(); + let greeting_file = File::open("hello.txt").unwrap(); } diff --git a/listings/ch09-error-handling/no-listing-05-expect/Cargo.toml b/listings/ch09-error-handling/no-listing-05-expect/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/no-listing-05-expect/Cargo.toml +++ b/listings/ch09-error-handling/no-listing-05-expect/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/no-listing-05-expect/src/main.rs b/listings/ch09-error-handling/no-listing-05-expect/src/main.rs index cab643bc5..3759f1fa7 100644 --- a/listings/ch09-error-handling/no-listing-05-expect/src/main.rs +++ b/listings/ch09-error-handling/no-listing-05-expect/src/main.rs @@ -1,5 +1,7 @@ use std::fs::File; fn main() { - let f = File::open("hello.txt").expect("Failed to open hello.txt"); + let greeting_file = File::open("hello.txt") + // "hello.txtがこのプロジェクトに含まれているべきです" + .expect("hello.txt should be included in this project"); } diff --git a/listings/ch09-error-handling/no-listing-06-question-mark-in-main/Cargo.lock b/listings/ch09-error-handling/no-listing-06-question-mark-in-main/Cargo.lock deleted file mode 100644 index 1fa96b797..000000000 --- a/listings/ch09-error-handling/no-listing-06-question-mark-in-main/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "error-handling" -version = "0.1.0" - diff --git a/listings/ch09-error-handling/no-listing-06-question-mark-in-main/Cargo.toml b/listings/ch09-error-handling/no-listing-06-question-mark-in-main/Cargo.toml deleted file mode 100644 index 2a48daefb..000000000 --- a/listings/ch09-error-handling/no-listing-06-question-mark-in-main/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "error-handling" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch09-error-handling/no-listing-06-question-mark-in-main/output.txt b/listings/ch09-error-handling/no-listing-06-question-mark-in-main/output.txt deleted file mode 100644 index 17a8b2e47..000000000 --- a/listings/ch09-error-handling/no-listing-06-question-mark-in-main/output.txt +++ /dev/null @@ -1,20 +0,0 @@ -$ cargo run - Compiling error-handling v0.1.0 (file:///projects/error-handling) -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) - --> src/main.rs:4:13 - | -3 | / fn main() { -4 | | let f = File::open("hello.txt")?; - | | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` -5 | | } - | |_- this function should return `Result` or `Option` to accept `?` - | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. -error: could not compile `error-handling`. - -To learn more, run the command again with --verbose. diff --git a/listings/ch09-error-handling/no-listing-06-question-mark-in-main/src/main.rs b/listings/ch09-error-handling/no-listing-06-question-mark-in-main/src/main.rs deleted file mode 100644 index 8608dc13f..000000000 --- a/listings/ch09-error-handling/no-listing-06-question-mark-in-main/src/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -use std::fs::File; - -fn main() { - let f = File::open("hello.txt")?; -} diff --git a/listings/ch09-error-handling/no-listing-07-main-returning-result/Cargo.toml b/listings/ch09-error-handling/no-listing-07-main-returning-result/Cargo.toml deleted file mode 100644 index 2a48daefb..000000000 --- a/listings/ch09-error-handling/no-listing-07-main-returning-result/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "error-handling" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch09-error-handling/no-listing-08-unwrap-that-cant-fail/Cargo.toml b/listings/ch09-error-handling/no-listing-08-unwrap-that-cant-fail/Cargo.toml index 2a48daefb..c496db783 100644 --- a/listings/ch09-error-handling/no-listing-08-unwrap-that-cant-fail/Cargo.toml +++ b/listings/ch09-error-handling/no-listing-08-unwrap-that-cant-fail/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "error-handling" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch09-error-handling/no-listing-08-unwrap-that-cant-fail/src/main.rs b/listings/ch09-error-handling/no-listing-08-unwrap-that-cant-fail/src/main.rs index e829724c5..ae237939b 100644 --- a/listings/ch09-error-handling/no-listing-08-unwrap-that-cant-fail/src/main.rs +++ b/listings/ch09-error-handling/no-listing-08-unwrap-that-cant-fail/src/main.rs @@ -2,6 +2,9 @@ fn main() { // ANCHOR: here use std::net::IpAddr; - let home: IpAddr = "127.0.0.1".parse().unwrap(); + let home: IpAddr = "127.0.0.1" + .parse() + // "ハードコードされたIPアドレスは有効であるべきです" + .expect("Hardcoded IP address should be valid"); // ANCHOR_END: here } diff --git a/listings/ch09-error-handling/no-listing-09-guess-out-of-range/Cargo.lock b/listings/ch09-error-handling/no-listing-09-guess-out-of-range/Cargo.lock index c346748e5..2ae9e459e 100644 --- a/listings/ch09-error-handling/no-listing-09-guess-out-of-range/Cargo.lock +++ b/listings/ch09-error-handling/no-listing-09-guess-out-of-range/Cargo.lock @@ -1,87 +1,75 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "bitflags" -version = "1.2.1" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cloudabi" -version = "0.0.3" +name = "getrandom" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "guessing_game" version = "0.1.0" dependencies = [ - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand", ] [[package]] name = "libc" -version = "0.2.53" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.5.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_chacha", + "rand_core", ] [[package]] -name = "rand_core" -version = "0.3.1" +name = "rand_chacha" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)" = "ec350a9417dfd244dc9a6c4a71e13895a4db6b92f0b106f07ebbc3f3bc580cee" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/listings/ch09-error-handling/no-listing-09-guess-out-of-range/Cargo.toml b/listings/ch09-error-handling/no-listing-09-guess-out-of-range/Cargo.toml index ad5ca696d..d508e9578 100644 --- a/listings/ch09-error-handling/no-listing-09-guess-out-of-range/Cargo.toml +++ b/listings/ch09-error-handling/no-listing-09-guess-out-of-range/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "guessing_game" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] -rand = "0.5.5" +rand = "0.8.5" diff --git a/listings/ch09-error-handling/no-listing-09-guess-out-of-range/src/main.rs b/listings/ch09-error-handling/no-listing-09-guess-out-of-range/src/main.rs index d89d719aa..fc22cbc5e 100644 --- a/listings/ch09-error-handling/no-listing-09-guess-out-of-range/src/main.rs +++ b/listings/ch09-error-handling/no-listing-09-guess-out-of-range/src/main.rs @@ -5,7 +5,7 @@ use std::io; fn main() { println!("Guess the number!"); - let secret_number = rand::thread_rng().gen_range(1, 101); + let secret_number = rand::thread_rng().gen_range(1..=100); // ANCHOR: here loop { diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 1a0898305..24d253292 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -116,7 +116,7 @@ - [Error Handling](ch09-00-error-handling.md) - [Unrecoverable Errors with `panic!`](ch09-01-unrecoverable-errors-with-panic.md) - [Recoverable Errors with `Result`](ch09-02-recoverable-errors-with-result.md) - - [To `panic!` or Not To `panic!`](ch09-03-to-panic-or-not-to-panic.md) + - [To `panic!` or Not to `panic!`](ch09-03-to-panic-or-not-to-panic.md) --> - [エラー処理](ch09-00-error-handling.md) - [`panic!`で回復不能なエラー](ch09-01-unrecoverable-errors-with-panic.md) diff --git a/src/ch09-00-error-handling.md b/src/ch09-00-error-handling.md index 8a389f8e0..d3c3865de 100644 --- a/src/ch09-00-error-handling.md +++ b/src/ch09-00-error-handling.md @@ -5,45 +5,45 @@ # エラー処理 -Rustの信頼性への傾倒は、エラー処理にも及びます。ソフトウェアにおいて、エラーは生きている証しです。 -従って、Rustには何かがおかしくなる場面を扱う機能がたくさんあります。多くの場面で、 +ソフトウェアにおいて、エラーは避けられない現実です。 +そのため、Rustには何かがおかしくなる場面に対処するための機能がたくさんあります。多くの場面で、 コンパイラは、プログラマにエラーの可能性を知り、コードのコンパイルが通るまでに何かしら対応を行うことを要求してきます。 この要求により、エラーを発見し、コードを実用に供する前に適切に対処していることを確認することでプログラムを頑健なものにしてくれるのです! Rustでは、エラーは大きく二つに分類されます: *回復可能*と*回復不能*なエラーです。 -ファイルが見つからないなどの回復可能なエラーには、問題をユーザに報告し、処理を再試行することが合理的になります。 -回復不能なエラーは、常にバグの兆候です。例えば、配列の境界を超えた箇所にアクセスしようとすることなどです。 +*ファイルが見つからない*などの回復可能なエラーには、ほとんどの場合は単に問題をユーザに報告し、処理を再試行したいことでしょう。 +回復不能なエラー、例えば配列の境界を超えた箇所にアクセスしようとすることなどは、常にバグの兆候であり、直ちにプログラムを停止したいことでしょう。 多くの言語では、この2種のエラーを区別することはなく、例外などの機構を使用して同様に扱います。 -Rustには例外が存在しません。代わりに、回復可能なエラーには`Result`値があり、 +Rustには例外が存在しません。代わりに、回復可能なエラーには`Result`型があり、 プログラムが回復不能なエラーに遭遇した時には、実行を中止する`panic!`マクロがあります。 この章では、まず`panic!`の呼び出しを講義し、それから`Result`を戻り値にする話をします。 加えて、エラーからの回復を試みるか、実行を中止するか決定する際に考慮すべき事項についても、探究しましょう。 diff --git a/src/ch09-01-unrecoverable-errors-with-panic.md b/src/ch09-01-unrecoverable-errors-with-panic.md index a8c8bded9..70c0c5a2b 100644 --- a/src/ch09-01-unrecoverable-errors-with-panic.md +++ b/src/ch09-01-unrecoverable-errors-with-panic.md @@ -6,25 +6,35 @@ -時として、コードで悪いことが起きるものです。そして、それに対してできることは何もありません。 -このような場面で、Rustには`panic!`マクロが用意されています。`panic!`マクロが実行されると、 -プログラムは失敗のメッセージを表示し、スタックを巻き戻し掃除して、終了します。これが最もありふれて起こるのは、 -何らかのバグが検出された時であり、プログラマには、どうエラーを処理すればいいか明確ではありません。 +時として、コード内で悪いことが起き、それに対してできることは何も無い、ということがあるでしょう。 +このような場面で、Rustには`panic!`マクロが用意されています。 +実際にパニックを発生させる方法は2つあります: +コードをパニックさせるような操作(配列にその終端を超えてアクセスするなど)を行う方法と、明示的に`panic!`マクロを呼び出す方法です。 +いずれの場合でも、プログラムでパニックが発生します。 +デフォルトでは、これらのパニックは失敗メッセージを出力し、スタックを巻き戻し、片付け、プログラムを終了させます。 +パニックが発生したときにはそのパニックの発生源を特定しやすくするために、 +環境変数を介してコールスタックを表示するように指示することもできます。 + -> ### パニックに対してスタックを巻き戻すか異常終了するか +> ### パニックに対してスタックを巻き戻すかアボートするか > -> 標準では、パニックが発生すると、プログラムは*巻き戻し*を始めます。つまり、言語がスタックを遡り、 -> 遭遇した各関数のデータを片付けるということです。しかし、この遡りと片付けはすべきことが多くなります。 -> 対立案は、即座に異常終了し、片付けをせずにプログラムを終了させることです。そうなると、プログラムが使用していたメモリは、 +> デフォルトでは、パニックが発生すると、プログラムは*巻き戻し*を始めます。 +> つまり、コンパイラ生成コードがスタックを遡り、遭遇した各関数のデータを片付けるということです。 +> しかし、この遡行と片付けはすべきことが多くなります。そのためRustでは、 +> 即座に*アボート*し、片付けをせずにプログラムを終了させることを、代替として選択できるようになっています。 +> +> そうなると、プログラムが使用していたメモリは、 > OSが片付ける必要があります。プロジェクトにおいて、実行可能ファイルを極力小さくする必要があれば、 > *Cargo.toml*ファイルの適切な`[profile]`欄に`panic = 'abort'`を追記することで、 -> パニック時に巻き戻しから異常終了するように切り替えることができます。例として、 -> リリースモード時に異常終了するようにしたければ、以下を追記してください: +> パニック時に巻き戻しからアボートするように切り替えることができます。例として、 +> リリースモード時にアボートするようにしたければ、以下を追記してください: > > ```toml > [profile.release] @@ -64,10 +77,8 @@ Let’s try calling `panic!` in a simple program: ファイル名: src/main.rs -```rust,should_panic -fn main() { - panic!("crash and burn"); //クラッシュして炎上 -} +```rust,should_panic,panics +{{#rustdoc_include ../listings/ch09-error-handling/no-listing-01-panic/src/main.rs}} ``` `panic!`の呼び出しが、最後の2行に含まれるエラーメッセージを発生させているのです。 1行目にパニックメッセージとソースコード中でパニックが発生した箇所を示唆しています: -*src/main.rs:2:4*は、*src/main.rs*ファイルの2行目4文字目であることを示しています。 +*src/main.rs:2:5*は、*src/main.rs*ファイルの2行目5文字目であることを示しています。 この場合、示唆される行は、自分のコードの一部で、その箇所を見に行けば、`panic!`マクロ呼び出しがあるわけです。 それ以外では、`panic!`呼び出しが、自分のコードが呼び出しているコードの一部になっている可能性もあるわけです。 エラーメッセージで報告されるファイル名と行番号が、結果的に`panic!`呼び出しに導いた自分のコードの行ではなく、 `panic!`マクロが呼び出されている他人のコードになるでしょう。`panic!`呼び出しの発生元である関数のバックトレースを使用して、 -問題を起こしている自分のコードの箇所を割り出すことができます。バックトレースがどんなものか、次に議論しましょう。 +問題を起こしている自分のコードの箇所を割り出すことができます。次はバックトレースについてはより詳しく議論しましょう。 別の例を眺めて、自分のコードでマクロを直接呼び出す代わりに、コードに存在するバグにより、 ライブラリで`panic!`呼び出しが発生するとどんな感じなのか確かめてみましょう。リスト9-1は、 -添え字でベクタの要素にアクセスを試みる何らかのコードです。 +ベクタに有効な添え字の範囲の外の添え字でアクセスを試みるコードです。 ここでは、ベクタの100番目の要素(添え字は0始まりなので添え字99)にアクセスを試みていますが、ベクタには3つしか要素がありません。 @@ -165,19 +166,19 @@ would be correct. 無効な添え字を渡せば、ここでRustが返せて正しいと思われる要素は何もないわけです。 -他の言語(Cなど)では、この場面で欲しいものではないにもかかわらず、まさしく要求したものを返そうとしてきます: -メモリがベクタに属していないにもかかわらず、ベクタ内のその要素に対応するメモリ上の箇所にあるものを何か返してくるのです。 -これは、*バッファー外読み出し*(buffer overread; `訳注`: バッファー読みすぎとも解釈できるか)と呼ばれ、 -攻撃者が、配列の後に格納された読めるべきでないデータを読み出せるように添え字を操作できたら、 +Cでは、データ構造の終端を超えて読み込みを行おうとすることは未定義動作です。 +メモリがデータ構造に属していないにもかかわらず、そのデータ構造内のその要素に対応するメモリ上の箇所にある何かを返してくるかもしれません。 +これは、*バッファオーバーリード* (*buffer overread*)と呼ばれ、 +攻撃者が、データ構造の後に格納された読めるべきでないデータを読み出せるように添え字を操作できたら、 セキュリティ脆弱性につながる可能性があります。 - -このエラーは、自分のファイルではない*vec.rs*ファイルを指しています。 -標準ライブラリの`Vec`の実装です。ベクタ`v`に対して`[]`を使った時に走るコードは、 -*vec.rs*に存在し、ここで実際に`panic!`が発生しているのです。 - - +このエラーは*main.rs*の4行目を指していて、ここではインデックス99にアクセスを試みています。 その次の注釈行は、`RUST_BACKTRACE`環境変数をセットして、まさしく何が起き、 エラーが発生したのかのバックトレースを得られることを教えてくれています。 *バックトレース*とは、ここに至るまでに呼び出された全関数の一覧です。Rustのバックトレースも、 他の言語同様に動作します: バックトレースを読むコツは、頭からスタートして自分のファイルを見つけるまで読むことです。 -そこが、問題の根源になるのです。自分のファイルを言及している箇所以前は、自分のコードで呼び出したコードになります; -以後は、自分のコードを呼び出しているコードになります。これらの行には、Rustの核となるコード、標準ライブラリのコード、 +そこが、問題が発生した場所です。この場所より上の行は、自分のコードが呼び出したコードになります; +それより下の行は、自分のコードを呼び出しているコードになります。これらの前後の行には、Rustの核となるコード、標準ライブラリのコード、 使用しているクレートなどが含まれるかもしれません。`RUST_BACKTRACE`環境変数を0以外の値にセットして、 バックトレースを出力してみましょう。リスト9-2のような出力が得られるでしょう。 -```text + + +```console $ RUST_BACKTRACE=1 cargo run - Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs - Running `target/debug/panic` -thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', /checkout/src/liballoc/vec.rs:1555:10 +thread 'main' panicked at src/main.rs:4:6: +index out of bounds: the len is 3 but the index is 99 stack backtrace: - 0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace - at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49 - 1: std::sys_common::backtrace::_print - at /checkout/src/libstd/sys_common/backtrace.rs:71 - 2: std::panicking::default_hook::{{closure}} - at /checkout/src/libstd/sys_common/backtrace.rs:60 - at /checkout/src/libstd/panicking.rs:381 - 3: std::panicking::default_hook - at /checkout/src/libstd/panicking.rs:397 - 4: std::panicking::rust_panic_with_hook - at /checkout/src/libstd/panicking.rs:611 - 5: std::panicking::begin_panic - at /checkout/src/libstd/panicking.rs:572 - 6: std::panicking::begin_panic_fmt - at /checkout/src/libstd/panicking.rs:522 - 7: rust_begin_unwind - at /checkout/src/libstd/panicking.rs:498 - 8: core::panicking::panic_fmt - at /checkout/src/libcore/panicking.rs:71 - 9: core::panicking::panic_bounds_check - at /checkout/src/libcore/panicking.rs:58 - 10: as core::ops::index::Index>::index - at /checkout/src/liballoc/vec.rs:1555 - 11: panic::main - at src/main.rs:4 - 12: __rust_maybe_catch_panic - at /checkout/src/libpanic_unwind/lib.rs:99 - 13: std::rt::lang_start - at /checkout/src/libstd/panicking.rs:459 - at /checkout/src/libstd/panic.rs:361 - at /checkout/src/libstd/rt.rs:61 - 14: main - 15: __libc_start_main - 16: + 0: rust_begin_unwind + at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5 + 1: core::panicking::panic_fmt + at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14 + 2: core::panicking::panic_bounds_check + at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:208:5 + 3: >::index + at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/slice/index.rs:255:10 + 4: core::slice::index:: for [T]>::index + at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/slice/index.rs:18:9 + 5: as core::ops::index::Index>::index + at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/alloc/src/vec/mod.rs:2770:9 + 6: panic::main + at ./src/main.rs:4:6 + 7: core::ops::function::FnOnce::call_once + at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5 +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. ``` -リスト9-2の出力で、バックトレースの11行目が問題発生箇所を指し示しています: *src/main.rs*の4行目です。 -プログラムにパニックしてほしくなければ、自分のファイルについて言及している最初の行で示されている箇所が、 -どのようにパニックを引き起こす値でこの箇所にたどり着いたか割り出すために調査を開始すべき箇所になります。 -バックトレースの使用法を模擬するためにわざとパニックするコードを書いたリスト9-1において、 -パニックを解消する方法は、3つしか要素のないベクタの添え字99の要素を要求しないことです。 +リスト9-2の出力で、バックトレースの6行目が問題発生箇所を指し示しています: *src/main.rs*の4行目です。 +プログラムにパニックしてほしくなければ、自分のファイルについて言及している最初の行で示されている箇所から調査を開始すべきです。 +わざとパニックするコードを書いたリスト9-1において、パニックを解消する方法は、 +ベクタの添え字の範囲を超えた要素を要求しないようにすることです。 将来コードがパニックしたら、パニックを引き起こすどんな値でコードがどんな動作をしているのかと、 代わりにコードは何をすべきなのかを算出する必要があるでしょう。 -この章の後ほど、「`panic!`するか`panic!`するまいか」節で`panic!`とエラー状態を扱うのに`panic!`を使うべき時と使わぬべき時に戻ってきます。 +この章の後ほど、[「`panic!`すべきかするまいか」][to-panic-or-not-to-panic]節で`panic!`とエラー状態を扱うのに`panic!`を使うべき時と使わぬべき時に戻ってきます。 次は、`Result`を使用してエラーから回復する方法を見ましょう。 + + + +[to-panic-or-not-to-panic]: +ch09-03-to-panic-or-not-to-panic.html#panicすべきかするまいか diff --git a/src/ch09-02-recoverable-errors-with-result.md b/src/ch09-02-recoverable-errors-with-result.md index 489e7aef7..205b115be 100644 --- a/src/ch09-02-recoverable-errors-with-result.md +++ b/src/ch09-02-recoverable-errors-with-result.md @@ -6,9 +6,9 @@ @@ -17,16 +17,14 @@ file instead of terminating the process. ファイルが存在しないために処理が失敗したら、プロセスを停止するのではなく、ファイルを作成したいことがあります。 -第2章の[「`Result`型で失敗する可能性に対処する」][handle_failure]で`Result` enumが以下のように、 +第2章の[「`Result`で失敗の可能性を扱う」][handle_failure]で`Result` enumが以下のように、 `Ok`と`Err`の2列挙子からなるよう定義されていることを思い出してください: -[handle_failure]: ch02-00-guessing-game-tutorial.html#resultで失敗の可能性を扱う - ```rust enum Result { Ok(T), @@ -40,15 +38,15 @@ detail in Chapter 10. What you need to know right now is that `T` represents the type of the value that will be returned in a success case within the `Ok` variant, and `E` represents the type of the error that will be returned in a failure case within the `Err` variant. Because `Result` has these generic type -parameters, we can use the `Result` type and the functions that the standard -library has defined on it in many different situations where the successful -value and error value we want to return may differ. +parameters, we can use the `Result` type and the functions defined on it in +many different situations where the successful value and error value we want to +return may differ. --> `T`と`E`は、ジェネリックな型引数です: ジェネリクスについて詳しくは、第10章で議論します。 たった今知っておく必要があることは、`T`が成功した時に`Ok`列挙子に含まれて返される値の型を表すことと、 `E`が失敗した時に`Err`列挙子に含まれて返されるエラーの型を表すことです。`Result`はこのようなジェネリックな型引数を含むので、 -標準ライブラリ上に定義されている`Result`型や関数などを、成功した時とエラーの時に返したい値が異なるような様々な場面で使用できるのです。 +`Result`型とその上に定義されている関数を、成功した時とエラーの時に返したい値が異なるような様々な場面で使用できるのです。 - -`File::open`が`Result`を返すとどう知るのでしょうか?標準ライブラリのAPIドキュメントを参照することもできますし、 -コンパイラに尋ねることもできます!`f`に関数の戻り値では*ない*と判明している型注釈を与えて、 -コードのコンパイルを試みれば、コンパイラは型が合わないと教えてくれるでしょう。そして、エラーメッセージは、 -`f`の*実際の*型を教えてくれるでしょう。試してみましょう!`File::open`の戻り値の型は`u32`ではないと判明しているので、 -`let f`文を以下のように変更しましょう: - -```rust,ignore -let f: u32 = File::open("hello.txt"); -``` - - -これでコンパイルしようとすると、以下のような出力が得られます: - -```text -error[E0308]: mismatched types -(エラー: 型が合いません) - --> src/main.rs:4:18 - | -4 | let f: u32 = File::open("hello.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^ expected u32, found enum -`std::result::Result` - | - = note: expected type `u32` - (注釈: 予期した型は`u32`です) - found type `std::result::Result` - (実際の型は`std::result::Result`です) -``` - - - -これにより、`File::open`関数の戻り値の型は、`Result`であることがわかります。ジェネリック引数の`T`は、 -ここでは成功値の型`std::fs::File`で埋められていて、これはファイルハンドルです。 +`File::open`の戻り値の型は、`Result`です。ジェネリック引数の`T`は、 +`File::open`の実装によって成功値の型`std::fs::File`で埋められていて、これはファイルハンドルです。 エラー値で使用されている`E`の型は、`std::io::Error`です。 - - - この戻り値型は、`File::open`の呼び出しが成功し、読み込みと書き込みを行えるファイルハンドルを返す可能性があることを意味します。 また、関数呼び出しは失敗もする可能性があります: 例えば、ファイルが存在しない可能性、ファイルへのアクセス権限がない可能性です。 `File::open`には成功したか失敗したかを知らせる方法とファイルハンドルまたは、エラー情報を与える方法が必要なのです。 この情報こそが`Result` enumが伝達するものなのです。 -`File::open`が成功した場合、変数`f`の値はファイルハンドルを含む`Ok`インスタンスになります。 -失敗した場合には、発生したエラーの種類に関する情報をより多く含む`Err`インスタンスが`f`の値になります。 +`File::open`が成功した場合、変数`greeting_file_result`の値はファイルハンドルを含む`Ok`インスタンスになります。 +失敗した場合には、発生したエラーの種類に関する情報をより多く含む`Err`インスタンスが`greeting_file_result`の値になります。 -`Option` enumのように、`Result` enumとその列挙子は、初期化処理でインポートされているので、 +`Option` enumのように、`Result` enumとその列挙子は、preludeでスコープ内に持ち込まれているので、 `match`アーム内で`Ok`と`Err`列挙子の前に`Result::`を指定する必要がないことに注目してください。 -ここでは、結果が`Ok`の時に、`Ok`列挙子から中身の`file`値を返すように指示し、 -それからそのファイルハンドル値を変数`f`に代入しています。`match`の後には、 -ファイルハンドルを使用して読み込んだり書き込むことができるわけです。 +このコードは、結果が`Ok`の場合は、`Ok`列挙子から中身の`file`値を返し、 +それからそのファイルハンドル値を変数`greeting_file`に代入しています。 +`match`の後には、ファイルハンドルを使用して読み込んだり書き込むことができるわけです。 -リスト9-4のコードは、`File::open`が失敗した理由にかかわらず`panic!`します。代わりにしたいことは、 -失敗理由によって動作を変えることです: ファイルが存在しないために`File::open`が失敗したら、 +リスト9-4のコードは、`File::open`が失敗した理由にかかわらず`panic!`します。 +ですが、失敗理由によって動作を変えたいとしましょう: ファイルが存在しないために`File::open`が失敗したら、 ファイルを作成し、その新しいファイルへのハンドルを返したいです。他の理由(例えばファイルを開く権限がなかったなど)で、 `File::open`が失敗したら、リスト9-4のようにコードには`panic!`してほしいのです。 -リスト9-5を眺めてください。ここでは`match`に別のアームを追加しています。 +このために、リスト9-5で示すように内側の`match`式を追加します。 ```rust,ignore -use std::fs::File; -use std::io::ErrorKind; - -fn main() { - let f = File::open("hello.txt"); - - let f = match f { - Ok(file) => file, - Err(ref error) if error.kind() == ErrorKind::NotFound => { - match File::create("hello.txt") { - Ok(fc) => fc, - Err(e) => { - panic!( - //ファイルを作成しようとしましたが、問題がありました - "Tried to create file but there was a problem: {:?}", - e - ) - }, - } - }, - Err(error) => { - panic!( - "There was a problem opening the file: {:?}", - error - ) - }, - }; -} +{{#rustdoc_include ../listings/ch09-error-handling/listing-09-05/src/main.rs}} ``` `File::open`が`Err`列挙子に含めて返す値の型は、`io::Error`であり、これは標準ライブラリで提供されている構造体です。 この構造体には、呼び出すと`io::ErrorKind`値が得られる`kind`メソッドがあります。`io::ErrorKind`というenumは、 標準ライブラリで提供されていて、`io`処理の結果発生する可能性のある色々な種類のエラーを表す列挙子があります。 使用したい列挙子は、`ErrorKind::NotFound`で、これは開こうとしているファイルがまだ存在しないことを示唆します。 +そこで、`greeting_file_result`に対してマッチし、さらに`error.kind()`に対する内側のマッチも持たせています。 - -`if error.kind() == ErrorKind::Notfound`という条件式は、*マッチガード*と呼ばれます: -アームのパターンをさらに洗練する`match`アーム上のおまけの条件式です。この条件式は、 -そのアームのコードが実行されるには真でなければいけないのです; そうでなければ、 -パターンマッチングは継続し、`match`の次のアームを考慮します。パターンの`ref`は、 -`error`がガード条件式にムーブされないように必要ですが、ただ単にガード式に参照されます。 -`ref`を使用して`&`の代わりにパターン内で参照を作っている理由は、第18章で詳しく講義します。 -手短に言えば、パターンの文脈において、`&`は参照にマッチし、その値を返しますが、 -`ref`は値にマッチし、それへの参照を返すということなのです。 - - -マッチガードで精査したい条件は、`error.kind()`により返る値が、`ErrorKind` enumの`NotFound`列挙子であるかということです。 +内側のマッチで精査したい条件は、`error.kind()`により返る値が、`ErrorKind` enumの`NotFound`列挙子であるかということです。 もしそうなら、`File::create`でファイル作成を試みます。ところが、`File::create`も失敗する可能性があるので、 -内部にも`match`式を追加する必要があるのです。ファイルが開けないなら、異なるエラーメッセージが出力されるでしょう。 -外側の`match`の最後のアームは同じままなので、ファイルが存在しないエラー以外ならプログラムはパニックします。 +内側の`match`式の2番目のアームが必要なのです。ファイルを作成できない場合、異なるエラーメッセージが出力されます。 +外側の`match`の2番目のアームは同じままなので、ファイルが存在しないエラー以外ならプログラムはパニックします。 + + + +> ### `Result`に対する`match`の使用の代わりとなる方法 +> +> `match`がたくさん出てきましたね!`match`式は非常に有用ですが、非常に原始的でもあります。 +> 第13章でクロージャについて学習しますが、これは`Result`上に定義されているメソッドの多くで使用することができます。 +> コード内で`Result`値を扱うときには、こうしたメソッドを使ったほうがより簡潔になります。 +> +> 例えば、以下はリスト9-5に示したものと同じロジックを書く例ですが、 +> 今度はクロージャと`unwrap_or_else`メソッドを使用しています: +> +> ```rust,ignore +> use std::fs::File; +> use std::io::ErrorKind; +> +> fn main() { +> let greeting_file = File::open("hello.txt").unwrap_or_else(|error| { +> if error.kind() == ErrorKind::NotFound { +> File::create("hello.txt").unwrap_or_else(|error| { +> panic!("Problem creating the file: {:?}", error); +> }) +> } else { +> panic!("Problem opening the file: {:?}", error); +> } +> }); +> } +> ``` +> +> このコードはリスト9-5と同じ動作をしますが、`match`式をまったく含んでおらず、より読みやすいです。 +> 第13章を読み終えたら、この例に戻ってきて、標準ライブラリドキュメント内で`unwrap_or_else`を探してみてください。 +> エラーに対処するときには、これらのメソッドを多用することで、巨大なネストされた`match`式を整理することができます。 `match`の使用は、十分に仕事をしてくれますが、いささか冗長になり得る上、必ずしも意図をよく伝えるとは限りません。 -`Result`型には、色々な作業をするヘルパーメソッドが多く定義されています。それらの関数の一つは、 -`unwrap`と呼ばれますが、リスト9-4で書いた`match`式と同じように実装された短絡メソッドです。 +`Result`型には、様々な特定の作業をするヘルパーメソッドが多く定義されています。 +`unwrap`メソッドは、リスト9-4で書いた`match`式と同じように実装された短絡メソッドです。 `Result`値が`Ok`列挙子なら、`unwrap`は`Ok`の中身を返します。`Result`が`Err`列挙子なら、 `unwrap`は`panic!`マクロを呼んでくれます。こちらが実際に動作している`unwrap`の例です: @@ -387,11 +342,7 @@ call the `panic!` macro for us. Here is an example of `unwrap` in action: ファイル名: src/main.rs ```rust,should_panic -use std::fs::File; - -fn main() { - let f = File::open("hello.txt").unwrap(); -} +{{#rustdoc_include ../listings/ch09-error-handling/no-listing-04-unwrap/src/main.rs}} ``` + + このコードを*hello.txt*ファイルなしで走らせたら、`unwrap`メソッドが行う`panic!`呼び出しからのエラーメッセージを目の当たりにするでしょう: ```text -thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { -repr: Os { code: 2, message: "No such file or directory" } }', -src/libcore/result.rs:906:4 -('main'スレッドは、src/libcore/result.rs:906:4の -「`Err`値に対して`Result::unwrap()`が呼び出されました: Error{ -repr: Os { code: 2, message: "そのようなファイルまたはディレクトリはありません" } }」でパニックしました) +thread 'main' panicked at src/main.rs:4:49: +called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" } +('main'スレッドは、src/main.rs:4:49でパニックしました: +`Err`値に対して`Result::unwrap()`が呼び出されました: Os { code: 2, kind: NotFound, message: "そのようなファイルやディレクトリはありません" }) ``` -別のメソッド`expect`は、`unwrap`に似ていますが、`panic!`のエラーメッセージも選択させてくれます。 +同様に、`expect`メソッドは、`panic!`のエラーメッセージも選択させてくれます。 `unwrap`の代わりに`expect`を使用して、いいエラーメッセージを提供すると、意図を伝え、 パニックの原因をたどりやすくしてくれます。`expect`の表記はこんな感じです: @@ -428,12 +383,7 @@ panic easier. The syntax of `expect` looks like this: ファイル名: src/main.rs ```rust,should_panic -use std::fs::File; - -fn main() { - // hello.txtを開くのに失敗しました - let f = File::open("hello.txt").expect("Failed to open hello.txt"); -} +{{#rustdoc_include ../listings/ch09-error-handling/no-listing-05-expect/src/main.rs}} ``` + + `expect`を`unwrap`と同じように使用してます: ファイルハンドルを返したり、`panic!`マクロを呼び出しています。 `expect`が`panic!`呼び出しで使用するエラーメッセージは、`unwrap`が使用するデフォルトの`panic!`メッセージではなく、 `expect`に渡した引数になります。以下のようになります: ```text -thread 'main' panicked at 'Failed to open hello.txt: Error { repr: Os { code: -2, message: "No such file or directory" } }', src/libcore/result.rs:906:4 +thread 'main' panicked at src/main.rs:5:10: +hello.txt should be included in this project: Os { code: 2, kind: NotFound, message: "No such file or directory" } +('main'スレッドは、src/main.rs:5:10でパニックしました: +「hello.txtがこのプロジェクトに含まれているべきです: Os { code: 2, kind: NotFound, message: "そのようなファイルやディレクトリはありません" }) ``` -このエラーメッセージは、指定したテキストの`hello.txtを開くのに失敗しました`で始まっているので、 -コード内のどこでエラーメッセージが出力されたのかより見つけやすくなるでしょう。複数箇所で`unwrap`を使用していたら、 -ズバリどの`unwrap`がパニックを引き起こしているのか理解するのは、より時間がかかる可能性があります。 -パニックする`unwrap`呼び出しは全て、同じメッセージを出力するからです。 +製品レベルの品質のコードでは、多くのRustaceanは`unwrap`よりむしろ`expect`を選択し、 +なぜその操作が常に成功すると想定されるのかについてより多くの文脈情報を提供します。 +そうすることで、万一あなたの仮定が誤っていたと判明した場合には、 +デバッグ時に利用するためのより多くの情報が得られます。 -失敗する可能性のある何かを呼び出す実装をした関数を書く際、関数内でエラーを処理する代わりに、 +関数の実装が失敗する可能性のある何かを呼び出す際、その関数自体の中でエラーを処理する代わりに、 呼び出し元がどうするかを決められるようにエラーを返すことができます。これはエラーの*委譲*として認知され、 自分のコードの文脈で利用可能なものよりも、 エラーの処理法を規定する情報やロジックがより多くある呼び出し元のコードに制御を明け渡します。 @@ -488,7 +445,7 @@ handled than what you have available in the context of your code. 例えば、リスト9-6の関数は、ファイルからユーザ名を読み取ります。ファイルが存在しなかったり、読み込みできなければ、 @@ -500,26 +457,12 @@ to the code that called this function. ファイル名: src/main.rs -```rust -use std::io; -use std::io::Read; -use std::fs::File; - -fn read_username_from_file() -> Result { - let f = File::open("hello.txt"); - - let mut f = match f { - Ok(file) => file, - Err(e) => return Err(e), - }; + - let mut s = String::new(); - - match f.read_to_string(&mut s) { - Ok(_) => Ok(s), - Err(e) => Err(e), - } -} +```rust +{{#include ../listings/ch09-error-handling/listing-09-06/src/main.rs:here}} ``` + +この関数はもっと短く書くことができますが、エラー処理について詳しく見るために、 +まずはエラー処理をたくさん手動で書くことから始めましょう; より短い方法は最後に示します。 +まずは、関数の戻り値型に注目しましょう: `Result`です。つまり、この関数は、 +`Result`型の値を返しているということです。ここでジェネリック引数の`T`は、具体型`String`で埋められ、 +ジェネリック引数の`E`は具体型`io::Error`で埋められています。 + + -まずは、関数の戻り値型に注目してください: `Result`です。つまり、この関数は、 -`Result`型の値を返しているということです。ここでジェネリック引数の`T`は、具体型`String`で埋められ、 -ジェネリック引数の`E`は具体型`io::Error`で埋められています。この関数が何の問題もなく成功すれば、 +この関数が何の問題もなく成功すれば、 この関数を呼び出したコードは、`String`(関数がファイルから読み取ったユーザ名)を保持する`Ok`値を受け取ります。 この関数が何か問題に行き当たったら、呼び出し元のコードは`io::Error`のインスタンスを保持する`Err`値を受け取り、 この`io::Error`は問題の内容に関する情報をより多く含んでいます。関数の戻り値の型に`io::Error`を選んだのは、 @@ -556,51 +509,57 @@ function and the `read_to_string` method. -関数の本体は、`File::open`関数を呼び出すところから始まります。そして、リスト9-4の`match`に似た`match`で返ってくる`Result`値を扱い、 -`Err`ケースに`panic!`を呼び出すだけの代わりに、この関数から早期リターンしてこの関数のエラー値として、 -`File::open`から得たエラー値を呼び出し元に渡し戻します。`File::open`が成功すれば、 -ファイルハンドルを変数`f`に保管して継続します。 +関数の本体は、`File::open`関数を呼び出すところから始まります。 +そして、リスト9-4の`match`に似た`match`で`Result`値を扱います。 +`File::open`が成功すれば、パターン変数`file`にあるファイルハンドルは可変変数`username_file`内の値となり、 +関数は継続します。 +`Err`ケースでは`panic!`を呼び出す代わりに、関数から完全に早期リターンしてこの関数のエラー値として、 +`File::open`から得たエラー値、これはパターン変数`e`内にありますが、これを呼び出し元に渡し戻すために`return`キーワードを使用します。 -さらに、変数`s`に新規`String`を生成し、`f`のファイルハンドルに対して`read_to_string`を呼び出して、 -ファイルの中身を`s`に読み出します。`File::open`が成功しても、失敗する可能性があるので、`read_to_string`メソッドも、 +`username_file`にファイルハンドルが得られたら、関数は次に変数`username`に新規`String`を生成し、 +`username_file`のファイルハンドルに対して`read_to_string`を呼び出して、ファイルの中身を`username`に読み出します。 +`File::open`が成功しても、失敗する可能性があるので、`read_to_string`メソッドも、 `Result`を返却します。その`Result`を処理するために別の`match`が必要になります: `read_to_string`が成功したら、 -関数は成功し、今は`Ok`に包まれた`s`に入っているファイルのユーザ名を返却します。`read_to_string`が失敗したら、 +関数は成功し、今は`Ok`に包まれた`username`に入っているファイルのユーザ名を返却します。`read_to_string`が失敗したら、 `File::open`の戻り値を扱った`match`でエラー値を返したように、エラー値を返します。 しかし、明示的に`return`を述べる必要はありません。これが関数の最後の式だからです。 そうしたら、呼び出し元のコードは、ユーザ名を含む`Ok`値か、`io::Error`を含む`Err`値を得て扱います。 -呼び出し元のコードがそれらの値をどうするかはわかりません。呼び出しコードが`Err`値を得たら、 +それらの値をどうするかを決めるのは、呼び出し元のコードに委ねられます。呼び出しコードが`Err`値を得たら、 例えば、`panic!`を呼び出してプログラムをクラッシュさせたり、デフォルトのユーザ名を使ったり、 ファイル以外の場所からユーザ名を検索したりできるでしょう。呼び出し元のコードが実際に何をしようとするかについて、 十分な情報がないので、成功や失敗情報を全て委譲して適切に扱えるようにするのです。 @@ -613,19 +572,19 @@ question mark operator `?` to make this easier. Rustにおいて、この種のエラー委譲は非常に一般的なので、Rustにはこれをしやすくする`?`演算子が用意されています。 #### エラー委譲のショートカット: `?`演算子 -リスト9-7もリスト9-6と同じ機能を有する`read_username_from_file`の実装ですが、 -こちらは`?`演算子を使用しています: +リスト9-7はリスト9-6にあったのと同じ機能を持つ`read_username_from_file`の実装ですが、 +こちらは`?`演算子を使用しています。 + ```rust -use std::io; -use std::io::Read; -use std::fs::File; - -fn read_username_from_file() -> Result { - let mut f = File::open("hello.txt")?; - let mut s = String::new(); - f.read_to_string(&mut s)?; - Ok(s) -} +{{#include ../listings/ch09-error-handling/listing-09-07/src/main.rs:here}} ``` `Result`値の直後に置かれた`?`は、リスト9-6で`Result`値を処理するために定義した`match`式とほぼ同じように動作します。 `Result`の値が`Ok`なら、`Ok`の中身がこの式から返ってきて、プログラムは継続します。値が`Err`なら、 -`return`キーワードを使ったかのように関数全体から`Err`の中身が返ってくるので、 +`return`キーワードを使ったかのように関数全体から`Err`が返ってくるので、 エラー値は呼び出し元のコードに委譲されます。 -リスト9-6の`match`式と`?`演算子には違いがあります: `?`を使ったエラー値は、 -標準ライブラリの`From`トレイトで定義され、エラーの型を別のものに変換する`from`関数を通ることです。 +リスト9-6の`match`式がやっていることと`?`演算子がやっていることには、違いがあります: +`?`演算子が呼ばれる対象となったエラー値は、 +標準ライブラリの`From`トレイトで定義され、値を別の型に変換する`from`関数を通ることです。 `?`演算子が`from`関数を呼び出すと、受け取ったエラー型が現在の関数の戻り値型で定義されているエラー型に変換されます。これは、 個々がいろんな理由で失敗する可能性があるのにも関わらず、関数が失敗する可能性を全て一つのエラー型で表現して返す時に有用です。 -各エラー型が`from`関数を実装して返り値のエラー型への変換を定義している限り、 -`?`演算子が変換の面倒を自動的に見てくれます。 + + + +例えば、リスト9-7の`read_username_from_file`関数を、`OurError`という名前の自分で定義したカスタムエラー型を返すように変更することができます。 +さらに、`io::Error`から`OutError`のインスタンスを構築するための`impl From for OurError`を定義すれば、 +`read_username_from_file`の本体の中の`?`演算子呼び出しは`from`を呼び出してくれるので、 +関数にコードを追加する必要なくエラー型を変換してくれます。 -リスト9-7の文脈では、`File::open`呼び出し末尾の`?`は`Ok`の中身を変数`f`に返します。 +リスト9-7の文脈では、`File::open`呼び出し末尾の`?`は`Ok`の中身を変数`username_file`に返します。 エラーが発生したら、`?`演算子により関数全体から早期リターンし、あらゆる`Err`値を呼び出し元に与えます。 同じ法則が`read_to_string`呼び出し末尾の`?`にも適用されます。 @@ -715,18 +681,12 @@ method calls immediately after the `?`, as shown in Listing 9-8. ファイル名: src/main.rs -```rust -use std::io; -use std::io::Read; -use std::fs::File; - -fn read_username_from_file() -> Result { - let mut s = String::new(); + - File::open("hello.txt")?.read_to_string(&mut s)?; - - Ok(s) -} +```rust +{{#include ../listings/ch09-error-handling/listing-09-08/src/main.rs:here}} ``` -`s`の新規`String`の生成を関数の冒頭に移動しました; その部分は変化していません。変数`f`を生成する代わりに、 +`username`の新規`String`の生成を関数の冒頭に移動しました; その部分は変化していません。 +変数`username_file`を生成する代わりに、 `read_to_string`の呼び出しを直接`File::open("hello.txt")?`の結果に連結させました。 それでも、`read_to_string`呼び出しの末尾には`?`があり、`File::open`と`read_to_string`両方が成功したら、 -エラーを返すというよりもそれでも、`s`にユーザ名を含む`Ok`値を返します。機能もまたリスト9-6及び、9-7と同じです; +エラーを返すというよりもそれでも、`username`を含む`Ok`値を返します。機能もまたリスト9-6及び、9-7と同じです; ただ単に異なるバージョンのよりエルゴノミックな書き方なのです。 -#### `?`演算子は、`Result`を返す関数でしか使用できない +これを`fs::read_to_string`を使用してさらに短くする方法をリスト9-9に示します。 -`?`演算子は戻り値に`Result`を持つ関数でしか使用できません。というのも、リスト9-6で定義した`match`式と同様に動作するよう、 -定義されているからです。`Result`の戻り値型を要求する`match`の部品は、`return Err(e)`なので、 -関数の戻り値はこの`return`と互換性を保つために`Result`でなければならないのです。 +ファイル名: src/main.rs + + + +```rust +{{#include ../listings/ch09-error-handling/listing-09-09/src/main.rs:here}} +``` -`main`関数で`?`演算子を使用したらどうなるか見てみましょう。`main`関数は、戻り値が`()`でしたね: +リスト9-9: ファイルを開いて読む代わりに`fs::read_to_string`を使用する -```rust,ignore -use std::fs::File; + -fn main() { - let f = File::open("hello.txt")?; -} +ファイルを文字列に読み込むことは非常によくある操作なので、標準ライブラリは、 +ファイルを開き、新しい`String`を作成し、ファイルの内容を読み込み、内容をその`String`に格納し、それを返す、 +便利な`fs::read_to_string`関数を提供しています。そうそう、`fs::read_to_string`を使用してしまうと、 +エラー処理のすべてについて説明する機会がなくなってしまうので、長ったらしい方法を先に使ったのでした。 + + + +#### `?`演算子が使用できる場所 + + + +`?`演算子は、`?`を使用する対象の値と戻り値の型に互換性がある関数でしか使用できません。 +というのも`?`演算子は、リスト9-6で定義した`match`式と同様に関数から値の早期リターンを実行するように定義されているからです。 +リスト9-6では、`match`は`Result`値を使用して、早期リターンする側のアームは`Err(e)`値を返していました。 +関数の戻り値型はこの`return`と互換性を保てるように、`Result`でなければならないのです。 + + + +リスト9-10で、`?`を使用する対象の値の型と戻り値の型に互換性がない`main`関数で、 +`?`演算子を使用した場合に得られるエラーを見てみましょう: + + + +ファイル名: src/main.rs + +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch09-error-handling/listing-09-10/src/main.rs}} ``` + +リスト9-10: `()`を返す`main`関数内で`?`を使用しようとするとコンパイルが通らない + + +このコードはファイルを開きますが、これは失敗する可能性があります。 +`?`演算子は`File::open`によって返される`Result`値を確認して対処しますが、この`main`関数は`Result`ではなく`()`の戻り値型を持っています。 このコードをコンパイルすると、以下のようなエラーメッセージが得られます: -```text -error[E0277]: the trait bound `(): std::ops::Try` is not satisfied -(エラー: `(): std::ops::Try`というトレイト境界が満たされていません) - --> src/main.rs:4:13 - | -4 | let f = File::open("hello.txt")?; - | ------------------------ - | | - | the `?` operator can only be used in a function that returns - `Result` (or another type that implements `std::ops::Try`) - | in this macro invocation - | (このマクロ呼び出しの`Result`(かまたは`std::ops::Try`を実装する他の型)を返す関数でしか`?`演算子は使用できません) - | - = help: the trait `std::ops::Try` is not implemented for `()` - (助言: `std::ops::Try`トレイトは`()`には実装されていません) - = note: required by `std::ops::Try::from_error` - (注釈: `std::ops::Try::from_error`で要求されています) +```console +{{#include ../listings/ch09-error-handling/listing-09-10/output.txt}} ``` + +このエラーは、`?`演算子は`Result`、`Option`、またはその他`FromResidual`を実装する型を返す関数でしか使用が許可されないと指摘しています。 + + + +このエラーを修正する方法としては、二つの選択肢があります。 +一つは、それを阻害する制限がない場合は、関数の戻り値型を、`?`演算子を使用する対象の値と互換性があるような型に変更することです。 +もう一つの手法は、`match`または`Result`のメソッドのいずれかを使用して、何らかの適切な方法で`Result`を処理することです。 + + + +エラーメッセージは、`?`は`Option`値にも使用できることに言及しています。 +`Result`に`?`を使用する場合と同様に、`Option`を返す関数の中でのみ、`Option`に`?`を使用することができます。 +`Option`に対して呼ばれた場合の`?`演算子の挙動は、`Result`に対して呼ばれた場合の挙動と似ています: +もしその値が`None`ならば、その時点で`None`が関数から早期リターンされます。 +もしその値が`Some`ならば、`Some`の内側の値がその式の結果の値となり、関数は継続します。 +リスト9-11は、与えられたテキストの最初の行の最後の文字を探索する関数の例です: + +```rust +{{#rustdoc_include ../listings/ch09-error-handling/listing-09-11/src/main.rs:here}} +``` + + + +リスト9-11: `Option`値に対する`?`演算子の使用 + + + +この関数は、文字はあるかもしれないし、ないかもしれないので、`Option`を返します。 +このコードは`text`文字列スライス引数を受け取り、それに対して`lines`メソッドを呼び出します。 +これは文字列内の行を走査するイテレータを返します。この関数では最初の行を確認したいので、 +イテレータに対して`next`を呼び出してイテレータから最初の値を取得します。 +`text`が空文字列の場合は、この`next`呼び出しは`None`を返すでしょう。 +その場合は`?`を使用して停止し、`last_char_of_first_line`から`None`を返します。 +`text`が空文字列でない場合は、`next`は`text`内の最初の行の文字列スライスを含む`Some`値を返すでしょう。 + + + +`?`が文字列スライスを抽出するので、その文字列スライスに対して`chars`を呼び出して、含まれる文字からなるイテレータを得ることができます。 +最初の行の最後の文字に関心があるので、このイテレータの最後の要素を返すために`last`を呼び出します。 +例えば`text`が空行で始まるが他の行には文字が含まれる`"\nhi"`のような文字列の場合、 +最初の行が空文字列である可能性があるので、この戻り値は`Option`になっています。 +しかしながら、最初の行の最後の文字がある場合は、それを`Some`列挙子に入れて返します。 +中間の`?`演算子はこのロジックを簡潔に表現する方法を提供し、そのためこの関数を一行で実装することができています。 +もし`?`演算子が`Option`に使用できなかったなら、より多くのメソッド呼び出しや`match`式を使用してこのロジックを実装する必要があったでしょう。 + + + +`Result`を返す関数内では`Result`に対して`?`演算子を使用でき、`Option`を返す関数内では`Option`に対して`?`演算子を使用できますが、 +混ぜて組み合わせることはできないことに注意してください。 +`?`演算子は、`Result`を`Option`に、またはその逆に、自動的に変換することはしません; +そのような場合には明示的に変換を行うために、`Result`の`ok`メソッドや、`Option`の`ok_or`メソッドのようなメソッドを使用することができます。 + + + +今までに使ってきた`main`関数はすべて`()`を返してきました。 +`main`関数は、実行可能なプログラムの開始および終了点であることから特別扱いされており、 +プログラムが期待通りに振る舞うために、その戻り値型として指定できる型に制限があります。 + + + +幸運なことに、`main`は`Result<(), E>`を返すこともできます。 +リスト9-12はリスト9-10のコードを含んでいますが、`main`の戻り値型を`Result<(), Box>`に変更し、 +最後に戻り値`Ok(())`を追加しています。 +これでこのコードはコンパイルできるでしょう: + +```rust,ignore +{{#rustdoc_include ../listings/ch09-error-handling/listing-09-12/src/main.rs}} +``` + + + +リスト9-12: `Result<(), E>`を返すように`main`を変更することで、`Result`値に対する`?`演算子が使用可能になる + + -このエラーは、`?`演算子は`Result`を返す関数でしか使用が許可されないと指摘しています。 `Result`を返さない関数では、`Result`を返す別の関数を呼び出した時、 `?`演算子を使用してエラーを呼び出し元に委譲する可能性を生み出す代わりに、`match`か`Result`のメソッドのどれかを使う必要があるでしょう。 + + +`Box`型は*トレイトオブジェクト*ですが、これについては第17章の[「トレイトオブジェクトで異なる型の値を許容する」][trait-objects]節で話します。 +今のところは、`Box`は「任意の種類のエラー」を意味するものと理解してください。 +エラー型`Box`を持つ`main`関数の中では、任意の`Err`値を早期リターンすることができるので、`Result`値に対する`?`の使用が許可されます。 +この`main`関数の本体は型`std::io::Error`のエラーしか返しませんが、それでも`Box`を指定することにより、 +他のエラーを返すコードが`main`の本体に追加された場合であっても、このシグネチャは正しいままであり続けるでしょう。 + + + +`main`関数が`Result<(), E>`を返す場合、その実行可能ファイルは、 +`main`が`Ok(())`を返す場合には値`0`で終了し、`main`が`Err`値を返す場合は非ゼロ値で終了するでしょう。 +Cで書かれた実行可能ファイルは終了時に整数を返します: +正常終了するプログラムは整数`0`を返し、エラーが発生したプログラムは`0`以外の整数を返します。 +Rustもこの慣例に従い、実行可能ファイルから整数を返します。 + + + +`main`関数は[`std::process::Termination`トレイト][termination]を実装する任意の型を返すことができます。 +このトレイトには`ExitCode`を返す`report`関数が含まれます。 +自身の型に対する`Termination`トレイトの実装に関するさらなる情報については、 +標準ライブラリドキュメントを確認してください。 + + +[handle_failure]: ch02-00-guessing-game-tutorial.html#resultで失敗の可能性を扱う +[trait-objects]: ch17-02-trait-objects.html#トレイトオブジェクトで異なる型の値を許容する +[termination]: https://doc.rust-lang.org/std/process/trait.Termination.html diff --git a/src/ch09-03-to-panic-or-not-to-panic.md b/src/ch09-03-to-panic-or-not-to-panic.md index 0aca603ba..91f59d6fd 100644 --- a/src/ch09-03-to-panic-or-not-to-panic.md +++ b/src/ch09-03-to-panic-or-not-to-panic.md @@ -5,39 +5,36 @@ ## `panic!`すべきかするまいか -では、`panic!`すべき時と`Result`を返すべき時はどう決定すればいいのでしょうか?コードがパニックしたら、 +では、`panic!`を呼ぶべき時と`Result`を返すべき時はどう決定すればいいのでしょうか?コードがパニックしたら、 回復する手段はありません。回復する可能性のある手段の有る無しに関わらず、どんなエラー場面でも`panic!`を呼ぶことはできますが、 -そうすると、呼び出す側のコードの立場に立ってこの場面は回復不能だという決定を下すことになります。 -`Result`値を返す決定をすると、決断を下すのではなく、呼び出し側に選択肢を与えることになります。 +そうすると、呼び出す側のコードに代わってこの場面は回復不能だという決定を下すことになります。 +`Result`値を返す決定をすると、呼び出し側に選択肢を与えることになります。 呼び出し側は、場面に合わせて回復を試みることを決定したり、この場合の`Err`値は回復不能と断定して、 `panic!`を呼び出し、回復可能だったエラーを回復不能に変換することもできます。故に、`Result`を返却することは、 失敗する可能性のある関数を定義する際には、いい第一選択肢になります。 -稀な場面では、`Result`を返すよりもパニックするコードを書く方がより適切になることもあります。 -例やプロトタイプコード、テストでパニックするのが適切な理由を探ってみましょう。 -それからコンパイラではありえない失敗だと気づけなくとも、人間なら気づける場面を議論しましょう。 +例やプロトタイプコード、テストなどの場面では、`Result`を返すよりもパニックするコードを書く方がより適切になることもあります。 +その理由を探ってみて、それからコンパイラではありえない失敗だと気づけなくとも、人間なら気づける場面を議論しましょう。 そして、ライブラリコードでパニックするか決定する方法についての一般的なガイドラインで結論づけましょう。 -例を記述して何らかの概念を具体化している時、頑健なエラー処理コードも例に含むことは、例の明瞭さを欠くことになりかねません。 +例を記述して何らかの概念を具体化している時、頑健なエラー処理コードを含めることは、例の明瞭さを欠くことになりかねません。 例において、`unwrap`などのパニックする可能性のあるメソッド呼び出しは、 アプリケーションにエラーを処理してほしい方法へのプレースホルダーを意味していると理解され、 これは残りのコードがしていることによって異なる可能性があります。 @@ -69,7 +66,7 @@ your code for when you’re ready to make your program more robust. 非常に便利です。それらにより、コードにプログラムをより頑健にする時の明らかなマーカーが残されるわけです。 -`Result`が`Ok`値であると確認する何らかの別のロジックがある場合、`unwrap`を呼び出すことは適切でしょうが、 +`Result`が`Ok`値であることを保証する何らかの別のロジックがある場合、`unwrap`または`except`を呼び出すことは適切でしょうが、 コンパイラは、そのロジックを理解はしません。それでも、処理する必要のある`Result`は存在するでしょう: 呼び出している処理が何であれ、自分の特定の場面では論理的に起こり得なくても、一般的にまだ失敗する可能性はあるわけです。 手動でコードを調査して`Err`列挙子は存在しないと確認できたら、`unwrap`を呼び出すことは完全に受容できることです。 +決して`Err`列挙子にならないと考える理由を`expect`のテキストに文書化すると、さらに良いでしょう。 こちらが例です: ```rust -use std::net::IpAddr; - -let home: IpAddr = "127.0.0.1".parse().unwrap(); +{{#rustdoc_include ../listings/ch09-error-handling/no-listing-08-unwrap-that-cant-fail/src/main.rs:here}} ``` ハードコードされた文字列を構文解析することで`IpAddr`インスタンスを生成しています。 -プログラマには`127.0.0.1`が合法なIPアドレスであることがわかるので、ここで`unwrap`を使用することは、 +プログラマには`127.0.0.1`が合法なIPアドレスであることがわかるので、ここで`expect`を使用することは、 受容可能なことです。しかしながら、ハードコードされた合法な文字列が存在することは、 `parse`メソッドの戻り値型を変えることにはなりません: それでも得られるのは、`Result`値であり、 -コンパイラはまだ`Err`列挙子になる可能性があるかのように`Result`を処理することを強制してきます。 +コンパイラは`Err`列挙子になる可能性があるかのように`Result`を処理することを強制してきます。 コンパイラは、この文字列が常に合法なIPアドレスであると把握できるほど利口ではないからです。 プログラムにハードコードされるのではなく、IPアドレス文字列がユーザ起源でそれ故に*確かに*失敗する可能性がある場合、 `Result`をもっと頑健な方法で処理したほうが絶対にいいでしょう。 +このIPアドレスはハードコードされたものだという想定に言及することで、もし将来IPアドレスを他の情報源から取得する必要がでてきた場合、 +`expect`の部分をよりよいエラー処理コードに変更することが促されるでしょう。 -コードが悪い状態に陥る可能性があるときにパニックさせるのは、推奨されることです。この文脈において、 -*悪い状態*とは、何らかの前提、保証、契約、不変性が破られたことを言い、例を挙げれば、無効な値、 -矛盾する値、行方不明な値がコードに渡されることと、さらに以下のいずれか一つ以上の状態であります: +コードが悪い状態に陥る可能性があるときには、パニックさせることが推奨されます。 +この文脈での*悪い状態*とは、無効な値、矛盾する値、欠けた値が自身のコードに渡されるなど、何らかの仮定、保証、契約、不変条件が破られることに加え、 +以下のいずれか一つ以上に当てはまる状態のことです: -* 悪い状態がときに起こるとは*予想*されないとき。 -* この時点以降、この悪い状態にないことを頼りにコードが書かれているとき。 -* 使用している型にこの情報をコード化するいい手段がないとき。 +* 悪い状態は、予期されていない何かです。ユーザが誤ったフォーマットでデータを入力することなどの、場合によっては起こりうることとは異なります。 +* この時点以降の自身のコードは、各段階で問題が無いか確認するのではなく、この悪い状態にないことに依存する必要があります。 +* 使用している型にこの情報をコード化するいい手段がありません。これが意味するところの例は、第17章の[「状態と振る舞いを型としてコード化する」][encoding]節で取り組みます。 -誰かが自分のコードを呼び出して筋の通らない値を渡してきたら、最善の選択肢は`panic!`し、 +誰かが自分のコードを呼び出して意味をなさない値を渡してきた場合は、可能であれば、 +ライブラリの利用者がその場合にどうしたいのかを決定できるように、エラーを返すのが最もよいでしょう。 +ですが、実行を継続するのが安全でなかったり有害かもしれない場合は、最善の選択肢は`panic!`を呼び出し、 開発段階で修正できるように自分たちのコードにバグがあることをライブラリ使用者に通知することかもしれません。 同様に自分の制御下にない外部コードを呼び出し、修正しようのない無効な状態を返すときに`panic!`はしばしば適切です。 - -しかし、どんなにコードをうまく書いても起こると予想されますが、悪い状態に達したとき、それでも`panic!`呼び出しをするよりも、 -`Result`を返すほうがより適切です。例には、不正なデータを渡されたパーサとか、 -訪問制限に引っかかったことを示唆するステータスを返すHTTPリクエストなどが挙げられます。 -このような場合には、呼び出し側が問題の処理方法を決定できるように`Result`を返してこの悪い状態を委譲して、 -失敗が予想される可能性であることを示唆するべきです。`panic!`を呼び出すことは、 -これらのケースでは最善策ではないでしょう。 - - - -コードが値に対して処理を行う場合、コードはまず値が合法であることを確認し、 +However, when failure is expected, it’s more appropriate to return a `Result` +than to make a `panic!` call. Examples include a parser being given malformed +data or an HTTP request returning a status that indicates you have hit a rate +limit. In these cases, returning a `Result` indicates that failure is an +expected possibility that the calling code must decide how to handle. +--> + +しかしながら、失敗が予測できる場合は、`panic!`呼び出しをするよりも`Result`を返すほうがより適切です。 +その例には、不正なデータを渡されたパーサとか、 +レートリミットに引っかかったことを示唆するステータスを返すHTTPリクエストなどが挙げられます。 +このような場合では`Result`を返すことで、失敗は、呼び出し側が処理方法を決定しなくてはならない、 +予測できる可能性であることが示されます。 + + + +あなたのコードが、不正な値を使用して呼ばれるとユーザを危険に晒すおそれのある処理を行う場合、コードはまず値が合法であることを確認し、 値が合法でなければパニックするべきです。これはほぼ安全性上の理由によるものです: 不正なデータの処理を試みると、 コードを脆弱性に晒す可能性があります。これが、境界外へのメモリアクセスを試みたときに標準ライブラリが`panic!`を呼び出す主な理由です: 現在のデータ構造に属しないメモリにアクセスを試みることは、ありふれたセキュリティ問題なのです。 @@ -217,20 +225,20 @@ documentation for the function. ですが、全ての関数でたくさんのエラーチェックを行うことは冗長で煩わしいことでしょう。幸運にも、 -Rustの型システム(故にコンパイラが行う型精査)を使用して多くの検査を行ってもらうことができます。 +Rustの型システム(故にコンパイラによって行われる型精査)を使用して多くの検査を行ってもらうことができます。 関数の引数に特定の型があるなら、合法な値があるとコンパイラがすでに確認していることを把握して、 コードのロジックに進むことができます。例えば、`Option`以外の型がある場合、プログラムは、 *何もない*ではなく*何かある*と想定します。そうしたらコードは、 @@ -252,7 +260,7 @@ guessing game in Chapter 2 in which our code asked the user to guess a number between 1 and 100. We never validated that the user’s guess was between those numbers before checking it against our secret number; we only validated that the guess was positive. In this case, the consequences were not very dire: our -output of “Too high” or “Too low” would still be correct. It would be a +output of “Too high” or “Too low” would still be correct. But it would be a useful enhancement to guide the user toward valid guesses and have different behavior when a user guesses a number that’s out of range versus when a user types, for example, letters instead. @@ -263,7 +271,7 @@ Rustの型システムを使用して合法な値があると確認するとい コードがユーザに1から100までの数字を推測するよう求めたことを思い出してください。 秘密の数字と照合する前にユーザの推測がそれらの値の範囲にあることを全く確認しませんでした; 推測が正であることしか確認しませんでした。この場合、結果はそれほど悲惨なものではありませんでした: -「大きすぎ」、「小さすぎ」という出力は、それでも正しかったでしょう。ユーザを合法な推測に導き、 +「大きすぎ」、「小さすぎ」という出力は、それでも正しかったでしょう。しかし、ユーザを合法な推測に導き、 ユーザが範囲外の数字を推測したり、例えばユーザが文字を代わりに入力したりしたときに別の挙動をするようにしたら、 有益な改善になるでしょう。 @@ -277,22 +285,7 @@ number being in range, like so: それから数字が範囲に収まっているというチェックを追加することでしょう。そう、以下のように: ```rust,ignore -loop { - // --snip-- - - let guess: i32 = match guess.trim().parse() { - Ok(num) => num, - Err(_) => continue, - }; - - if guess < 1 || guess > 100 { - println!("The secret number will be between 1 and 100."); - continue; - } - - match guess.cmp(&secret_number) { - // --snip-- -} +{{#rustdoc_include ../listings/ch09-error-handling/no-listing-09-guess-out-of-range/src/main.rs:here}} ``` 代わりに、新しい型を作って検証を関数内に閉じ込め、検証を全箇所で繰り返すのではなく、 その型のインスタンスを生成することができます。そうすれば、関数がその新しい型をシグニチャに用い、 -受け取った値を自信を持って使用することは安全になります。リスト9-9に、`new`関数が1から100までの値を受け取った時のみ、 +受け取った値を自信を持って使用することは安全になります。リスト9-13に、`new`関数が1から100までの値を受け取った時のみ、 `Guess`のインスタンスを生成する`Guess`型を定義する一つの方法を示しました。 + + ```rust -pub struct Guess { - value: u32, -} - -impl Guess { - pub fn new(value: u32) -> Guess { - if value < 1 || value > 100 { - // 予想の値は1から100の範囲でなければなりませんが、{}でした - panic!("Guess value must be between 1 and 100, got {}.", value); - } - - Guess { - value - } - } - - pub fn value(&self) -> u32 { - self.value - } -} +{{#include ../listings/ch09-error-handling/listing-09-13/src/main.rs:here}} ``` -リスト9-9: 値が1から100の場合のみ処理を継続する`Guess`型 +リスト9-13: 値が1から100の場合のみ処理を継続する`Guess`型 -まず、`u32`型の`value`をフィールドに持つ`Guess`という名前の構造体を定義しています。 +まず、`i32`型の`value`をフィールドに持つ`Guess`という名前の構造体を定義しています。 ここに数値が保管されます。 それから`Guess`に`Guess`値のインスタンスを生成する`new`という名前の関連関数を実装しています。 -`new`関数は、`u32`型の`value`という引数を取り、`Guess`を返すように定義されています。 +`new`関数は、`i32`型の`value`という引数を取り、`Guess`を返すように定義されています。 `new`関数の本体のコードは、`value`をふるいにかけ、1から100の範囲であることを確かめます。 `value`がふるいに引っかかったら、`panic!`呼び出しを行います。これにより、呼び出しコードを書いているプログラマに、 修正すべきバグがあると警告します。というのも、この範囲外の`value`で`Guess`を生成することは、 @@ -397,17 +376,17 @@ to the `value` parameter and return the `Guess`. -次に、`self`を借用し、他に引数はなく、`u32`を返す`value`というメソッドを実装します。 +次に、`self`を借用し、他に引数はなく、`i32`を返す`value`というメソッドを実装します。 この類のメソッドは時に*ゲッター*と呼ばれます。目的がフィールドから何らかのデータを得て返すことだからです。 この公開メソッドは、`Guess`構造体の`value`フィールドが非公開なので、必要になります。 `value`フィールドが非公開なことは重要であり、そのために`Guess`構造体を使用するコードは、 @@ -417,11 +396,11 @@ hasn’t been checked by the conditions in the `Guess::new` function. -そうしたら、引数を一つ持つか、1から100の範囲の数値のみを返す関数は、シグニチャで`u32`ではなく、 +そうしたら、引数を一つ持つか、1から100の範囲の数値のみを返す関数は、シグニチャで`i32`ではなく、 `Guess`を取るか返し、本体内で追加の確認を行う必要はなくなると宣言できるでしょう。 + +[encoding]: ch17-03-oo-design-patterns.html#状態と振る舞いを型としてコード化する From 4eabca9e3c54be198509c5559666bc2ee73bfaef Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:04 +0900 Subject: [PATCH 11/22] =?UTF-8?q?ch10=20=E3=82=B8=E3=82=A7=E3=83=8D?= =?UTF-8?q?=E3=83=AA=E3=83=83=E3=82=AF=E5=9E=8B=E3=80=81=E3=83=88=E3=83=AC?= =?UTF-8?q?=E3=82=A4=E3=83=88=E3=80=81=E3=83=A9=E3=82=A4=E3=83=95=E3=82=BF?= =?UTF-8?q?=E3=82=A4=E3=83=A0=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-10-01/Cargo.toml | 3 +- .../listing-10-01/src/main.rs | 7 +- .../listing-10-02/Cargo.toml | 3 +- .../listing-10-02/src/main.rs | 8 +- .../listing-10-03/Cargo.toml | 3 +- .../listing-10-03/src/main.rs | 4 +- .../listing-10-04/Cargo.toml | 3 +- .../listing-10-04/src/main.rs | 4 +- .../listing-10-05/Cargo.toml | 3 +- .../listing-10-05/output.txt | 19 +- .../listing-10-05/src/main.rs | 2 +- .../listing-10-06/Cargo.toml | 3 +- .../listing-10-07/Cargo.toml | 3 +- .../listing-10-07/output.txt | 7 +- .../listing-10-08/Cargo.toml | 3 +- .../listing-10-09/Cargo.toml | 3 +- .../listing-10-10/Cargo.toml | 3 +- .../listing-10-11/Cargo.toml | 3 +- .../listing-10-11/src/main.rs | 10 +- .../listing-10-12/Cargo.lock | 5 +- .../listing-10-12/Cargo.toml | 5 +- .../listing-10-13/Cargo.lock | 5 +- .../listing-10-13/Cargo.toml | 5 +- .../listing-10-14/Cargo.lock | 5 +- .../listing-10-14/Cargo.toml | 5 +- .../listing-10-15/Cargo.toml | 3 +- .../src/lib.rs | 0 .../listing-10-15/src/main.rs | 23 - .../listing-10-16/Cargo.toml | 3 +- .../listing-10-16/output.txt | 22 + .../listing-10-16/src/main.rs | 10 + .../listing-10-17/Cargo.lock | 2 - .../listing-10-17/Cargo.toml | 3 +- .../listing-10-17/output.txt | 23 - .../rustfmt-ignore | 0 .../listing-10-17/src/main.rs | 22 +- .../listing-10-18/Cargo.toml | 3 +- .../listing-10-18/src/main.rs | 20 +- .../listing-10-19/Cargo.lock | 2 + .../listing-10-19/Cargo.toml | 3 +- .../listing-10-19/src/main.rs | 16 +- .../listing-10-20/Cargo.toml | 3 +- .../listing-10-20/output.txt | 20 + .../listing-10-20/src/main.rs | 11 +- .../listing-10-21/Cargo.toml | 3 +- .../listing-10-21/output.txt | 20 - .../listing-10-21/src/main.rs | 2 +- .../listing-10-22/Cargo.toml | 3 +- .../listing-10-22/src/main.rs | 17 +- .../listing-10-23/Cargo.toml | 3 +- .../output.txt | 8 +- .../listing-10-23/src/main.rs | 9 +- .../listing-10-24/Cargo.toml | 3 +- .../listing-10-24/src/main.rs | 24 +- .../listing-10-25/Cargo.lock | 2 +- .../listing-10-25/Cargo.toml | 5 +- .../listing-10-25/src/main.rs | 34 +- .../listing-10-26/Cargo.lock | 6 - .../listing-10-26/Cargo.toml | 7 - .../listing-10-26/src/main.rs | 29 -- .../Cargo.lock | 5 +- .../Cargo.toml | 5 +- .../src/main.rs | 4 +- .../Cargo.lock | 5 +- .../Cargo.toml | 5 +- .../src/main.rs | 2 +- .../Cargo.lock | 5 +- .../Cargo.toml | 5 +- .../src/main.rs | 2 +- .../Cargo.lock | 5 +- .../Cargo.toml | 5 +- .../Cargo.lock | 5 +- .../Cargo.toml | 5 +- .../Cargo.lock | 5 +- .../Cargo.toml | 5 +- .../Cargo.lock | 6 - .../Cargo.toml | 7 - .../output.txt | 37 -- .../src/main.rs | 25 - .../no-listing-07-where-clause/Cargo.toml | 8 + .../no-listing-07-where-clause/src/lib.rs | 9 + .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../output.txt | 12 +- .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- src/ch10-00-generics.md | 216 ++++----- src/ch10-01-syntax.md | 399 ++++++--------- src/ch10-02-traits.md | 409 ++++++---------- src/ch10-03-lifetime-syntax.md | 456 +++++++++--------- 90 files changed, 865 insertions(+), 1287 deletions(-) rename listings/ch10-generic-types-traits-and-lifetimes/{listing-10-16 => listing-10-15}/src/lib.rs (100%) delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/main.rs create mode 100644 listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/output.txt create mode 100644 listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/main.rs delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/output.txt rename listings/ch10-generic-types-traits-and-lifetimes/{listing-10-19 => listing-10-17}/rustfmt-ignore (100%) create mode 100644 listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/output.txt delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/output.txt rename listings/ch10-generic-types-traits-and-lifetimes/{listing-10-24 => listing-10-23}/output.txt (75%) delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/Cargo.lock delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/Cargo.toml delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/src/main.rs delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/Cargo.lock delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/Cargo.toml delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt delete mode 100644 listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/src/main.rs create mode 100644 listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/Cargo.toml create mode 100644 listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/src/lib.rs diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-01/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-01/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-01/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-01/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-01/src/main.rs index d2ba23b4a..e91166d2e 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-01/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-01/src/main.rs @@ -2,17 +2,18 @@ fn main() { let number_list = vec![34, 50, 25, 100, 65]; - let mut largest = number_list[0]; + let mut largest = &number_list[0]; - for number in number_list { + for number in &number_list { if number > largest { largest = number; } } + // "最大値は{}です" println!("The largest number is {}", largest); // ANCHOR_END: here - assert_eq!(largest, 100); + assert_eq!(*largest, 100); // ANCHOR: here } // ANCHOR_END: here diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-02/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-02/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-02/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-02/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-02/src/main.rs index 9138dfcb4..8c523a8be 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-02/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-02/src/main.rs @@ -1,9 +1,9 @@ fn main() { let number_list = vec![34, 50, 25, 100, 65]; - let mut largest = number_list[0]; + let mut largest = &number_list[0]; - for number in number_list { + for number in &number_list { if number > largest { largest = number; } @@ -13,9 +13,9 @@ fn main() { let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8]; - let mut largest = number_list[0]; + let mut largest = &number_list[0]; - for number in number_list { + for number in &number_list { if number > largest { largest = number; } diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-03/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-03/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-03/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-03/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-03/src/main.rs index 9d8d9bfb5..899222909 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-03/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-03/src/main.rs @@ -17,7 +17,7 @@ fn main() { let result = largest(&number_list); println!("The largest number is {}", result); // ANCHOR_END: here - assert_eq!(result, &100); + assert_eq!(*result, 100); // ANCHOR: here let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8]; @@ -25,7 +25,7 @@ fn main() { let result = largest(&number_list); println!("The largest number is {}", result); // ANCHOR_END: here - assert_eq!(result, &6000); + assert_eq!(*result, 6000); // ANCHOR: here } // ANCHOR_END: here diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-04/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-04/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-04/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-04/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-04/src/main.rs index 3e2f98aab..a47e3f232 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-04/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-04/src/main.rs @@ -29,7 +29,7 @@ fn main() { let result = largest_i32(&number_list); println!("The largest number is {}", result); // ANCHOR_END: here - assert_eq!(result, &100); + assert_eq!(*result, 100); // ANCHOR: here let char_list = vec!['y', 'm', 'a', 'q']; @@ -37,7 +37,7 @@ fn main() { let result = largest_char(&char_list); println!("The largest char is {}", result); // ANCHOR_END: here - assert_eq!(result, &'y'); + assert_eq!(*result, 'y'); // ANCHOR: here } // ANCHOR_END: here diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt index 65498128d..8f209cfbe 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt @@ -1,18 +1,19 @@ $ cargo run Compiling chapter10 v0.1.0 (file:///projects/chapter10) -error[E0369]: binary operation `>` cannot be applied to type `T` +error[E0369]: binary operation `>` cannot be applied to type `&T` +(エラー: 2項演算`>`は、型`&T`に適用できません) --> src/main.rs:5:17 | 5 | if item > largest { - | ---- ^ ------- T + | ---- ^ ------- &T | | - | T + | &T | - = note: `T` might need a bound for `std::cmp::PartialOrd` - -error: aborting due to previous error +help: consider restricting type parameter `T` +(ヘルプ: 型引数`T`を制約することを考慮してください) + | +1 | fn largest(list: &[T]) -> &T { + | ++++++++++++++++++++++ For more information about this error, try `rustc --explain E0369`. -error: could not compile `chapter10`. - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` (bin "chapter10") due to 1 previous error diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs index 814fddc50..df33743f7 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs @@ -1,5 +1,5 @@ fn largest(list: &[T]) -> &T { - let mut largest = list[0]; + let mut largest = &list[0]; for item in list { if item > largest { diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-06/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-06/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-06/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/output.txt b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/output.txt index 4a67e1b59..72ec7e339 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/output.txt +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/output.txt @@ -1,14 +1,11 @@ $ cargo run Compiling chapter10 v0.1.0 (file:///projects/chapter10) error[E0308]: mismatched types +(エラー: 型が合いません) --> src/main.rs:7:38 | 7 | let wont_work = Point { x: 5, y: 4.0 }; | ^^^ expected integer, found floating-point number -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `chapter10`. - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` (bin "chapter10") due to 1 previous error diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-08/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-08/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-08/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-09/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-09/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-09/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-10/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-10/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-10/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/src/main.rs index 4a08d1a8d..86b028108 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/src/main.rs @@ -1,10 +1,10 @@ -struct Point { - x: T, - y: U, +struct Point { + x: X1, + y: Y1, } -impl Point { - fn mixup(self, other: Point) -> Point { +impl Point { + fn mixup(self, other: Point) -> Point { Point { x: self.x, y: other.y, diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/Cargo.lock index e8007a19b..2835471f0 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "chapter10" +name = "aggregator" version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/Cargo.toml index 6d5a0ff1d..46f46a7f4 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "aggregator" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/Cargo.lock index e8007a19b..2835471f0 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "chapter10" +name = "aggregator" version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/Cargo.toml index 6d5a0ff1d..46f46a7f4 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "aggregator" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/Cargo.lock index e8007a19b..2835471f0 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "chapter10" +name = "aggregator" version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/Cargo.toml index 6d5a0ff1d..46f46a7f4 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "aggregator" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/lib.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/lib.rs similarity index 100% rename from listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/lib.rs rename to listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/lib.rs diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/main.rs deleted file mode 100644 index 7aa6a3bd2..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/main.rs +++ /dev/null @@ -1,23 +0,0 @@ -fn largest(list: &[T]) -> T { - let mut largest = list[0]; - - for &item in list { - if item > largest { - largest = item; - } - } - - largest -} - -fn main() { - let number_list = vec![34, 50, 25, 100, 65]; - - let result = largest(&number_list); - println!("The largest number is {}", result); - - let char_list = vec!['y', 'm', 'a', 'q']; - - let result = largest(&char_list); - println!("The largest char is {}", result); -} diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/output.txt b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/output.txt new file mode 100644 index 000000000..fd617e751 --- /dev/null +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/output.txt @@ -0,0 +1,22 @@ +$ cargo run + Compiling chapter10 v0.1.0 (file:///projects/chapter10) +error[E0597]: `x` does not live long enough +(エラー[E0597]: `x`の生存期間が短すぎます) + --> src/main.rs:6:13 + | +5 | let x = 5; + | - binding `x` declared here + | (束縛`x`はここで宣言されています) +6 | r = &x; + | ^^ borrowed value does not live long enough + | (借用された値の生存期間が短すぎます) +7 | } + | - `x` dropped here while still borrowed + | (`x`は借用されている間にここでドロップされました) +8 | +9 | println!("r: {}", r); + | - borrow later used here + | (その後、借用はここで使われています) + +For more information about this error, try `rustc --explain E0597`. +error: could not compile `chapter10` (bin "chapter10") due to 1 previous error diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/main.rs new file mode 100644 index 000000000..d71134ea0 --- /dev/null +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/main.rs @@ -0,0 +1,10 @@ +fn main() { + let r; + + { + let x = 5; + r = &x; + } + + println!("r: {}", r); +} diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/Cargo.lock index e8007a19b..6388bb2b5 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/Cargo.lock @@ -1,5 +1,3 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. [[package]] name = "chapter10" version = "0.1.0" diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/output.txt b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/output.txt deleted file mode 100644 index e95702e78..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/output.txt +++ /dev/null @@ -1,23 +0,0 @@ -$ cargo run - Compiling chapter10 v0.1.0 (file:///projects/chapter10) -error[E0597]: `x` does not live long enough -(エラー[E0597]: `x`の生存期間が短すぎます) - --> src/main.rs:7:17 - | -7 | r = &x; - | ^^ borrowed value does not live long enough - | (借用された値の生存期間が短すぎます) -8 | } - | - `x` dropped here while still borrowed - | (`x`は借用されている間にここでドロップされました) -9 | -10 | println!("r: {}", r); - | - borrow later used here - | (その後、借用はここで使われています) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. -error: could not compile `chapter10`. - -To learn more, run the command again with --verbose. diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/rustfmt-ignore b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/rustfmt-ignore similarity index 100% rename from listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/rustfmt-ignore rename to listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/rustfmt-ignore diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/src/main.rs index 16adb6a0d..e8ca92328 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/src/main.rs @@ -1,14 +1,10 @@ fn main() { - // ANCHOR: here - { - let r; - - { - let x = 5; - r = &x; - } - - println!("r: {}", r); - } - // ANCHOR_END: here -} + let r; // ---------+-- 'a + // | + { // | + let x = 5; // -+-- 'b | + r = &x; // | | + } // -+ | + // | + println!("r: {}", r); // | +} // ---------+ diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/src/main.rs index 65dbf375a..09ae3919c 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/src/main.rs @@ -1,14 +1,8 @@ fn main() { - // ANCHOR: here - { - let r; // ---------+-- 'a - // | - { // | - let x = 5; // -+-- 'b | - r = &x; // | | - } // -+ | - // | - println!("r: {}", r); // | - } // ---------+ - // ANCHOR_END: here -} + let x = 5; // ----------+-- 'b + // | + let r = &x; // --+-- 'a | + // | | + println!("r: {}", r); // | | + // --+ | +} // ----------+ diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/Cargo.lock index 6388bb2b5..e8007a19b 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "chapter10" version = "0.1.0" diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/src/main.rs index 94e70f00f..e1a830aad 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/src/main.rs @@ -1,12 +1,8 @@ fn main() { - // ANCHOR: here - { - let x = 5; // ----------+-- 'b - // | - let r = &x; // --+-- 'a | - // | | - println!("r: {}", r); // | | - // --+ | - } // ----------+ - // ANCHOR_END: here + let string1 = String::from("abcd"); + let string2 = "xyz"; + + let result = longest(string1.as_str(), string2); + // 最長の文字列は、{}です + println!("The longest string is {}", result); } diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/output.txt b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/output.txt new file mode 100644 index 000000000..ae5d43494 --- /dev/null +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/output.txt @@ -0,0 +1,20 @@ +$ cargo run + Compiling chapter10 v0.1.0 (file:///projects/chapter10) +error[E0106]: missing lifetime specifier +(エラー[E0106]: ライフタイム指定子が不足しています) + --> src/main.rs:9:33 + | +9 | fn longest(x: &str, y: &str) -> &str { + | ---- ---- ^ expected named lifetime parameter + | (名前付きライフタイム引数があるべきです) + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` + (ヘルプ: この関数の戻り値型は借用された値を含んでいますが、シグネチャは、それが`x`と`y`どちらから借用されたものなのか宣言していません) +help: consider introducing a named lifetime parameter +(ヘルプ: 名前付きライフライム引数の導入を検討してください) + | +9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { + | ++++ ++ ++ ++ + +For more information about this error, try `rustc --explain E0106`. +error: could not compile `chapter10` (bin "chapter10") due to 1 previous error diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/src/main.rs index e1a830aad..6af8c9f0d 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/src/main.rs @@ -3,6 +3,15 @@ fn main() { let string2 = "xyz"; let result = longest(string1.as_str(), string2); - // 最長の文字列は、{}です println!("The longest string is {}", result); } + +// ANCHOR: here +fn longest(x: &str, y: &str) -> &str { + if x.len() > y.len() { + x + } else { + y + } +} +// ANCHOR_END: here diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/output.txt b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/output.txt deleted file mode 100644 index baaf69902..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/output.txt +++ /dev/null @@ -1,20 +0,0 @@ -$ cargo run - Compiling chapter10 v0.1.0 (file:///projects/chapter10) -error[E0106]: missing lifetime specifier -(エラー[E0106]: ライフタイム指定子が不足しています) - --> src/main.rs:9:33 - | -9 | fn longest(x: &str, y: &str) -> &str { - | ^ expected lifetime parameter - | (ライフタイム引数があるべきです) - | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` - (助言: この関数の戻り値型は借用された値を含んでいますが、 - シグニチャは、それが`x`と`y`どちらから借用されたものなのか宣言していません) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0106`. -error: could not compile `chapter10`. - -To learn more, run the command again with --verbose. diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/src/main.rs index 6af8c9f0d..09c3a0daa 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/src/main.rs @@ -7,7 +7,7 @@ fn main() { } // ANCHOR: here -fn longest(x: &str, y: &str) -> &str { +fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-22/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-22/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-22/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-22/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-22/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-22/src/main.rs index 09c3a0daa..e54d5de45 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-22/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-22/src/main.rs @@ -1,12 +1,18 @@ +// ANCHOR: here fn main() { - let string1 = String::from("abcd"); - let string2 = "xyz"; + // 長い文字列は長い + let string1 = String::from("long string is long"); + // (訳注:この言葉自体に深い意味はない。下の"xyz"より長いということだけが重要) - let result = longest(string1.as_str(), string2); - println!("The longest string is {}", result); + { + let string2 = String::from("xyz"); + let result = longest(string1.as_str(), string2.as_str()); + // 一番長い文字列は{} + println!("The longest string is {}", result); + } } +// ANCHOR_END: here -// ANCHOR: here fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x @@ -14,4 +20,3 @@ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { y } } -// ANCHOR_END: here diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/output.txt b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/output.txt similarity index 75% rename from listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/output.txt rename to listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/output.txt index bcedda0f4..471347c68 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/output.txt +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/output.txt @@ -3,6 +3,8 @@ $ cargo run error[E0597]: `string2` does not live long enough --> src/main.rs:6:44 | +5 | let string2 = String::from("xyz"); + | ------- binding `string2` declared here 6 | result = longest(string1.as_str(), string2.as_str()); | ^^^^^^^ borrowed value does not live long enough 7 | } @@ -10,9 +12,5 @@ error[E0597]: `string2` does not live long enough 8 | println!("The longest string is {}", result); | ------ borrow later used here -error: aborting due to previous error - For more information about this error, try `rustc --explain E0597`. -error: could not compile `chapter10`. - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` (bin "chapter10") due to 1 previous error diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/src/main.rs index e54d5de45..2a6fa5898 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/src/main.rs @@ -1,15 +1,12 @@ // ANCHOR: here fn main() { - // 長い文字列は長い let string1 = String::from("long string is long"); - // (訳注:この言葉自体に深い意味はない。下の"xyz"より長いということだけが重要) - + let result; { let string2 = String::from("xyz"); - let result = longest(string1.as_str(), string2.as_str()); - // 一番長い文字列は{} - println!("The longest string is {}", result); + result = longest(string1.as_str(), string2.as_str()); } + println!("The longest string is {}", result); } // ANCHOR_END: here diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/src/main.rs index 2a6fa5898..2937b194c 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/src/main.rs @@ -1,19 +1,11 @@ -// ANCHOR: here -fn main() { - let string1 = String::from("long string is long"); - let result; - { - let string2 = String::from("xyz"); - result = longest(string1.as_str(), string2.as_str()); - } - println!("The longest string is {}", result); +struct ImportantExcerpt<'a> { + part: &'a str, } -// ANCHOR_END: here -fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { - if x.len() > y.len() { - x - } else { - y - } +fn main() { + let novel = String::from("Call me Ishmael. Some years ago..."); + let first_sentence = novel.split('.').next().expect("Could not find a '.'"); + let i = ImportantExcerpt { + part: first_sentence, + }; } diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/Cargo.lock index e8007a19b..2aa4918e5 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "chapter10" +name = "ownership" version = "0.1.0" diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/Cargo.toml index 6d5a0ff1d..e8847526d 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "ownership" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/src/main.rs index 25598d3f6..431a261d2 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/src/main.rs @@ -1,13 +1,29 @@ -struct ImportantExcerpt<'a> { - part: &'a str, +// ANCHOR: here +fn first_word(s: &str) -> &str { + let bytes = s.as_bytes(); + + for (i, &item) in bytes.iter().enumerate() { + if item == b' ' { + return &s[0..i]; + } + } + + &s[..] } +// ANCHOR_END: here fn main() { - // 僕をイシュマエルとお呼び。何年か前・・・ - let novel = String::from("Call me Ishmael. Some years ago..."); - // "'.'が見つかりませんでした" - let first_sentence = novel.split('.').next().expect("Could not find a '.'"); - let i = ImportantExcerpt { - part: first_sentence, - }; + let my_string = String::from("hello world"); + + // first_word works on slices of `String`s + let word = first_word(&my_string[..]); + + let my_string_literal = "hello world"; + + // first_word works on slices of string literals + let word = first_word(&my_string_literal[..]); + + // Because string literals *are* string slices already, + // this works too, without the slice syntax! + let word = first_word(my_string_literal); } diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/Cargo.lock deleted file mode 100644 index 2aa4918e5..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "ownership" -version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/Cargo.toml deleted file mode 100644 index 686de938f..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "ownership" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/src/main.rs deleted file mode 100644 index 431a261d2..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/listing-10-26/src/main.rs +++ /dev/null @@ -1,29 +0,0 @@ -// ANCHOR: here -fn first_word(s: &str) -> &str { - let bytes = s.as_bytes(); - - for (i, &item) in bytes.iter().enumerate() { - if item == b' ' { - return &s[0..i]; - } - } - - &s[..] -} -// ANCHOR_END: here - -fn main() { - let my_string = String::from("hello world"); - - // first_word works on slices of `String`s - let word = first_word(&my_string[..]); - - let my_string_literal = "hello world"; - - // first_word works on slices of string literals - let word = first_word(&my_string_literal[..]); - - // Because string literals *are* string slices already, - // this works too, without the slice syntax! - let word = first_word(my_string_literal); -} diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/Cargo.lock index e8007a19b..2835471f0 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "chapter10" +name = "aggregator" version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/Cargo.toml index 6d5a0ff1d..46f46a7f4 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "aggregator" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/src/main.rs index 47de4d5c0..f4f66890e 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/src/main.rs @@ -1,7 +1,6 @@ -use chapter10::{self, Summary, Tweet}; +use aggregator::{Summary, Tweet}; fn main() { - // ANCHOR: here let tweet = Tweet { username: String::from("horse_ebooks"), content: String::from( @@ -13,5 +12,4 @@ fn main() { }; println!("1 new tweet: {}", tweet.summarize()); - // ANCHOR_END: here } diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/Cargo.lock index e8007a19b..2835471f0 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "chapter10" +name = "aggregator" version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/Cargo.toml index 6d5a0ff1d..46f46a7f4 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "aggregator" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/src/main.rs index f659ea6ad..56f49bb8b 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/src/main.rs @@ -1,4 +1,4 @@ -use chapter10::{self, NewsArticle, Summary}; +use aggregator::{self, NewsArticle, Summary}; fn main() { // ANCHOR: here diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/Cargo.lock index e8007a19b..2835471f0 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "chapter10" +name = "aggregator" version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/Cargo.toml index 6d5a0ff1d..46f46a7f4 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "aggregator" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/main.rs index 466dc4d59..e05e8e1c6 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/main.rs +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/main.rs @@ -1,4 +1,4 @@ -use chapter10::{self, Summary, Tweet}; +use aggregator::{self, Summary, Tweet}; fn main() { // ANCHOR: here diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/Cargo.lock index e8007a19b..2835471f0 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "chapter10" +name = "aggregator" version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/Cargo.toml index 6d5a0ff1d..46f46a7f4 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "aggregator" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/Cargo.lock index e8007a19b..2835471f0 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "chapter10" +name = "aggregator" version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/Cargo.toml index 6d5a0ff1d..46f46a7f4 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "aggregator" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/Cargo.lock index e8007a19b..2835471f0 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/Cargo.lock +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "chapter10" +name = "aggregator" version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/Cargo.toml index 6d5a0ff1d..46f46a7f4 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "chapter10" +name = "aggregator" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/Cargo.lock b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/Cargo.lock deleted file mode 100644 index e8007a19b..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "chapter10" -version = "0.1.0" - diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/Cargo.toml deleted file mode 100644 index 6d5a0ff1d..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "chapter10" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt deleted file mode 100644 index a225d01f3..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt +++ /dev/null @@ -1,37 +0,0 @@ -$ cargo run - Compiling chapter10 v0.1.0 (file:///projects/chapter10) -error[E0508]: cannot move out of type `[T]`, a non-copy slice -(エラー[E0508]: 型`[T]`をもつ、非コピーのスライスからのムーブはできません) - --> src/main.rs:2:23 - | -2 | let mut largest = list[0]; - | ^^^^^^^ - | | - | cannot move out of here - | (ここからムーブすることはできません) - | move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait - | (ムーブが発生するのは、`list[_]`は`T`という、`Copy`トレイトを実装しない型であるためです) - | help: consider borrowing here: `&list[0]` - | (助言:借用するようにしてみてはいかがですか: `&list[0]`) - -error[E0507]: cannot move out of a shared reference -(エラー[E0507]:共有の参照からムーブはできません) - --> src/main.rs:4:18 - | -4 | for &item in list { - | ----- ^^^^ - | || - | |data moved here - | |(データがここでムーブされています) - | |move occurs because `item` has type `T`, which does not implement the `Copy` trait - | |(ムーブが発生するのは、`item`は`T`という、`Copy`トレイトを実装しない型であるためです) - | help: consider removing the `&`: `item` - | (助言:`&`を取り除いてみてはいかがですか: `item`) - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0507, E0508. -For more information about an error, try `rustc --explain E0507`. -error: could not compile `chapter10`. - -To learn more, run the command again with --verbose. diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/src/main.rs b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/src/main.rs deleted file mode 100644 index 525ce815a..000000000 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/src/main.rs +++ /dev/null @@ -1,25 +0,0 @@ -// ANCHOR: here -fn largest(list: &[T]) -> T { - // ANCHOR_END: here - let mut largest = list[0]; - - for &item in list { - if item > largest { - largest = item; - } - } - - largest -} - -fn main() { - let number_list = vec![34, 50, 25, 100, 65]; - - let result = largest(&number_list); - println!("The largest number is {}", result); - - let char_list = vec!['y', 'm', 'a', 'q']; - - let result = largest(&char_list); - println!("The largest char is {}", result); -} diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/Cargo.toml new file mode 100644 index 000000000..4dbde9090 --- /dev/null +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "chapter10" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/src/lib.rs b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/src/lib.rs new file mode 100644 index 000000000..05b07c31a --- /dev/null +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/src/lib.rs @@ -0,0 +1,9 @@ +// ANCHOR: here +fn some_function(t: &T, u: &U) -> i32 +where + T: Display + Clone, + U: Clone + Debug, +{ + // ANCHOR_END: here + unimplemented!() +} diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-08-only-one-reference-with-lifetime/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-08-only-one-reference-with-lifetime/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-08-only-one-reference-with-lifetime/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-08-only-one-reference-with-lifetime/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/output.txt b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/output.txt index acdf96e4e..05420c7d7 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/output.txt +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/output.txt @@ -1,20 +1,16 @@ $ cargo run Compiling chapter10 v0.1.0 (file:///projects/chapter10) error[E0515]: cannot return value referencing local variable `result` -(エラー[E0515]: ローカル変数`result`を参照している値は返せません) +(エラー[E0515]: ローカル変数`result`を参照する値を返すことはできません) --> src/main.rs:11:5 | 11 | result.as_str() | ------^^^^^^^^^ | | | returns a value referencing data owned by the current function + | (現在の関数に所有されているデータを参照する値を返しています) | `result` is borrowed here - | (現在の関数に所有されているデータを参照する値を返しています - | `result`はここで借用されています) - -error: aborting due to previous error + | (`result`はここで借用されています) For more information about this error, try `rustc --explain E0515`. -error: could not compile `chapter10`. - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` (bin "chapter10") due to 1 previous error diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-10-lifetimes-on-methods/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-10-lifetimes-on-methods/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-10-lifetimes-on-methods/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-10-lifetimes-on-methods/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-11-generics-traits-and-lifetimes/Cargo.toml b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-11-generics-traits-and-lifetimes/Cargo.toml index 6d5a0ff1d..489f80967 100644 --- a/listings/ch10-generic-types-traits-and-lifetimes/no-listing-11-generics-traits-and-lifetimes/Cargo.toml +++ b/listings/ch10-generic-types-traits-and-lifetimes/no-listing-11-generics-traits-and-lifetimes/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chapter10" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/src/ch10-00-generics.md b/src/ch10-00-generics.md index dc40f97c7..7aa347db7 100644 --- a/src/ch10-00-generics.md +++ b/src/ch10-00-generics.md @@ -6,20 +6,21 @@ -全てのプログラミング言語には、概念の重複を効率的に扱う道具があります。Rustにおいて、そのような道具の一つが*ジェネリクス*です。 -ジェネリクスは、具体型や他のプロパティの抽象的な代役です。コード記述の際、コンパイルやコード実行時に、 +全てのプログラミング言語には、概念の重複を効率的に扱う道具があります。 +Rustにおいて、そのような道具の一つが*ジェネリクス*です。 +ジェネリクスは、具体型や他のプロパティの抽象的な代役です。コンパイルやコード実行時に、 ジェネリクスの位置に何が入るかを知ることなく、ジェネリクスの振る舞いや他のジェネリクスとの関係を表現できるのです。 @@ -43,22 +44,24 @@ generic types in struct and enum definitions. それから、トレイトを使用して、ジェネリックな方法で振る舞いを定義する方法を学びます。 -ジェネリックな型にトレイトを組み合わせることで、ジェネリックな型を、単にあらゆる型に対してではなく、特定の振る舞いのある型のみに制限できます。 +ジェネリックな型にトレイトを組み合わせることで、ジェネリックな型を、単にあらゆる型に対してではなく、特定の振る舞いのある型のみを受け付けるように制限できます。 最後に、ライフタイムを議論します。ライフタイムとは、コンパイラに参照がお互いにどう関係しているかの情報を与える一種のジェネリクスです。 -ライフタイムのおかげでコンパイラに参照が有効であることを確認してもらうことを可能にしつつ、多くの場面で値を借用できます。 +ライフタイムを利用することで、借用された値についての十分な情報をコンパイラに渡すことができ、 +プログラマの支援がなくてもできる範囲よりもより多くの場面で、参照が有効であることを保証できます。 -ジェネリクスの記法に飛び込む前にまずは、関数を抽出することでジェネリックな型が関わらない重複を取り除く方法を見ましょう。 -そして、このテクニックを適用してジェネリックな関数を抽出するのです!重複したコードを認識して関数に抽出できるのと同じように、 -ジェネリクスを使用できる重複コードも認識し始めるでしょう。 +ジェネリクスを使用すると、複数の型を表現するプレースホルダで特定の型を置き換えることで、コードの重複を取り除くことができます。 +ジェネリクスの記法に飛び込む前にまずは、複数の値を表現するプレースホルダで特定の値を置き換えて関数を抽出することで、ジェネリックな型が関わらない重複を取り除く方法を見ましょう。 +そして、同じテクニックを適用してジェネリックな関数を抽出するのです! +関数に抽出できる重複したコードを認識する方法を見てみることで、ジェネリクスを使用できる重複コードも認識できるようになるでしょう。 -リスト10-1に示したように、リスト内の最大値を求める短いプログラムを考えてください。 +リスト10-1の、リスト内の最大値を求める短いプログラムで始めましょう。 -リスト10-1: 数字のリストから最大値を求めるコード +リスト10-1: 数字のリストから最大値を求める -このコードは、整数のリストを変数`number_list`に格納し、リストの最初の数字を`largest`という変数に配置しています。 -それからリストの数字全部を走査し、現在の数字が`largest`に格納された数値よりも大きければ、 -その変数の値を置き換えます。ですが、現在の数値が今まで見た最大値よりも小さければ、 +このコードは、整数のリストを変数`number_list`に格納し、リストの最初の数への参照を`largest`という変数に配置しています。 +それからリストの数全部を走査し、現在の数が`largest`に格納された数値よりも大きければ、 +その変数に代入されている参照を置き換えます。ですが、現在の数値が今まで見た最大値以下であれば、 変数は変わらず、コードはリストの次の数値に移っていきます。リストの数値全てを吟味した後、 -`largest`は最大値を保持しているはずで、今回は100になります。 +`largest`は最大値を参照しているはずで、今回は100になります。 -2つの異なる数値のリストから最大値を発見するには、リスト10-1のコードを複製し、 -プログラムの異なる2箇所で同じロジックを使用できます。リスト10-2のようにですね。 +次は2つの異なる数値のリストから最大値を発見するタスクが課されました。 +これを行うために、リスト10-1のコードを複製し、プログラムの異なる2箇所で同じロジックを使用するという手があります。リスト10-2のようにですね。 -このコードは動くものの、コードを複製することは退屈ですし、間違いも起きやすいです。また、 -コードを変更したい時に複数箇所、更新しなければなりません。 +このコードは動くものの、コードを複製することは退屈ですし、間違いも起きやすいです。 +また、コードを変更したい時には、複数箇所更新することを覚えておかなくてはなりません。 -この重複を排除するには、引数で与えられた整数のどんなリストに対しても処理が行える関数を定義して抽象化できます。 +この重複を排除するには、引数で与えられた整数のどんなリストに対しても処理が行える関数を定義して抽象化しましょう。 この解決策によりコードがより明確になり、リストの最大値を探すという概念を抽象的に表現させてくれます。 -リスト10-3では、最大値を探すコードを`largest`という関数に抽出しました。リスト10-1のコードは、 -たった1つの特定のリストからだけ最大値を探せますが、それとは異なり、このプログラムは2つの異なるリストから最大値を探せます。 +リスト10-3では、最大値を探すコードを`largest`という関数に抽出しています。 +そして、リスト10-2の2つのリストから最大値を探すために、この関数を呼んでいます。 +将来持つことになるかもしれない他のどんな`i32`値のリストに対しても、この関数を使用することができます。 `largest`関数には`list`と呼ばれる引数があり、これは、関数に渡す可能性のある、あらゆる`i32`値の具体的なスライスを示します。 結果的に、関数呼び出しの際、コードは渡した特定の値に対して走るのです。 @@ -272,7 +219,7 @@ Listing 10-3: @@ -281,13 +228,12 @@ inputs and return values of that code in the function signature. 3. 重複したコードの2つの実体を代わりに関数を呼び出すように更新する。 -次は、この同じ手順をジェネリクスでも踏んで異なる方法でコードの重複を減らします。 +次は、この同じ手順をジェネリクスでも踏んでコードの重複を減らします。 関数本体が特定の値ではなく抽象的な`list`に対して処理できたのと同様に、 ジェネリクスは抽象的な型に対して処理するコードを可能にしてくれます。 diff --git a/src/ch10-01-syntax.md b/src/ch10-01-syntax.md index f4f23eeae..b42d96f63 100644 --- a/src/ch10-01-syntax.md +++ b/src/ch10-01-syntax.md @@ -5,7 +5,7 @@ ## ジェネリックなデータ型 `largest`関数を続けます。リスト10-4はどちらもスライスから最大値を探す2つの関数を示しています。 +ここから、これらをジェネリクスを使用する単一の関数にまとめます。 -これから定義する新しい関数の型を引数にするには、ちょうど関数の値引数のように型引数に名前をつける必要があります。 +新しい単一の関数の型を引数にするには、ちょうど関数の値引数のように型引数に名前をつける必要があります。 型引数の名前にはどんな識別子も使用できますが、`T`を使用します。というのも、慣習では、 -Rustの引数名は短く(しばしばたった1文字になります)、Rustの型の命名規則がキャメルケースだからです。 +Rustの型引数名は短く(しばしばたった1文字になります)、Rustの型の命名規則がアッパーキャメルケースだからです。 "type"の省略形なので、`T`が多くのRustプログラマの既定の選択なのです。 この定義は以下のように解読します: 関数`largest`は、なんらかの型`T`に関してジェネリックであると。 この関数には`list`という引数が1つあり、これは型`T`の値のスライスです。 -`largest`関数は同じ`T`型の値を返します。 +`largest`関数は同じ`T`型の値への参照を返します。 -リスト10-5: ジェネリックな型引数を使用するものの、まだコンパイルできない`largest`関数の定義 +リスト10-5: ジェネリックな型引数を使用する`largest`関数; まだコンパイルできません src/main.rs:5:12 - | -5 | if item > largest { - | ^^^^^^^^^^^^^^ - | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `T` - (注釈: `std::cmp::PartialOrd`の実装が`T`に対して存在しない可能性があります) +```console +{{#include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt}} ``` -注釈が`std::cmp::PartialOrd`に触れています。これは、*トレイト*です。トレイトについては、次の節で語ります。 -とりあえず、このエラーは、`largest`の本体は、`T`がなりうる全ての可能性のある型に対して動作しないと述べています。 +ヘルプメッセージが`std::cmp::PartialOrd`に触れています。これは、*トレイト*です。トレイトについては、次の節で語ります。 +今のところは、このエラーは、`largest`の本体は、`T`がなりうる可能性のある全ての型に対して動作するとは限らないと主張している、と理解してください。 本体で型`T`の値を比較したいので、値が順序付け可能な型のみしか使用できないのです。比較を可能にするために、 標準ライブラリには型に実装できる`std::cmp::PartialOrd`トレイトがあります(このトレイトについて詳しくは付録Cを参照されたし)。 -ジェネリックな型が特定のトレイトを持つと指定する方法は「トレイト境界」節で習うでしょうが、 -先にジェネリックな型引数を使用する他の方法を探究しましょう。 +ヘルプメッセージの提案に従うことで、`T`として有効な型を`PartialOrd`を実装するもののみに制限することができ、 +そうすると、標準ライブラリは`i32`と`char`の両方に`PartialOrd`を実装しているので、この例はコンパイルできるようになるでしょう。 構造体を定義して`<>`記法で1つ以上のフィールドにジェネリックな型引数を使用することもできます。 -リスト10-6は、`Point`構造体を定義してあらゆる型の`x`と`y`座標を保持する方法を示しています。 +リスト10-6は、`Point`構造体を定義してあらゆる型の`x`と`y`座標を保持しています。 -構造体定義でジェネリクスを使用する記法は、関数定義のものと似ています。まず、山カッコ内に型引数の名前を構造体名の直後に宣言します。 -そうすると、本来具体的なデータ型を記述する構造体定義の箇所に、ジェネリックな型を使用できます。 +構造体定義でジェネリクスを使用する記法は、関数定義のものと似ています。 +まず、山カッコ内に型引数の名前を構造体名の直後に宣言します。 +そして、本来具体的なデータ型を記述する構造体定義の箇所に、ジェネリックな型を使用します。 @@ -329,23 +252,15 @@ same type as `x`, we’ll get a type mismatch error like this: この例で、`x`に整数値5を代入すると、この`Point`のインスタンスに対するジェネリックな型`T`は整数になるとコンパイラに知らせます。 それから`y`に4.0を指定する時に、このフィールドは`x`と同じ型と定義したはずなので、このように型不一致エラーが出ます: -```text -error[E0308]: mismatched types - --> src/main.rs:7:38 - | -7 | let wont_work = Point { x: 5, y: 4.0 }; - | ^^^ expected integral variable, found -floating-point variable - | - = note: expected type `{integer}` - found type `{float}` +```console +{{#include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/output.txt}} ``` `x`と`y`が両方ジェネリックだけれども、異なる型になり得る`Point`構造体を定義するには、 @@ -359,16 +274,7 @@ Listing 10-8, we can change the definition of `Point` to be generic over types ファイル名: src/main.rs ```rust -struct Point { - x: T, - y: U, -} - -fn main() { - let both_integer = Point { x: 5, y: 10 }; - let both_float = Point { x: 1.0, y: 4.0 }; - let integer_and_float = Point { x: 5, y: 4.0 }; -} +{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-08/src/main.rs}} ``` これで、示された`Point`インスタンスは全部使用可能です!所望の数だけ定義でジェネリックな型引数を使用できますが、 -数個以上使用すると、コードが読みづらくなります。コードで多くのジェネリックな型が必要な時は、 +数個以上使用すると、コードが読みづらくなります。コードで多くのジェネリックな型が必要になることに気づいた時は、 コードの小分けが必要なサインかもしれません。 -この定義はもう、あなたにとってより道理が通っているはずです。ご覧の通り、`Option`は、 +この定義はもう、あなたにとってより道理が通っているはずです。ご覧の通り、`Option` enumは、 型`T`に関してジェネリックで2つの列挙子のあるenumです: その列挙子は、型`T`の値を保持する`Some`と、 値を何も保持しない`None`です。`Option` enumを使用することで、オプショナルな値があるという抽象的な概念を表現でき、 `Option`はジェネリックなので、オプショナルな値の型に関わらず、この抽象を使用できます。 @@ -487,22 +394,7 @@ struct we defined in Listing 10-6 with a method named `x` implemented on it. ファイル名: src/main.rs ```rust -struct Point { - x: T, - y: T, -} - -impl Point { - fn x(&self) -> &T { - &self.x - } -} - -fn main() { - let p = Point { x: 5, y: 10 }; - - println!("p.x = {}", p.x()); -} +{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-09/src/main.rs}} ``` `impl`の直後に`T`を宣言しなければならないことに注意してください。こうすることで、型`Point`にメソッドを実装していることを指定するために、`T`を使用することができます。 `impl`の後に`T`をジェネリックな型として宣言することで、コンパイラは、`Point`の山カッコ内の型が、 具体的な型ではなくジェネリックな型であることを認識できるのです。 +このジェネリック引数には、構造体定義内で宣言したジェネリック引数とは異なる名前を選択することもできますが、 +同じ名前を使用するのが慣用的です。 +ジェネリック型を宣言する`impl`内に書かれたメソッドは、そのジェネリック型を置き換えることになる具体型が何であっても、その型のインスタンスの任意の値に対して定義されます。 +型にメソッドを定義するときに、ジェネリック型に制約を指定することもできます。 例えば、ジェネリックな型を持つ`Point`インスタンスではなく、`Point`だけにメソッドを実装することもできるでしょう。 リスト10-10では、具体的な型`f32`を使用しています。つまり、`impl`の後に型を宣言しません。 + + +ファイル名: src/main.rs + ```rust -# struct Point { -# x: T, -# y: T, -# } -# -impl Point { - fn distance_from_origin(&self) -> f32 { - (self.x.powi(2) + self.y.powi(2)).sqrt() - } -} +{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-10/src/main.rs:here}} ``` -このコードは、`Point`には`distance_from_origin`というメソッドが存在するが、 +このコードは、`Point`には`distance_from_origin`メソッドが存在するが、 `T`が`f32`ではない`Point`の他のインスタンスにはこのメソッドが定義されないことを意味します。 このメソッドは、この点が座標(0.0, 0.0)の点からどれだけ離れているかを測定し、 浮動小数点数にのみ利用可能な数学的処理を使用します。 構造体定義のジェネリックな型引数は、必ずしもその構造体のメソッドシグニチャで使用するものと同じにはなりません。 -例を挙げれば、リスト10-11は、リスト10-8の`Point`にメソッド`mixup`を定義しています。 -このメソッドは、他の`Point`を引数として取り、この引数は`mixup`を呼び出している`self`の`Point`とは異なる型の可能性があります。 -このメソッドは、(型`T`の)`self`の`Point`の`x`値と渡した(型`W`の)`Point`の`y`値から新しい`Point`インスタンスを生成します。 +リスト10-11では、例をより見通しよくするために、`Point`構造体に対してはジェネリック型`X1`と`Y1`を使用し、 +`mixup`メソッドのシグネチャに対しては`X2`と`Y2`を使用しています。 +このメソッドは、(型`X1`の)`self`の`Point`の`x`値と渡した(型`Y2`の)`Point`の`y`値から新しい`Point`インスタンスを生成します。 リスト10-11: 構造体定義とは異なるジェネリックな型を使用するメソッド @@ -645,14 +522,15 @@ call will print `p3.x = 5, p3.y = c`. この例の目的は、一部のジェネリックな引数は`impl`で宣言され、他の一部はメソッド定義で宣言される場面をデモすることです。 -ここで、ジェネリックな引数`T`と`U`は`impl`の後に宣言されています。構造体定義にはまるからです。 -ジェネリックな引数`V`と`W`は`fn mixup`の後に宣言されています。何故なら、このメソッドにしか関係ないからです。 +ここで、ジェネリックな引数`X1`と`Y1`は`impl`の後に宣言されています。構造体定義にはまるからです。 +ジェネリックな引数`X2`と`Y2`は`fn mixup`の後に宣言されています。何故なら、このメソッドにしか関係ないからです。 ジェネリックな型引数を使用すると、実行時にコストが発生するのかな、と思うかもしれません。 -嬉しいことにRustでは、ジェネリクスを、具体的な型があるコードよりもジェネリックな型を使用したコードを実行するのが遅くならないように実装しています。 +嬉しいことに、ジェネリックな型を使用したからといって、具体的な型を使って同じことを行う場合よりもプログラムの実行が遅くなることはありません。 コンパイラはこれを、ジェネリクスを使用しているコードの単相化をコンパイル時に行うことで達成しています。 *単相化*(monomorphization)は、コンパイル時に使用されている具体的な型を入れることで、 ジェネリックなコードを特定のコードに変換する過程のことです。 - - - この過程において、コンパイラは、リスト10-5でジェネリックな関数を生成するために使用した手順と真逆のことをしています: コンパイラは、ジェネリックなコードが呼び出されている箇所全部を見て、 ジェネリックなコードが呼び出されている具体的な型のコードを生成するのです。 -標準ライブラリの`Option` enumを使用する例でこれが動作する方法を見ましょう: +標準ライブラリのジェネリックな`Option` enumを使用して、これがどう機能するのか見てみましょう: ```rust let integer = Some(5); @@ -708,23 +581,23 @@ let float = Some(5.0); When Rust compiles this code, it performs monomorphization. During that process, the compiler reads the values that have been used in `Option` instances and identifies two kinds of `Option`: one is `i32` and the other -is `f64`. As such, it expands the generic definition of `Option` into -`Option_i32` and `Option_f64`, thereby replacing the generic definition with -the specific ones. +is `f64`. As such, it expands the generic definition of `Option` into two +definitions specialized to `i32` and `f64`, thereby replacing the generic +definition with the specific ones. --> コンパイラがこのコードをコンパイルすると、単相化を行います。その過程で、コンパイラは`Option`のインスタンスに使用された値を読み取り、 2種類の`Option`を識別します: 一方は`i32`で、もう片方は`f64`です。そのように、 -コンパイラは、`Option`のジェネリックな定義を`Option_i32`と`Option_f64`に展開し、 +コンパイラは、`Option`のジェネリックな定義を`i32`と`f64`に特化した2つの定義に展開し、 それにより、ジェネリックな定義を特定の定義と置き換えます。 -単相化されたバージョンのコードは、以下のようになります。ジェネリックな`Option`が、 -コンパイラが生成した特定の定義に置き換えられています: +単相化されたバージョンのコードは、以下のようなものになります +(コンパイラは、ここで説明のために使用しているものとは異なる名前を使用します): +ジェネリックな`Option`は、コンパイラによって生成される特化された定義で置き換えられます。 Rustでは、ジェネリックなコードを各インスタンスで型を指定したコードにコンパイルするので、 ジェネリクスを使用することに対して実行時コストを払うことはありません。コードを実行すると、 それぞれの定義を手作業で複製した時のように振る舞います。単相化の過程により、 diff --git a/src/ch10-02-traits.md b/src/ch10-02-traits.md index 4fb28ae36..53f7cc045 100644 --- a/src/ch10-02-traits.md +++ b/src/ch10-02-traits.md @@ -5,15 +5,15 @@ ## トレイト: 共通の振る舞いを定義する -*トレイト*は、Rustコンパイラに、特定の型に存在し、他の型と共有できる機能について知らせます。 -トレイトを使用すると、共通の振る舞いを抽象的に定義できます。トレイト境界を使用すると、 -あるジェネリックが、特定の振る舞いをもつあらゆる型になり得ることを指定できます。 +*トレイト*は、特定の型に存在し、他の型と共有できる機能を定義します。 +トレイトを使用すると、共通の振る舞いを抽象的に定義できます。*トレイト境界*を使用すると、 +あるジェネリック型が、特定の振る舞いをもつあらゆる型になり得ることを指定できます。 -`NewsArticle` または `Tweet` インスタンスに保存されているデータのサマリーを表示できるメディア アグリゲータ ライブラリを作成します。 -これをするには、各型のサマリーが必要で、インスタンスで `summarize` メソッドを呼び出してサマリーを要求する必要があります。 -リスト10-12は、この振る舞いを表現する`Summary`トレイトの定義を表示しています。 +`NewsArticle` または `Tweet` インスタンスに保存されているデータのサマリーを表示できる`aggregator`という名前のメディア アグリゲータ ライブラリ クレートを作成します。 +これをするには、各型のサマリーが必要で、インスタンスで `summarize` メソッドを呼び出してサマリーを要求することになるでしょう。 +リスト10-12は、この振る舞いを表現する公開の`Summary`トレイトの定義を表示しています。 -ここでは、`trait`キーワード、それからトレイト名を使用してトレイトを定義していて、その名前は今回の場合、 -`Summary`です。波括弧の中にこのトレイトを実装する型の振る舞いを記述するメソッドシグニチャを定義し、 +ここでは、`trait`キーワード、それからトレイト名を使用してトレイトを宣言していて、その名前は今回の場合、 +`Summary`です。 +また、いくつかの例で見ていきますが、このクレートに依存するクレートがこのトレイトを利用できるように、トレイトを`pub`として宣言しています。 +波括弧の中にこのトレイトを実装する型の振る舞いを記述するメソッドシグニチャを定義し、 今回の場合は、`fn summarize(&self) -> String`です。 -今や `Summary` トレイトを使用して目的の動作を定義できたので、メディア アグリゲータでこれを型に実装できます。 +これで `Summary` トレイトのメソッドのシグネチャを希望通りに定義できたので、メディア アグリゲータ内の型に対してこれを実装できます。 リスト10-13は、 `Summary` トレイトを `NewsArticle` 構造体上に実装したもので、ヘッドライン、著者、そして地域情報を使って`summarize` の戻り値を作っています。 `Tweet` 構造体に関しては、ツイートの内容が既に280文字に制限されていると仮定して、ユーザー名の後にツイートのテキスト全体が続くものとして `summarize` を定義します。 @@ -136,7 +140,7 @@ already limited to 280 characters. ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/src/lib.rs:here}} ``` @@ -149,13 +153,12 @@ already limited to 280 characters. 型にトレイトを実装することは、普通のメソッドを実装することに似ています。違いは、`impl`の後に、 @@ -164,15 +167,20 @@ particular type. 波括弧を使用し、メソッド本体に特定の型のトレイトのメソッドに欲しい特定の振る舞いを入れます。 -トレイトを実装後、普通のメソッド同様に`NewsArticle`や`Tweet`のインスタンスに対してこのメソッドを呼び出せます。 -こんな感じで: +これでライブラリは`NewsArticle`と`Tweet`に対して`Summary`トレイトを実装できたので、クレートの利用者は普通のメソッド同様に`NewsArticle`や`Tweet`のインスタンスに対してこのトレイトメソッドを呼び出せます。 +唯一の違いは、ユーザは型だけではなくトレイトもスコープ内に持ち込まなくてはならないということです。 +以下は、バイナリクレートが私たちの`aggregator`ライブラリクレートをどうやって使用できるかの例です: ```rust,ignore -{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/src/main.rs:here}} +{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/src/main.rs}} ``` -トレイト実装で注意すべき制限の1つは、トレイトか対象の型が自分のクレートに固有(local)である時のみ、 +`aggregator`クレートに依存する他のクレートも、自身の型に対して`Summary`を実装するために、`Summary`トレイトをスコープに持ち込むことができます。 +注意すべき制限の1つは、トレイトか、対象の型のうち、少なくとも一方が自分のクレートに固有(local)である時のみ、 型に対してトレイトを実装できるということです。例えば、`Display`のような標準ライブラリのトレイトを`aggregator`クレートの機能の一部として、 `Tweet`のような独自の型に実装できます。型`Tweet`が`aggregator`クレートに固有だからです。 また、`Summary`を`aggregator`クレートで`Vec`に対して実装することもできます。 @@ -222,19 +233,19 @@ trait `Summary` is local to our `aggregator` crate. しかし、外部のトレイトを外部の型に対して実装することはできません。例として、 `aggregator`クレート内で`Vec`に対して`Display`トレイトを実装することはできません。 -`Display`と`Vec`は標準ライブラリで定義され、`aggregator`クレートに固有ではないからです。 -この制限は、*コヒーレンス*(coherence)、特に*孤児のルール*(orphan rule)と呼ばれるプログラムの特性の一部で、 +`Display`と`Vec`はどちらも標準ライブラリで定義され、`aggregator`クレートに固有ではないからです。 +この制限は、*コヒーレンス*(coherence)、特に*孤児のルール*(orphan rule)と呼ばれる特性の一部で、 親の型が存在しないためにそう命名されました。この規則により、他の人のコードが自分のコードを壊したり、 その逆が起きないことを保証してくれます。この規則がなければ、2つのクレートが同じ型に対して同じトレイトを実装できてしまい、 コンパイラはどちらの実装を使うべきかわからなくなってしまうでしょう。 @@ -256,13 +267,13 @@ each method’s default behavior. そうすれば、特定の型にトレイトを実装する際、各メソッドのデフォルト実装を保持するかオーバーライドするか選べるわけです。 -リスト10-14は、リスト10-12のように、メソッドシグニチャだけを定義するのではなく、 -`Summary`トレイトの`summarize`メソッドにデフォルトの文字列を指定する方法を示しています。 +リスト10-14では、リスト10-12のように、メソッドシグニチャだけを定義するのではなく、 +`Summary`トレイトの`summarize`メソッドにデフォルトの文字列を指定しています。 -リスト10-14: `summarize`メソッドのデフォルト実装がある`Summary`トレイトの定義 +リスト10-14: `summarize`メソッドのデフォルト実装がある`Summary`トレイトを定義する -独自の実装を定義するのではなく、デフォルト実装を利用して`NewsArticle`のインスタンスをまとめるには、 +デフォルト実装を利用して`NewsArticle`のインスタンスをまとめるには、 `impl Summary for NewsArticle {}`と空の`impl`ブロックを指定します。 -`summarize`にデフォルト実装を用意しても、リスト10-13の`Tweet`の`Summary`実装を変える必要はありません。 +デフォルト実装を用意しても、リスト10-13の`Tweet`の`Summary`実装を変える必要はありません。 理由は、デフォルト実装をオーバーライドする記法はデフォルト実装のないトレイトメソッドを実装する記法と同じだからです。 トレイトを定義し実装する方法はわかったので、トレイトを使っていろんな種類の型を受け付ける関数を定義する方法を学んでいきましょう。 - - -たとえば、Listing 10-13では、`NewsArticle`と`Tweet`型に`Summary`トレイトを実装しました。 -ここで、引数の`item`の`summarize`メソッドを呼ぶ関数`notify`を定義することができます。ただし、引数`item`は`Summary`トレイトを実装しているような何らかの型であるとします。 -このようなことをするためには、`impl Trait`構文を使うことができます。 +リスト10-13で`NewsArticle`と`Tweet`に対して実装した`Summary`トレイトを使用して、`notify`関数を定義しましょう。 +この関数は、`Summary`トレイトを実装する何らかの型を持つ引数`item`を持ち、それに対して`summarize`メソッドを呼び出します。 +これを行うためには、このように`impl Trait`構文を使います: ```rust,ignore {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/src/lib.rs:here}} @@ -424,17 +429,21 @@ because those types don’t implement `Summary`. この関数を呼び出すときに、`String`や`i32`のような他の型を渡すようなコードはコンパイルできません。 なぜなら、これらの型は`Summary`を実装していないからです。 + + + #### トレイト境界構文 -`impl Trait`構文は単純なケースを解決しますが、実はより長い*トレイト境界 (trait bound)* と呼ばれる姿の糖衣構文 (syntax sugar) なのです。 +`impl Trait`構文は単純なケースを解決しますが、実はより長い*トレイト境界 (trait bound)* として知られる姿の糖衣構文 (syntax sugar) なのです。 それは以下のようなものです: ```rust,ignore @@ -454,27 +463,27 @@ parameter after a colon and inside angle brackets. -簡単なケースに対し、`impl Trait`構文は便利で、コードを簡潔にしてくれます。 -そうでないケースの場合、トレイト境界構文を使えば複雑な状態を表現できます。 +簡単なケースでは`impl Trait`構文は便利で、コードを簡潔にしてくれます。 +一方でそうでないケースでは、完全なトレイト境界構文を使えばより複雑な制約を表現できます。 たとえば、`Summary`を実装する2つのパラメータを持つような関数を考えることができます。 -`impl Trait`構文を使うとこのようになるでしょう: +`impl Trait`構文を使ってそうするのはこのようになるでしょう: ```rust,ignore pub fn notify(item1: &impl Summary, item2: &impl Summary) { ``` -この関数が受け取る`item1`と`item2`の型が(どちらも`Summary`を実装する限り)異なっても良いとするならば、`impl Trait`は適切でしょう。 -両方の引数が同じ型であることを強制することは、以下のようにトレイト境界を使ってのみ表現可能です: +この関数が受け取る`item1`と`item2`の型が(どちらも`Summary`を実装する限り)異なっても良い場合、`impl Trait`の使用は適切です。 +しかし、両方の引数が同じ型であることを強制したい場合は、次のようにトレイト境界を使用しなくてはなりません: ```rust,ignore pub fn notify(item1: &T, item2: &T) { @@ -495,12 +504,12 @@ passed as an argument for `item1` and `item2` must be the same. 複数のトレイト境界も指定できます。 -たとえば、`notify`に`summarize`メソッドに加えて`item`の画面出力形式(ディスプレイフォーマット)を使わせたいとします。 +たとえば、`notify`に、`item`に対する`summarize`に加えて画面出力形式(ディスプレイフォーマット)も使わせたいとします。 その場合は、`notify`の定義に`item`は`Display`と`Summary`の両方を実装していなくてはならないと指定することになります。 これは、以下のように`+`構文で行うことができます: @@ -552,10 +561,7 @@ we can use a `where` clause, like this: 代わりに、`where`句を使い、このように書くことができます: ```rust,ignore -fn some_function(t: &T, u: &U) -> i32 - where T: Display + Clone, - U: Clone + Debug -{ +{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/src/lib.rs:here}} ``` 戻り値の型として`impl Summary`を使うことにより、具体的な型が何かを言うことなく、`returns_summarizable`関数は`Summary`トレイトを実装している何らかの型を返すのだ、と指定することができます。 -今回`returns_summarizable`は`Tweet`を返しますが、この関数を呼び出すコードはそのことを知りません。 +今回`returns_summarizable`は`Tweet`を返しますが、この関数を呼び出すコードはそのことを知る必要はありません。 実装しているトレイトだけで戻り値型を指定できることは、13章で学ぶ、クロージャとイテレータを扱うときに特に便利です。 クロージャとイテレータの作り出す型は、コンパイラだけが知っているものであったり、指定するには長すぎるものであったりします。 @@ -619,129 +625,11 @@ Returning either a `NewsArticle` or a `Tweet` isn’t allowed due to restriction around how the `impl Trait` syntax is implemented in the compiler. We’ll cover how to write a function with this behavior in the [“Using Trait Objects That Allow for Values of Different -Types”][using-trait-objects-that-allow-for-values-of-different-types] section of Chapter 17. +Types”][using-trait-objects-that-allow-for-values-of-different-types] +section of Chapter 17. --> `NewsArticle`か`Tweet`を返すというのは、コンパイラの`impl Trait`構文の実装まわりの制約により許されていません。 -このような振る舞いをする関数を書く方法は、17章の[トレイトオブジェクトで異なる型の値を許容する][using-trait-objects-that-allow-for-values-of-different-types]節で学びます。 - - -### トレイト境界で`largest`関数を修正する - - -ジェネリックな型引数の境界で使用したい振る舞いを指定する方法がわかったので、リスト10-5に戻って、 -ジェネリックな型引数を使用する`largest`関数の定義を修正しましょう!最後にそのコードを実行しようとした時、 -こんなエラーが出ていました: - -```text -{{#include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt}} -``` - - -`largest`の本体で、大なり演算子(`>`)を使用して型`T`の2つの値を比較しようとしていました。この演算子は、 -標準ライブラリトレイトの`std::cmp::PartialOrd`でデフォルトメソッドとして定義されているので、 -`largest`関数が、比較できるあらゆる型のスライスに対して動くようにするためには、`T`のトレイト境界に`PartialOrd`を指定する必要があります。 -`PartialOrd`はpreludeに含まれているので、これをスコープに導入する必要はありません。 -`largest`のシグニチャを以下のように変えてください: - -```rust,ignore -{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/src/main.rs:here}} -``` - - -今回のコンパイルでは、別のエラーが出てきます: - -```console -{{#include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt}} -``` - - -このエラーの鍵となる行は、`cannot move out of type [T], a non-copy slice`です。 -ジェネリックでないバージョンの`largest`関数では、最大の`i32`か`char`を探そうとするだけでした。 -第4章の[スタックのみのデータ: コピー][stack-only-data-copy]節で議論したように、`i32`や`char`のようなサイズが既知の型は -スタックに格納できるので、`Copy`トレイトを実装しています。しかし、`largest`関数をジェネリックにすると、 -`list`引数が`Copy`トレイトを実装しない型を含む可能性も出てきたのです。結果として、 -`list[0]`から値を`largest`にムーブできず、このエラーに陥ったのです。 - - -このコードを`Copy`トレイトを実装する型だけを使って呼び出すようにしたいなら、`T`のトレイト境界に`Copy`を追加すればよいです! -リスト10-15は、関数に渡したスライスの値の型が、`i32`や`char`などのように`PartialOrd`*と*`Copy`を実装する限りコンパイルできる、ジェネリックな`largest`関数の完全なコードを示しています。 - - -ファイル名: src/main.rs - -```rust -{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/main.rs}} -``` - - -リスト10-15: `PartialOrd`と`Copy`トレイトを実装するあらゆるジェネリックな型に対して動く、 -`largest`関数の実際の定義 - - -もし`largest`関数を`Copy`を実装する型だけに制限したくなかったら、`T`が`Copy`ではなく`Clone`というトレイト境界を持つと指定することもできます。そうしたら、 -`largest`関数に所有権が欲しい時にスライスの各値をクローンできます。`clone`関数を使用するということは、 -`String`のようなヒープデータを持つ型の場合により多くのヒープ確保が発生する可能性があることを意味します。 -そして、大量のデータを取り扱っていたら、ヒープ確保には時間がかかることもあります。 - - -`largest`の別の実装方法は、関数がスライスの`T`値への参照を返すようにすることです。 -戻り値の型を`T`ではなく`&T`に変え、それにより関数の本体を参照を返すように変更したら、 -`Clone`や`Copy`トレイト境界は必要なくなり、ヒープ確保も避けられるでしょう。 -これらの代替策をご自身で実装してみましょう! +このような振る舞いをする関数を書く方法は、17章の[「トレイトオブジェクトで異なる型の値を許容する」][using-trait-objects-that-allow-for-values-of-different-types]節で学びます。 ジェネリックな型引数を持つ`impl`ブロックにトレイト境界を与えることで、 特定のトレイトを実装する型に対するメソッド実装を条件分けできます。例えば、 -リスト10-16の型`Pair`は、常に`new`関数を実装します。しかし、`Pair`は、 +リスト10-15の型`Pair`は、`Pair`の新しいインスタンスを返す`new`関数を常に実装します +(第5章の[「メソッドを定義する」][methods]節で学んだ、`Self`は`impl`ブロックの型に対する型エイリアスだということを思い出してください、今回は`Pair`です)。しかし次の`impl`ブロック内では、`Pair`は、 内部の型`T`が比較を可能にする`PartialOrd`トレイト*と*出力を可能にする`Display`トレイトを実装している時のみ、 `cmp_display`メソッドを実装します。 @@ -767,15 +659,15 @@ the `Display` trait that enables printing. --> ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/lib.rs}} +```rust,noplayground +{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/lib.rs}} ``` -リスト10-16: トレイト境界によってジェネリックな型に対するメソッド実装を条件分けする +リスト10-15: トレイト境界によってジェネリックな型に対するメソッド実装を条件分けする -すでに使っている他のジェネリクスに、ライフタイムと呼ばれるものがあります。 -ライフタイムは、型が欲しい振る舞いを保持していることではなく、必要な間だけ参照が有効であることを保証します。 -ライフタイムがどうやってそれを行うかを見てみましょう。 - -[stack-only-data-copy]: -ch04-01-what-is-ownership.html#%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E3%81%BF%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF-%E3%82%B3%E3%83%94%E3%83%BC -[using-trait-objects-that-allow-for-values-of-different-types]: -ch17-02-trait-objects.html#%E3%83%88%E3%83%AC%E3%82%A4%E3%83%88%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A7%E7%95%B0%E3%81%AA%E3%82%8B%E5%9E%8B%E3%81%AE%E5%80%A4%E3%82%92%E8%A8%B1%E5%AE%B9%E3%81%99%E3%82%8B +[using-trait-objects-that-allow-for-values-of-different-types]: ch17-02-trait-objects.html#トレイトオブジェクトで異なる型の値を許容する +[methods]: ch05-03-method-syntax.html#メソッドを定義する diff --git a/src/ch10-03-lifetime-syntax.md b/src/ch10-03-lifetime-syntax.md index cfb1fd7e9..fb4f52dba 100644 --- a/src/ch10-03-lifetime-syntax.md +++ b/src/ch10-03-lifetime-syntax.md @@ -4,36 +4,42 @@ ## ライフタイムで参照を検証する + +ライフタイムは、すでに使ってきましたが、もう一つの種類のジェネリクスです。 +ライフタイムは、型が欲しい振る舞いを持つことを保証するのではなく、必要な間だけ参照が有効であることを保証します。 + 第4章の[「参照と借用」][references-and-borrowing]節で議論しなかった詳細の一つに、Rustにおいて参照は全てライフタイムを保持するということがあります。 ライフタイムとは、その参照が有効になるスコープのことです。多くの場合、型が推論されるように、 -大体の場合、ライフタイムも暗黙的に推論されます。複数の型の可能性があるときには、型を注釈しなければなりません。 +大体の場合、ライフタイムも暗黙的に推論されます。複数の型の可能性があるときにのみ、型を注釈しなければなりません。 同様に、参照のライフタイムがいくつか異なる方法で関係することがある場合には注釈しなければなりません。 コンパイラは、ジェネリックライフタイム引数を使用して関係を注釈し、実行時に実際の参照が確かに有効であることを保証することを要求するのです。 -ライフタイムの概念は、他のプログラミング言語の道具とはどこか異なり、間違いなくRustで一番際立った機能になっています。 +ライフタイムの注釈は、他の多くのプログラミング言語にはない概念ですので、馴染みのない気分になるでしょう。 この章では、ライフタイムの全体を解説することはしませんが、 -ライフタイム記法が必要となる最も一般的な場合について議論しますので、ライフタイムの概念について馴染むことができるでしょう。 +ライフタイム記法に遭遇するよくある場合について議論しますので、ライフタイムの概念について馴染むことができるでしょう。 -ライフタイムの主な目的は、ダングリング参照を回避することです。ダングリング参照によりプログラムは、 +ライフタイムの主な目的は、*ダングリング参照*を回避することです。ダングリング参照によりプログラムは、 参照するつもりだったデータ以外のデータを参照してしまいます。リスト10-17のプログラムを考えてください。 これには、外側のスコープと内側のスコープが含まれています。 ```rust,ignore,does_not_compile -{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/src/main.rs:here}} +{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/main.rs}} ``` -リスト10-17: 値がスコープを抜けてしまった参照を使用しようとする +リスト10-16: 値がスコープを抜けてしまった参照を使用しようとする -> 注釈: リスト10-17や10-18、10-24では、変数に初期値を与えずに宣言しているので、変数名は外側のスコープに存在します。 +> 注釈: リスト10-16や10-17、10-23では、変数に初期値を与えずに宣言しているので、変数名は外側のスコープに存在します。 > 初見では、これはRustにはnull値が存在しないということと衝突しているように見えるかもしれません。 > しかしながら、値を与える前に変数を使用しようとすれば、コンパイルエラーになり、 > 確かにRustではnull値は許可されていないことがわかります。 @@ -82,7 +88,7 @@ The outer scope declares a variable named `r` with no initial value, and the inner scope declares a variable named `x` with the initial value of 5. Inside the inner scope, we attempt to set the value of `r` as a reference to `x`. Then the inner scope ends, and we attempt to print the value in `r`. This code won’t -compile because the value `r` is referring to has gone out of scope before we +compile because what the value `r` is referring to has gone out of scope before we try to use it. Here is the error message: --> @@ -92,7 +98,7 @@ try to use it. Here is the error message: このコードはコンパイルできません。こちらがエラーメッセージです: ```console -{{#include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/output.txt}} +{{#include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/output.txt}} ``` Rustコンパイラには、スコープを比較して全ての借用が有効であるかを決定する*借用チェッカー*があります。 -リスト10-18は、リスト10-17と同じコードを示していますが、変数のライフタイムを表示する注釈が付いています。 +リスト10-17は、リスト10-16と同じコードを示していますが、変数のライフタイムを表示する注釈が付いています。 ```rust,ignore,does_not_compile -{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/src/main.rs:here}} +{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/src/main.rs}} ``` -リスト10-18: それぞれ`'a`と`'b`と名付けられた`r`と`x`のライフタイムの注釈 +リスト10-17: それぞれ`'a`と`'b`と名付けられた`r`と`x`のライフタイムの注釈 -リスト10-19でコードを修正したので、ダングリング参照はなくなり、エラーなくコンパイルできます。 +リスト10-18でコードを修正したので、ダングリング参照はなくなり、エラーなくコンパイルできます。 ```rust -{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/src/main.rs:here}} +{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/src/main.rs}} ``` -リスト10-19: データのライフタイムが参照より長いので、有効な参照 +リスト10-18: データのライフタイムが参照より長いので、有効な参照 2つの文字列スライスのうち、長い方を返す関数を書きましょう。この関数は、 2つの文字列スライスを取り、1つの文字列スライスを返します。`longest`関数の実装完了後、 -リスト10-20のコードは、`The longest string is abcd`と出力するはずです。 +リスト10-19のコードは、`The longest string is abcd`と出力するはずです。 -リスト10-20: `longest`関数を呼び出して2つの文字列スライスのうち長い方を探す`main`関数 +リスト10-19: `longest`関数を呼び出して2つの文字列スライスのうち長い方を探す`main`関数 -関数に取ってほしい引数が文字列スライス、つまり参照であることに注意してください。 +関数に取ってほしい引数が文字列ではなく文字列スライス、つまり参照であることに注意してください。 何故なら、`longest`関数に引数の所有権を奪ってほしくないからです。 -リスト10-20で使用している引数が、我々が必要としているものである理由についてもっと詳しい議論は、 +リスト10-19で使用している引数が、我々が必要としているものである理由についてもっと詳しい議論は、 第4章の[「引数としての文字列スライス」][string-slices-as-parameters]節をご参照ください。 -リスト10-21に示すように`longest`関数を実装しようとしたら、コンパイルできないでしょう。 +リスト10-20に示すように`longest`関数を実装しようとしたら、コンパイルできないでしょう。 -リスト10-21: 2つの文字列スライスのうち長い方を返すけれども、コンパイルできない`longest`関数の実装 +リスト10-20: 2つの文字列スライスのうち長い方を返すけれども、コンパイルできない`longest`関数の実装 この関数を定義する際、この関数に渡される具体的な値がわからないので、`if`ケースと`else`ケースのどちらが実行されるかわからないのです。 -また、リスト10-18と10-19で、返す参照が常に有効であるかを決定したときのようにスコープを見ることも、渡される参照の具体的なライフタイムがわからないのでできないのです。 +また、リスト10-17と10-18で、返す参照が常に有効であるかを決定したときのようにスコープを見ることも、渡される参照の具体的なライフタイムがわからないのでできないのです。 借用チェッカーもこれを決定することはできません。`x`と`y`のライフタイムがどう戻り値のライフタイムと関係するかわからないからです。 このエラーを修正するために、借用チェッカーが解析を実行できるように、参照間の関係を定義するジェネリックなライフタイム引数を追加しましょう。 @@ -309,29 +315,29 @@ perform its analysis. ### ライフタイム注釈記法 -ライフタイム注釈は、いかなる参照の生存期間も変えることはありません。シグニチャにジェネリックな型引数を指定された -関数が、あらゆる型を受け取ることができるのと同様に、ジェネリックなライフタイム引数を指定された関数は、 -あらゆるライフタイムの参照を受け取ることができます。ライフタイム注釈は、ライフタイムに影響することなく、 -複数の参照のライフタイムのお互いの関係を記述します。 +ライフタイム注釈は、いかなる参照の生存期間も変えることはありません。むしろ、ライフタイムに影響することなく、 +複数の参照のライフタイムのお互いの関係を記述します。シグニチャにジェネリックな型引数を指定された関数が、 +あらゆる型を受け取ることができるのと同様に、ジェネリックなライフタイム引数を指定された関数は、 +あらゆるライフタイムの参照を受け取ることができます。 ライフタイム注釈は、少し不自然な記法です: ライフタイム引数の名前はアポストロフィー(`'`)で始まらなければならず、 -通常全部小文字で、ジェネリック型のようにとても短いです。多くの人は、`'a`という名前を使います。 +通常全部小文字で、ジェネリック型のようにとても短いです。 +多くの人は、最初のライフライム注釈に対して`'a`という名前を使います。 ライフタイム引数注釈は、参照の`&`の後に配置し、注釈と参照の型を区別するために空白を1つ使用します。 -1つのライフタイム注釈それだけでは、大して意味はありません。注釈は、複数の参照のジェネリックなライフタイム引数が、 -お互いにどう関係するかをコンパイラに指示することを意図しているからです。例えば、 -ライフタイム`'a`付きの`i32`への参照となる引数`first`のある関数があるとしましょう。 -この関数にはさらに、`'a`のライフタイム付きの`i32`への別の参照となる`second`という別の引数もあります。 -ライフタイム注釈は、`first`と`second`の参照がどちらもこのジェネリックなライフタイムと同じだけ生きることを示唆します。 +1つのライフタイム注釈それだけでは、大して意味はありません。 +注釈は、複数の参照のジェネリックなライフタイム引数が、お互いにどう関係するかをコンパイラに指示することを意図しているからです。 +`longest`関数を例に、ライフタイム注釈が互いにどう関連していくのか、詳しく見ていきましょう。 + +関数シグネチャでライフタイム注釈を使用するには、ジェネリック*型*引数でやったのとまったく同じように、 +関数名と引数リストの間の山カッコの中にジェネリックな*ライフタイム*引数を宣言します。 + + -さて、`longest`関数を例にライフタイム注釈を詳しく見ていきましょう。ジェネリックな型引数同様、 -関数名と引数リストの間の山カッコの中にジェネリックなライフタイム引数を宣言します。 -このシグニチャで表現したい制約は、引数の全ての参照と戻り値が同じライフタイムを持つことです。 -リスト10-22に示すように、ライフタイムを`'a`と名付け、それを各参照に付与します。 +このシグニチャで以下の制約を表現したいです: +返される参照は、両引数が有効である限り、有効になります。 +これが引数と戻り値の間のライフタイムの関係です。 +リスト10-21に示すように、ライフタイムを`'a`と名付け、それを各参照に付与します。 -リスト10-22: シグニチャの全参照が同じライフタイム`'a`を持つと指定した`longest`関数の定義 +リスト10-21: シグニチャの全参照が同じライフタイム`'a`を持つと指定した`longest`関数の定義 -このコードはコンパイルでき、リスト10-20の`main`関数とともに使用したら、欲しい結果になるはずです。 +このコードはコンパイルでき、リスト10-19の`main`関数とともに使用したら、欲しい結果になるはずです。 + +これで関数シグニチャは、何らかのライフタイム`'a`に対して、関数は2つの引数を取り、 +どちらも少なくともライフタイム`'a`と同じだけ生きる文字列スライスであるとコンパイラに教えるようになりました。 +また、この関数シグニチャは、関数から返る文字列スライスも少なくともライフタイム`'a`と同じだけ生きると、 +コンパイラに教えています。 +実際には、`longest`関数が返す参照のライフタイムは、関数実引数によって参照される値のうち、小さい方のライフタイムと同じであるという事です。 +これらの関係は、まさに私たちがコンパイラにこのコードを解析するときに使用してほしかったものです。 + + -これで関数シグニチャは、何らかのライフタイム`'a`に対して、関数は2つの引数を取り、 -どちらも少なくともライフタイム`'a`と同じだけ生きる文字列スライスであるとコンパイラに教えるようになりました。 -また、この関数シグニチャは、関数から返る文字列スライスも少なくともライフタイム`'a`と同じだけ生きると、 -コンパイラに教えています。 -実際には、`longest`関数が返す参照のライフタイムは、渡された参照のうち、小さい方のライフタイムと同じであるという事です。 -これらの制約は、まさに私たちがコンパイラに保証してほしかったものです。 - この関数シグニチャでライフタイム引数を指定する時、渡されたり、返したりした、いかなる値のライフタイムも変更していないことを思い出してください。 むしろ、借用チェッカーは、これらの制約を守らない値全てを拒否するべきと指定しています。 `longest`関数は、`x`と`y`の正確な生存期間を知っている必要はなく、 @@ -445,18 +456,23 @@ substituted for `'a` that will satisfy this signature. 関数にライフタイムを注釈するときは、注釈は関数の本体ではなくシグニチャに付与します。 -コンパイラは注釈がなくとも関数内のコードを解析できます。しかしながら、 -関数に関数外からの参照や関数外への参照がある場合、コンパイラが引数や戻り値のライフタイムを自力で解決することはほとんど不可能になります。 -そのライフタイムは、関数が呼び出される度に異なる可能性があります。このために、手動でライフタイムを注釈する必要があるのです。 +ライフタイム注釈は、シグニチャ内の型がそうであるように、その関数の契約の一部を構成します。 +関数シグニチャにライフタイムの契約を含めることで、コンパイラが行う解析をより簡潔にすることができます。 +関数の注釈や呼ばれる状況に問題がある場合に、コンパイラのエラーはより正確にコードと制約の問題のある部分を示すことができます。 +もしRustコンパイラが、プログラムが意図するライフタイムの関係についてこれより深く推論を行うとしたら、 +コンパイラは、問題の原因から何ステップも離れたコードを指し示すことしかできなくなるかもしれません。 ライフタイム注釈が異なる具体的なライフタイムを持つ参照を渡すことで`longest`関数を制限する方法を見ましょう。 -リスト10-23はそのシンプルな例です。 +リスト10-22はそのシンプルな例です。 -リスト10-23: 異なる具体的なライフタイムを持つ`String`値への参照で`longest`関数を使用する +リスト10-22: 異なる具体的なライフタイムを持つ`String`値への参照で`longest`関数を使用する この例において、`string1`は外側のスコープの終わりまで有効で、`string2`は内側のスコープの終わりまで有効、 そして`result`は内側のスコープの終わりまで有効な何かを参照しています。このコードを実行すると、 -借用チェッカーがこのコードを良しとするのがわかるでしょう。要するに、コンパイルでき、 +借用チェッカーが良しとするのがわかるでしょう。要するに、コンパイルでき、 `The longest string is long string is long`と出力するのです。 次に、`result`の参照のライフタイムが2つの引数の小さい方のライフタイムになることを示す例を試しましょう。 `result`変数の宣言を内側のスコープの外に移すものの、`result`変数への代入は`string2`のスコープ内に残したままにします。 それから`result`を使用する`println!`を内側のスコープの外、内側のスコープが終わった後に移動します。 -リスト10-24のコードはコンパイルできません。 +リスト10-23のコードはコンパイルできません。 -リスト10-24: `string2`がスコープを抜けてから`result`を使用しようとする +リスト10-23: `string2`がスコープを抜けてから`result`を使用しようとする このコードのコンパイルを試みると、こんなエラーになります: ```console -{{#include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/output.txt}} +{{#include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/output.txt}} ``` 人間からしたら、`string1`は`string2`よりも長く、それ故に`result`が`string1`への参照を含んでいることは @@ -579,7 +595,7 @@ disallows the code in Listing 10-24 as possibly having an invalid reference. `string1`への参照は`println!`にとって有効でしょう。ですが、コンパイラはこの場合、 参照が有効であると見なせません。`longest`関数から返ってくる参照のライフタイムは、 渡した参照のうちの小さい方と同じだとコンパイラに指示しました。したがって、 -借用チェッカーは、リスト10-24のコードを無効な参照がある可能性があるとして許可しないのです。 +借用チェッカーは、リスト10-23のコードを無効な参照がある可能性があるとして許可しないのです。 -この例では、引数`x`と戻り値に対してライフタイム引数`'a`を指定しましたが、引数`y`には指定していません。 +引数`x`と戻り値に対してライフタイム引数`'a`を指定しましたが、引数`y`には指定していません。 `y`のライフタイムは`x`や戻り値のライフタイムとは何の関係もないからです。 関数から参照を返す際、戻り値型のライフタイム引数は、引数のうちどれかのライフタイム引数と一致する必要があります。 返される参照が引数のどれかを参照*していない*ならば、この関数内で生成された値を参照しているはずです。 -すると、その値は関数の末端でスコープを抜けるので、これはダングリング参照になるでしょう。 +しかしながら、その値は関数の末端でスコープを抜けるので、これはダングリング参照になるでしょう。 以下に示す、コンパイルできない`longest`関数の未完成の実装を考えてください: -ここまで、所有された型を保持する構造体だけを定義してきました。構造体に参照を保持させることもできますが、 +ここまで定義してきた構造体はすべて所有された型を保持しています。参照を保持する構造体を定義することもできますが、 その場合、構造体定義の全参照にライフタイム注釈を付け加える必要があるでしょう。 -リスト10-25には、文字列スライスを保持する`ImportantExcerpt`(重要な一節)という構造体があります。 +リスト10-24には、文字列スライスを保持する`ImportantExcerpt`(重要な一節)という構造体があります。 -リスト10-25: 参照を含む構造体なので、定義にライフタイム注釈が必要 +リスト10-24: ライフタイム注釈を必要とする、参照を含む構造体 -この構造体には文字列スライスを保持する1つのフィールド、`part`があり、これは参照です。 +この構造体には文字列スライスを保持する単一のフィールド、`part`があり、これは参照です。 ジェネリックなデータ型同様、構造体名の後、山カッコの中にジェネリックなライフタイム引数の名前を宣言するので、 構造体定義の本体でライフタイム引数を使用できます。この注釈は、`ImportantExcerpt`のインスタンスが、 `part`フィールドに保持している参照よりも長生きしないことを意味します。 @@ -763,12 +780,12 @@ the `ImportantExcerpt` goes out of scope, so the reference in the 全参照にはライフタイムがあり、参照を使用する関数や構造体にはライフタイム引数を指定する必要があることを学びました。 -しかし、リスト4-9にあった関数(リスト10-26に再度示しました)はライフタイム注釈なしでコンパイルできました。 +しかし、リスト4-9にあった関数(リスト10-25に再度示しました)はライフタイム注釈なしでコンパイルできました。 -リスト10-26: リスト4-9で定義した、引数と戻り値型が参照であるにも関わらず、ライフタイム注釈なしでコンパイルできた関数 +リスト10-25: リスト4-9で定義した、引数と戻り値型が参照であるにも関わらず、ライフタイム注釈なしでコンパイルできた関数 省略規則は、完全な推論を提供しません。コンパイラが決定的に規則を適用できるけれども、 参照が保持するライフタイムに関してそれでも曖昧性があるなら、コンパイラは、残りの参照がなるべきライフタイムを推測しません。 -この場合コンパイラは、それらを推測するのではなくエラーを与えます。 -これらは、参照がお互いにどう関係するかを指定するライフタイム注釈を追記することで解決できます。 +コンパイラはそれらを推測するのではなく、ライフタイム注釈を追記することで解決できるようなエラーを与えます。 -コンパイラは3つの規則を活用し、明示的な注釈がない時に、参照がどんなライフタイムになるかを計算します。 +コンパイラは3つの規則を活用し、明示的な注釈がない時に、参照のライフタイムを計算します。 最初の規則は入力ライフタイムに適用され、2番目と3番目の規則は出力ライフタイムに適用されます。 コンパイラが3つの規則の最後まで到達し、それでもライフタイムを割り出せない参照があったら、 コンパイラはエラーで停止します。 これらのルールは`fn`の定義にも`impl`ブロックにも適用されます。 -最初の規則は、参照である各引数は、独自のライフタイム引数を得るというものです。換言すれば、 -1引数の関数は、1つのライフタイム引数を得るということです: `fn foo<'a>(x: &'a i32)`; +最初の規則は、コンパイラは参照である各引数に、ライフタイム引数を割り当てるというものです。 +換言すれば、1引数の関数は、1つのライフタイム引数を得るということです: `fn foo<'a>(x: &'a i32)`; 2つ引数のある関数は、2つの個別のライフタイム引数を得ます: `fn foo<'a, 'b>(x: &'a i32, y: &'b i32)`; 以下同様。 @@ -897,10 +912,10 @@ lifetime is assigned to all output lifetime parameters: `fn foo<'a>(x: &'a i32) `fn foo<'a>(x: &'a i32) -> &'a i32`。 3番目の規則は、複数の入力ライフタイム引数があるけれども、メソッドなのでそのうちの一つが`&self`や`&mut self`だったら、 @@ -908,13 +923,13 @@ much nicer to read and write because fewer symbols are necessary. この3番目の規則により、必要なシンボルの数が減るので、メソッドが遥かに読み書きしやすくなります。 -コンパイラの立場になってみましょう。これらの規則を適用して、リスト10-26の`first_word`関数のシグニチャの参照のライフタイムが何か計算します。 +コンパイラの立場になってみましょう。これらの規則を適用して、リスト10-25の`first_word`関数のシグニチャの参照のライフタイムを計算します。 シグニチャは、参照に紐づけられるライフタイムがない状態から始まります: ```rust,ignore @@ -958,10 +973,10 @@ the lifetimes in this function signature. -別の例に目を向けましょう。今回は、リスト10-21で取り掛かったときにはライフタイム引数がなかった`longest`関数です: +別の例に目を向けましょう。今回は、リスト10-20で取り掛かったときにはライフタイム引数がなかった`longest`関数です: ```rust,ignore fn longest(x: &str, y: &str) -> &str { @@ -985,13 +1000,13 @@ input lifetime. The third rule doesn’t apply either, because `longest` is a function rather than a method, so none of the parameters are `self`. After working through all three rules, we still haven’t figured out what the return type’s lifetime is. This is why we got an error trying to compile the code in -Listing 10-21: the compiler worked through the lifetime elision rules but still +Listing 10-20: the compiler worked through the lifetime elision rules but still couldn’t figure out all the lifetimes of the references in the signature. --> 2つ以上入力ライフタイムがあるので、2番目の規則は適用されないとわかります。また3番目の規則も適用されません。 `longest`はメソッドではなく関数なので、どの引数も`self`ではないのです。3つの規則全部を適用した後でも、 -まだ戻り値型のライフタイムが判明していません。このために、リスト10-21でこのコードをコンパイルしようとしてエラーになったのです: +まだ戻り値型のライフタイムが判明していません。このために、リスト10-20でこのコードをコンパイルしようとしてエラーになったのです: コンパイラは、ライフタイム省略規則全てを適用したけれども、シグニチャの参照全部のライフタイムを計算できなかったのです。 `impl`ブロック内のメソッドシグニチャでは、参照は構造体のフィールドの参照のライフタイムに紐づいている可能性と、 独立している可能性があります。加えて、ライフタイム省略規則により、メソッドシグニチャでライフタイム注釈が必要なくなることがよくあります。 -リスト10-25で定義した`ImportantExcerpt`という構造体を使用した例をいくつか見てみましょう。 +リスト10-24で定義した`ImportantExcerpt`という構造体を使用した例をいくつか見てみましょう。 -議論する必要のある1種の特殊なライフタイムが、`'static`であり、これは、この参照がプログラムの全期間生存*できる*事を意味します。 +議論する必要のある1種の特殊なライフタイムが`'static`であり、これは影響を受ける参照がプログラムの全期間生存*できる*ことを示します。 文字列リテラルは全て`'static`ライフタイムになり、次のように注釈できます: ```rust @@ -1115,16 +1130,15 @@ is always available. Therefore, the lifetime of all string literals is You might see suggestions to use the `'static` lifetime in error messages. But before specifying `'static` as the lifetime for a reference, think about whether the reference you have actually lives the entire lifetime of your -program or not. You might consider whether you want it to live that long, even -if it could. Most of the time, the problem results from attempting to create a -dangling reference or a mismatch of the available lifetimes. In such cases, the -solution is fixing those problems, not specifying the `'static` lifetime. +program or not, and whether you want it to. Most of the time, an error message +suggesting the `'static` lifetime results from attempting to create a dangling +reference or a mismatch of the available lifetimes. In such cases, the solution +is fixing those problems, not specifying the `'static` lifetime. --> エラーメッセージで、`'static`ライフタイムを使用するよう勧める提言を見かける可能性があります。 -ですが、参照に対してライフタイムとして`'static`を指定する前に、今ある参照が本当にプログラムの全期間生きるかどうか考えてください。 -それが可能であったとしても、参照がそれだけの期間生きてほしいのかどうか考慮するのも良いでしょう。 -ほとんどの場合、問題は、ダングリング参照を生成しようとしているか、利用可能なライフタイムの不一致が原因です。 +ですが、参照に対してライフタイムとして`'static`を指定する前に、今ある参照が本当にプログラムの全期間生きるかどうか、そして生きてほしいのかどうか、考えてください。 +ほとんどの場合、`'static`ライフタイムを提案するエラーメッセージは、ダングリング参照を生成しようとしているか、利用可能なライフタイムの不一致が原因です。 そのような場合、解決策はその問題を修正することであり、`'static`ライフタイムを指定することではありません。 -これがリスト10-22からの2つの文字列のうち長い方を返す`longest`関数ですが、 +これがリスト10-21からの2つの文字列のうち長い方を返す`longest`関数ですが、 ジェネリックな型`T`の`ann`という追加の引数があり、これは`where`節で指定されているように、 `Display`トレイトを実装するあらゆる型で埋めることができます。 -この追加の引数は、関数が文字列スライスの長さを比較する前に出力されるので、 -`Display`トレイト境界が必要なのです。ライフタイムは一種のジェネリックなので、 -ライフタイム引数`'a`とジェネリックな型引数`T`が関数名の後、山カッコ内の同じリストに収まっています。 +この追加の引数は`{}`を使用して出力されるので、`Display`トレイト境界が必要なのです。 +ライフタイムは一種のジェネリックなので、ライフタイム引数`'a`とジェネリックな型引数`T`が関数名の後、 +山カッコ内の同じリストに収まっています。 + [references-and-borrowing]: ch04-02-references-and-borrowing.html#参照と借用 [string-slices-as-parameters]: From 09725f3921c3ff5354eebbf0259d98c6defacf23 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:04 +0900 Subject: [PATCH 12/22] =?UTF-8?q?ch11=20=E8=87=AA=E5=8B=95=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=82=92=E6=9B=B8=E3=81=8F=E3=81=AE=E5=92=8C?= =?UTF-8?q?=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-11-01/Cargo.lock | 3 +- .../listing-11-01/Cargo.toml | 5 +- .../listing-11-01/output.txt | 6 +- .../listing-11-01/src/lib.rs | 13 +- .../listing-11-03/Cargo.toml | 3 +- .../listing-11-03/output.txt | 11 +- .../listing-11-03/src/lib.rs | 2 - .../listing-11-05/Cargo.toml | 3 +- .../listing-11-05/src/lib.rs | 2 - .../listing-11-06/Cargo.toml | 3 +- .../listing-11-06/output.txt | 6 +- .../listing-11-06/src/lib.rs | 2 - .../listing-11-07/Cargo.toml | 3 +- .../listing-11-07/output.txt | 6 +- .../listing-11-07/src/lib.rs | 4 - .../listing-11-08/Cargo.toml | 3 +- .../listing-11-08/output.txt | 8 +- .../listing-11-08/src/lib.rs | 4 - .../listing-11-09/Cargo.toml | 3 +- .../listing-11-09/src/lib.rs | 7 +- .../listing-11-10/Cargo.toml | 3 +- .../listing-11-10/output.txt | 15 +- .../listing-11-10/src/lib.rs | 5 +- .../listing-11-11/Cargo.toml | 3 +- .../listing-11-11/output.txt | 6 +- .../listing-11-12/Cargo.toml | 3 +- .../listing-11-12/src/lib.rs | 4 - .../listing-11-13/Cargo.toml | 3 +- .../listing-11-13/output.txt | 12 +- .../Cargo.toml | 3 +- .../output.txt | 6 +- .../src/lib.rs | 4 - .../Cargo.toml | 3 +- .../output.txt | 6 +- .../src/lib.rs | 2 - .../Cargo.toml | 3 +- .../output.txt | 15 +- .../src/lib.rs | 2 - .../no-listing-04-bug-in-add-two/Cargo.toml | 3 +- .../no-listing-04-bug-in-add-two/output.txt | 15 +- .../no-listing-04-bug-in-add-two/src/lib.rs | 2 - .../no-listing-05-greeter/Cargo.toml | 3 +- .../no-listing-05-greeter/src/lib.rs | 4 - .../no-listing-06-greeter-with-bug/Cargo.toml | 3 +- .../no-listing-06-greeter-with-bug/output.txt | 11 +- .../no-listing-06-greeter-with-bug/src/lib.rs | 2 - .../Cargo.toml | 3 +- .../output.txt | 11 +- .../no-listing-08-guess-with-bug/Cargo.toml | 3 +- .../no-listing-08-guess-with-bug/output.txt | 8 +- .../no-listing-08-guess-with-bug/src/lib.rs | 2 - .../Cargo.toml | 3 +- .../output.txt | 15 +- .../src/lib.rs | 2 +- .../no-listing-10-result-in-tests/Cargo.toml | 3 +- .../no-listing-11-ignore-a-test/Cargo.toml | 3 +- .../no-listing-11-ignore-a-test/output.txt | 6 +- .../no-listing-11-ignore-a-test/src/lib.rs | 5 +- .../Cargo.toml | 3 +- .../output.txt | 14 +- .../tests/common.rs | 1 + .../Cargo.toml | 3 +- .../output-only-01-show-output/Cargo.toml | 3 +- .../output-only-01-show-output/output.txt | 15 +- .../output-only-02-single-test/Cargo.toml | 3 +- .../output-only-02-single-test/output.txt | 4 +- .../output-only-03-multiple-tests/Cargo.toml | 3 +- .../output-only-03-multiple-tests/output.txt | 4 +- .../output-only-04-running-ignored/Cargo.toml | 3 +- .../output-only-04-running-ignored/output.txt | 6 +- .../output-only-04-running-ignored/src/lib.rs | 2 - .../Cargo.toml | 3 +- .../output.txt | 4 +- src/ch11-00-testing.md | 26 +- src/ch11-01-writing-tests.md | 467 +++++++++--------- src/ch11-02-running-tests.md | 247 +++------ src/ch11-03-test-organization.md | 355 ++++++------- 77 files changed, 638 insertions(+), 830 deletions(-) diff --git a/listings/ch11-writing-automated-tests/listing-11-01/Cargo.lock b/listings/ch11-writing-automated-tests/listing-11-01/Cargo.lock index d37189b33..8b8c69d33 100644 --- a/listings/ch11-writing-automated-tests/listing-11-01/Cargo.lock +++ b/listings/ch11-writing-automated-tests/listing-11-01/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "adder" version = "0.1.0" - diff --git a/listings/ch11-writing-automated-tests/listing-11-01/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-01/Cargo.toml index 0e3940cf1..b7d36d44c 100644 --- a/listings/ch11-writing-automated-tests/listing-11-01/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-01/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-01/output.txt b/listings/ch11-writing-automated-tests/listing-11-01/output.txt index aa4b0990d..c3e812ed8 100644 --- a/listings/ch11-writing-automated-tests/listing-11-01/output.txt +++ b/listings/ch11-writing-automated-tests/listing-11-01/output.txt @@ -1,16 +1,16 @@ $ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.57s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 1 test test tests::it_works ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/listing-11-01/src/lib.rs b/listings/ch11-writing-automated-tests/listing-11-01/src/lib.rs index 8e678421e..7d12d9af8 100644 --- a/listings/ch11-writing-automated-tests/listing-11-01/src/lib.rs +++ b/listings/ch11-writing-automated-tests/listing-11-01/src/lib.rs @@ -1,11 +1,14 @@ -// ANCHOR: here +pub fn add(left: usize, right: usize) -> usize { + left + right +} + #[cfg(test)] mod tests { + use super::*; + #[test] fn it_works() { - assert_eq!(2 + 2, 4); + let result = add(2, 2); + assert_eq!(result, 4); } } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/listing-11-03/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-03/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/listing-11-03/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-03/output.txt b/listings/ch11-writing-automated-tests/listing-11-03/output.txt index c39456f81..194755691 100644 --- a/listings/ch11-writing-automated-tests/listing-11-03/output.txt +++ b/listings/ch11-writing-automated-tests/listing-11-03/output.txt @@ -1,7 +1,7 @@ $ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.72s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 2 tests test tests::another ... FAILED @@ -10,13 +10,14 @@ test tests::exploration ... ok failures: ---- tests::another stdout ---- -thread 'main' panicked at 'Make this test fail', src/lib.rs:10:9 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::another' panicked at src/lib.rs:10:9: +Make this test fail +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::another -test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch11-writing-automated-tests/listing-11-03/src/lib.rs b/listings/ch11-writing-automated-tests/listing-11-03/src/lib.rs index e746508dc..02c3a3ba7 100644 --- a/listings/ch11-writing-automated-tests/listing-11-03/src/lib.rs +++ b/listings/ch11-writing-automated-tests/listing-11-03/src/lib.rs @@ -13,5 +13,3 @@ mod tests { } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/listing-11-05/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-05/Cargo.toml index 32efee50a..2447c67f5 100644 --- a/listings/ch11-writing-automated-tests/listing-11-05/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "rectangle" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-05/src/lib.rs b/listings/ch11-writing-automated-tests/listing-11-05/src/lib.rs index aad33554b..0f1bc4e08 100644 --- a/listings/ch11-writing-automated-tests/listing-11-05/src/lib.rs +++ b/listings/ch11-writing-automated-tests/listing-11-05/src/lib.rs @@ -11,5 +11,3 @@ impl Rectangle { } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/listing-11-06/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-06/Cargo.toml index 32efee50a..2447c67f5 100644 --- a/listings/ch11-writing-automated-tests/listing-11-06/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "rectangle" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-06/output.txt b/listings/ch11-writing-automated-tests/listing-11-06/output.txt index 241997c15..dad02b460 100644 --- a/listings/ch11-writing-automated-tests/listing-11-06/output.txt +++ b/listings/ch11-writing-automated-tests/listing-11-06/output.txt @@ -1,16 +1,16 @@ $ cargo test Compiling rectangle v0.1.0 (file:///projects/rectangle) Finished test [unoptimized + debuginfo] target(s) in 0.66s - Running target/debug/deps/rectangle-6584c4561e48942e + Running unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e) running 1 test test tests::larger_can_hold_smaller ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests rectangle running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/listing-11-06/src/lib.rs b/listings/ch11-writing-automated-tests/listing-11-06/src/lib.rs index a02395313..6ad1512ed 100644 --- a/listings/ch11-writing-automated-tests/listing-11-06/src/lib.rs +++ b/listings/ch11-writing-automated-tests/listing-11-06/src/lib.rs @@ -30,5 +30,3 @@ mod tests { } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/listing-11-07/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-07/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/listing-11-07/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-07/output.txt b/listings/ch11-writing-automated-tests/listing-11-07/output.txt index dc1a5212e..fa02835bd 100644 --- a/listings/ch11-writing-automated-tests/listing-11-07/output.txt +++ b/listings/ch11-writing-automated-tests/listing-11-07/output.txt @@ -1,16 +1,16 @@ $ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.58s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 1 test test tests::it_adds_two ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/listing-11-07/src/lib.rs b/listings/ch11-writing-automated-tests/listing-11-07/src/lib.rs index 534073276..3e5d66bfa 100644 --- a/listings/ch11-writing-automated-tests/listing-11-07/src/lib.rs +++ b/listings/ch11-writing-automated-tests/listing-11-07/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here pub fn add_two(a: i32) -> i32 { a + 2 } @@ -12,6 +11,3 @@ mod tests { assert_eq!(4, add_two(2)); } } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/listing-11-08/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-08/Cargo.toml index 922762ab1..4e348c8d2 100644 --- a/listings/ch11-writing-automated-tests/listing-11-08/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "guessing_game" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-08/output.txt b/listings/ch11-writing-automated-tests/listing-11-08/output.txt index 47a50f7e1..caca1542f 100644 --- a/listings/ch11-writing-automated-tests/listing-11-08/output.txt +++ b/listings/ch11-writing-automated-tests/listing-11-08/output.txt @@ -1,16 +1,16 @@ $ cargo test Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Finished test [unoptimized + debuginfo] target(s) in 0.58s - Running target/debug/deps/guessing_game-57d70c3acb738f4d + Running unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d) running 1 test -test tests::greater_than_100 ... ok +test tests::greater_than_100 - should panic ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests guessing_game running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/listing-11-08/src/lib.rs b/listings/ch11-writing-automated-tests/listing-11-08/src/lib.rs index e1d513bf1..002aaa151 100644 --- a/listings/ch11-writing-automated-tests/listing-11-08/src/lib.rs +++ b/listings/ch11-writing-automated-tests/listing-11-08/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here pub struct Guess { value: i32, } @@ -24,6 +23,3 @@ mod tests { Guess::new(200); } } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/listing-11-09/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-09/Cargo.toml index 922762ab1..4e348c8d2 100644 --- a/listings/ch11-writing-automated-tests/listing-11-09/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "guessing_game" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-09/src/lib.rs b/listings/ch11-writing-automated-tests/listing-11-09/src/lib.rs index 3ad7c5138..38e234ad2 100644 --- a/listings/ch11-writing-automated-tests/listing-11-09/src/lib.rs +++ b/listings/ch11-writing-automated-tests/listing-11-09/src/lib.rs @@ -4,6 +4,7 @@ pub struct Guess { // ANCHOR: here // --snip-- + impl Guess { pub fn new(value: i32) -> Guess { if value < 1 { @@ -29,12 +30,10 @@ mod tests { use super::*; #[test] - //予想値は100以下でなければなりません - #[should_panic(expected = "Guess value must be less than or equal to 100")] + //100以下 + #[should_panic(expected = "less than or equal to 100")] fn greater_than_100() { Guess::new(200); } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/listing-11-10/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-10/Cargo.toml index 4e0f185af..f751864de 100644 --- a/listings/ch11-writing-automated-tests/listing-11-10/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "silly-function" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-10/output.txt b/listings/ch11-writing-automated-tests/listing-11-10/output.txt index 1621d796b..7a2b200ac 100644 --- a/listings/ch11-writing-automated-tests/listing-11-10/output.txt +++ b/listings/ch11-writing-automated-tests/listing-11-10/output.txt @@ -1,7 +1,7 @@ $ cargo test Compiling silly-function v0.1.0 (file:///projects/silly-function) Finished test [unoptimized + debuginfo] target(s) in 0.58s - Running target/debug/deps/silly_function-160869f38cff9166 + Running unittests src/lib.rs (target/debug/deps/silly_function-160869f38cff9166) running 2 tests test tests::this_test_will_fail ... FAILED @@ -11,15 +11,16 @@ failures: ---- tests::this_test_will_fail stdout ---- I got the value 8 -thread 'main' panicked at 'assertion failed: `(left == right)` - left: `5`, - right: `10`', src/lib.rs:19:9 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::this_test_will_fail' panicked at src/lib.rs:19:9: +assertion `left == right` failed + left: 5 + right: 10 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::this_test_will_fail -test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch11-writing-automated-tests/listing-11-10/src/lib.rs b/listings/ch11-writing-automated-tests/listing-11-10/src/lib.rs index 62d0fddbf..4f63cda3b 100644 --- a/listings/ch11-writing-automated-tests/listing-11-10/src/lib.rs +++ b/listings/ch11-writing-automated-tests/listing-11-10/src/lib.rs @@ -1,7 +1,5 @@ -fn main() {} - -// ANCHOR: here fn prints_and_returns_10(a: i32) -> i32 { + //{}という値を得た println!("I got the value {}", a); 10 } @@ -22,4 +20,3 @@ mod tests { assert_eq!(5, value); } } -// ANCHOR_END: here diff --git a/listings/ch11-writing-automated-tests/listing-11-11/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-11/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/listing-11-11/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-11/output.txt b/listings/ch11-writing-automated-tests/listing-11-11/output.txt index 59feae324..fe19c83c4 100644 --- a/listings/ch11-writing-automated-tests/listing-11-11/output.txt +++ b/listings/ch11-writing-automated-tests/listing-11-11/output.txt @@ -1,18 +1,18 @@ $ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.62s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 3 tests test tests::add_three_and_two ... ok test tests::add_two_and_two ... ok test tests::one_hundred ... ok -test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/listing-11-12/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-12/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/listing-11-12/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-12/src/lib.rs b/listings/ch11-writing-automated-tests/listing-11-12/src/lib.rs index 800b84f53..c3961b1f6 100644 --- a/listings/ch11-writing-automated-tests/listing-11-12/src/lib.rs +++ b/listings/ch11-writing-automated-tests/listing-11-12/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here pub fn add_two(a: i32) -> i32 { internal_adder(a, 2) } @@ -16,6 +15,3 @@ mod tests { assert_eq!(4, internal_adder(2, 2)); } } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/listing-11-13/Cargo.toml b/listings/ch11-writing-automated-tests/listing-11-13/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/listing-11-13/Cargo.toml +++ b/listings/ch11-writing-automated-tests/listing-11-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/listing-11-13/output.txt b/listings/ch11-writing-automated-tests/listing-11-13/output.txt index e213b9c38..22970e9e1 100644 --- a/listings/ch11-writing-automated-tests/listing-11-13/output.txt +++ b/listings/ch11-writing-automated-tests/listing-11-13/output.txt @@ -1,23 +1,23 @@ $ cargo test Compiling adder v0.1.0 (file:///projects/adder) - Finished test [unoptimized + debuginfo] target(s) in 0.73s - Running target/debug/deps/adder-92948b65e88960b4 + Finished test [unoptimized + debuginfo] target(s) in 1.31s + Running unittests src/lib.rs (target/debug/deps/adder-1082c4b063a8fbe6) running 1 test test tests::internal ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - Running target/debug/deps/integration_test-82e7799c1bc62298 + Running tests/integration_test.rs (target/debug/deps/integration_test-1082c4b063a8fbe6) running 1 test test it_adds_two ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/output.txt b/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/output.txt index 0f287fc56..8a3330844 100644 --- a/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/output.txt @@ -1,16 +1,16 @@ $ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.59s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 1 test test tests::exploration ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/src/lib.rs b/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/src/lib.rs index 2974d7273..330bddf6a 100644 --- a/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/src/lib.rs +++ b/listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here #[cfg(test)] mod tests { #[test] @@ -6,6 +5,3 @@ mod tests { assert_eq!(2 + 2, 4); } } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/Cargo.toml index 32efee50a..2447c67f5 100644 --- a/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "rectangle" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/output.txt b/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/output.txt index e95f4727e..30e45e525 100644 --- a/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/output.txt @@ -1,17 +1,17 @@ $ cargo test Compiling rectangle v0.1.0 (file:///projects/rectangle) Finished test [unoptimized + debuginfo] target(s) in 0.66s - Running target/debug/deps/rectangle-6584c4561e48942e + Running unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e) running 2 tests test tests::larger_can_hold_smaller ... ok test tests::smaller_cannot_hold_larger ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests rectangle running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/src/lib.rs b/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/src/lib.rs index 338ad0936..ee4fc45b9 100644 --- a/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/src/lib.rs +++ b/listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/src/lib.rs @@ -47,5 +47,3 @@ mod tests { } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/Cargo.toml index 32efee50a..2447c67f5 100644 --- a/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "rectangle" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/output.txt b/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/output.txt index 5a9fd811a..1c422f3f9 100644 --- a/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/output.txt @@ -1,7 +1,7 @@ $ cargo test Compiling rectangle v0.1.0 (file:///projects/rectangle) Finished test [unoptimized + debuginfo] target(s) in 0.66s - Running target/debug/deps/rectangle-6584c4561e48942e + Running unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e) running 2 tests test tests::larger_can_hold_smaller ... FAILED @@ -10,13 +10,16 @@ test tests::smaller_cannot_hold_larger ... ok failures: ---- tests::larger_can_hold_smaller stdout ---- -thread 'main' panicked at 'assertion failed: larger.can_hold(&smaller)', src/lib.rs:28:9 -(スレッド'main'はsrc/lib.rs:28:9の'assertion failed: larger.can_hold(&smaller)'でパニックしました) -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::larger_can_hold_smaller' panicked at src/lib.rs:28:9: +assertion failed: larger.can_hold(&smaller) +(スレッド'tests::larger_can_hold_smaller'はsrc/lib.rs:28:9でパニックしました: +アサーション失敗: larger.can_hold(&smaller)) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + failures: tests::larger_can_hold_smaller -test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/src/lib.rs b/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/src/lib.rs index 33a2dd0ac..f5968fcaf 100644 --- a/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/src/lib.rs +++ b/listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/src/lib.rs @@ -45,5 +45,3 @@ mod tests { assert!(!smaller.can_hold(&larger)); } } - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/output.txt b/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/output.txt index 7fb67743e..102479df6 100644 --- a/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/output.txt @@ -1,7 +1,7 @@ $ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.61s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 1 test test tests::it_adds_two ... FAILED @@ -9,15 +9,16 @@ test tests::it_adds_two ... FAILED failures: ---- tests::it_adds_two stdout ---- -thread 'main' panicked at 'assertion failed: `(left == right)` - left: `4`, - right: `5`', src/lib.rs:11:9 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::it_adds_two' panicked at src/lib.rs:11:9: +assertion `left == right` failed + left: 4 + right: 5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::it_adds_two -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/src/lib.rs b/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/src/lib.rs index 8b4534b4a..f18662526 100644 --- a/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/src/lib.rs +++ b/listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/src/lib.rs @@ -13,5 +13,3 @@ mod tests { assert_eq!(4, add_two(2)); } } - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/no-listing-05-greeter/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-05-greeter/Cargo.toml index c289e837a..90a826cf4 100644 --- a/listings/ch11-writing-automated-tests/no-listing-05-greeter/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-05-greeter/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "greeter" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-05-greeter/src/lib.rs b/listings/ch11-writing-automated-tests/no-listing-05-greeter/src/lib.rs index 4fcdbbf27..3ba3d8819 100644 --- a/listings/ch11-writing-automated-tests/no-listing-05-greeter/src/lib.rs +++ b/listings/ch11-writing-automated-tests/no-listing-05-greeter/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here pub fn greeting(name: &str) -> String { format!("Hello {}!", name) } @@ -13,6 +12,3 @@ mod tests { assert!(result.contains("Carol")); } } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/Cargo.toml index c289e837a..90a826cf4 100644 --- a/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "greeter" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/output.txt b/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/output.txt index 8f832a743..bbd42d04d 100644 --- a/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/output.txt @@ -1,7 +1,7 @@ $ cargo test Compiling greeter v0.1.0 (file:///projects/greeter) Finished test [unoptimized + debuginfo] target(s) in 0.91s - Running target/debug/deps/greeter-170b942eb5bf5e3a + Running unittests src/lib.rs (target/debug/deps/greeter-170b942eb5bf5e3a) running 1 test test tests::greeting_contains_name ... FAILED @@ -9,13 +9,14 @@ test tests::greeting_contains_name ... FAILED failures: ---- tests::greeting_contains_name stdout ---- -thread 'main' panicked at 'assertion failed: result.contains("Carol")', src/lib.rs:12:9 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::greeting_contains_name' panicked at src/lib.rs:12:9: +assertion failed: result.contains("Carol") +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::greeting_contains_name -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/src/lib.rs b/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/src/lib.rs index d516534e5..6f28fc52a 100644 --- a/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/src/lib.rs +++ b/listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/src/lib.rs @@ -14,5 +14,3 @@ mod tests { assert!(result.contains("Carol")); } } - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/Cargo.toml index c289e837a..90a826cf4 100644 --- a/listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "greeter" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/output.txt b/listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/output.txt index c3a735e4d..e6cc739c4 100644 --- a/listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/output.txt @@ -1,7 +1,7 @@ $ cargo test Compiling greeter v0.1.0 (file:///projects/greeter) Finished test [unoptimized + debuginfo] target(s) in 0.93s - Running target/debug/deps/greeter-170b942eb5bf5e3a + Running unittests src/lib.rs (target/debug/deps/greeter-170b942eb5bf5e3a) running 1 test test tests::greeting_contains_name ... FAILED @@ -9,13 +9,14 @@ test tests::greeting_contains_name ... FAILED failures: ---- tests::greeting_contains_name stdout ---- -thread 'main' panicked at 'Greeting did not contain name, value was `Hello!`', src/lib.rs:12:9 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::greeting_contains_name' panicked at src/lib.rs:12:9: +Greeting did not contain name, value was `Hello!` +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::greeting_contains_name -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/Cargo.toml index 922762ab1..4e348c8d2 100644 --- a/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "guessing_game" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/output.txt b/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/output.txt index c9a4fda93..9318d4ce0 100644 --- a/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/output.txt @@ -1,10 +1,10 @@ $ cargo test Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Finished test [unoptimized + debuginfo] target(s) in 0.62s - Running target/debug/deps/guessing_game-57d70c3acb738f4d + Running unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d) running 1 test -test tests::greater_than_100 ... FAILED +test tests::greater_than_100 - should panic ... FAILED failures: @@ -14,6 +14,6 @@ note: test did not panic as expected failures: tests::greater_than_100 -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/src/lib.rs b/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/src/lib.rs index 26fe853fa..62f2cef2e 100644 --- a/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/src/lib.rs +++ b/listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/src/lib.rs @@ -26,5 +26,3 @@ mod tests { Guess::new(200); } } - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/Cargo.toml index 922762ab1..4e348c8d2 100644 --- a/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "guessing_game" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/output.txt b/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/output.txt index f2b8ffc7c..6e80336e5 100644 --- a/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/output.txt @@ -1,23 +1,24 @@ $ cargo test Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Finished test [unoptimized + debuginfo] target(s) in 0.66s - Running target/debug/deps/guessing_game-57d70c3acb738f4d + Running unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d) running 1 test -test tests::greater_than_100 ... FAILED +test tests::greater_than_100 - should panic ... FAILED failures: ---- tests::greater_than_100 stdout ---- -thread 'main' panicked at 'Guess value must be greater than or equal to 1, got 200.', src/lib.rs:13:13 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::greater_than_100' panicked at src/lib.rs:13:13: +Guess value must be greater than or equal to 1, got 200. +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: panic did not contain expected string panic message: `"Guess value must be greater than or equal to 1, got 200."`, - expected substring: `"Guess value must be less than or equal to 100"` + expected substring: `"less than or equal to 100"` failures: tests::greater_than_100 -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/src/lib.rs b/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/src/lib.rs index 431f1487d..f11443140 100644 --- a/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/src/lib.rs +++ b/listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/src/lib.rs @@ -29,7 +29,7 @@ mod tests { use super::*; #[test] - #[should_panic(expected = "Guess value must be less than or equal to 100")] + #[should_panic(expected = "less than or equal to 100")] fn greater_than_100() { Guess::new(200); } diff --git a/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/output.txt b/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/output.txt index 8cf7475c5..c559de8d0 100644 --- a/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/output.txt @@ -1,17 +1,17 @@ $ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.60s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 2 tests test expensive_test ... ignored test it_works ... ok -test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/src/lib.rs b/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/src/lib.rs index 9a75301e3..9dab4d148 100644 --- a/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/src/lib.rs +++ b/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/src/lib.rs @@ -1,4 +1,3 @@ -// ANCHOR: here #[test] fn it_works() { assert_eq!(2 + 2, 4); @@ -7,8 +6,6 @@ fn it_works() { #[test] #[ignore] fn expensive_test() { + // 実行に1時間かかるコード // code that takes an hour to run } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/output.txt b/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/output.txt index 0637a1068..324d566ab 100644 --- a/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/output.txt +++ b/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/output.txt @@ -1,29 +1,29 @@ $ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.89s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 1 test test tests::internal ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - Running target/debug/deps/common-7064e1b6d2e271be + Running tests/common.rs (target/debug/deps/common-92948b65e88960b4) running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - Running target/debug/deps/integration_test-82e7799c1bc62298 + Running tests/integration_test.rs (target/debug/deps/integration_test-92948b65e88960b4) running 1 test test it_adds_two ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/tests/common.rs b/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/tests/common.rs index 5fb7a390a..bb4805991 100644 --- a/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/tests/common.rs +++ b/listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/tests/common.rs @@ -1,3 +1,4 @@ pub fn setup() { + // ここにライブラリテスト固有のコードが来る // setup code specific to your library's tests would go here } diff --git a/listings/ch11-writing-automated-tests/no-listing-13-fix-shared-test-code-problem/Cargo.toml b/listings/ch11-writing-automated-tests/no-listing-13-fix-shared-test-code-problem/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/no-listing-13-fix-shared-test-code-problem/Cargo.toml +++ b/listings/ch11-writing-automated-tests/no-listing-13-fix-shared-test-code-problem/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/output-only-01-show-output/Cargo.toml b/listings/ch11-writing-automated-tests/output-only-01-show-output/Cargo.toml index 4e0f185af..f751864de 100644 --- a/listings/ch11-writing-automated-tests/output-only-01-show-output/Cargo.toml +++ b/listings/ch11-writing-automated-tests/output-only-01-show-output/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "silly-function" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/output-only-01-show-output/output.txt b/listings/ch11-writing-automated-tests/output-only-01-show-output/output.txt index 901df6ae6..b8aae1fae 100644 --- a/listings/ch11-writing-automated-tests/output-only-01-show-output/output.txt +++ b/listings/ch11-writing-automated-tests/output-only-01-show-output/output.txt @@ -1,7 +1,7 @@ $ cargo test -- --show-output Compiling silly-function v0.1.0 (file:///projects/silly-function) Finished test [unoptimized + debuginfo] target(s) in 0.60s - Running target/debug/deps/silly_function-160869f38cff9166 + Running unittests src/lib.rs (target/debug/deps/silly_function-160869f38cff9166) running 2 tests test tests::this_test_will_fail ... FAILED @@ -20,15 +20,16 @@ failures: ---- tests::this_test_will_fail stdout ---- I got the value 8 -thread 'main' panicked at 'assertion failed: `(left == right)` - left: `5`, - right: `10`', src/lib.rs:19:9 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::this_test_will_fail' panicked at src/lib.rs:19:9: +assertion `left == right` failed + left: 5 + right: 10 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::this_test_will_fail -test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch11-writing-automated-tests/output-only-02-single-test/Cargo.toml b/listings/ch11-writing-automated-tests/output-only-02-single-test/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/output-only-02-single-test/Cargo.toml +++ b/listings/ch11-writing-automated-tests/output-only-02-single-test/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/output-only-02-single-test/output.txt b/listings/ch11-writing-automated-tests/output-only-02-single-test/output.txt index 9284de3d4..f2da98442 100644 --- a/listings/ch11-writing-automated-tests/output-only-02-single-test/output.txt +++ b/listings/ch11-writing-automated-tests/output-only-02-single-test/output.txt @@ -1,10 +1,10 @@ $ cargo test one_hundred Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.69s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 1 test test tests::one_hundred ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/output-only-03-multiple-tests/Cargo.toml b/listings/ch11-writing-automated-tests/output-only-03-multiple-tests/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/output-only-03-multiple-tests/Cargo.toml +++ b/listings/ch11-writing-automated-tests/output-only-03-multiple-tests/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/output-only-03-multiple-tests/output.txt b/listings/ch11-writing-automated-tests/output-only-03-multiple-tests/output.txt index 76c2c170d..255a051b5 100644 --- a/listings/ch11-writing-automated-tests/output-only-03-multiple-tests/output.txt +++ b/listings/ch11-writing-automated-tests/output-only-03-multiple-tests/output.txt @@ -1,11 +1,11 @@ $ cargo test add Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.61s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 2 tests test tests::add_three_and_two ... ok test tests::add_two_and_two ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/output-only-04-running-ignored/Cargo.toml b/listings/ch11-writing-automated-tests/output-only-04-running-ignored/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/output-only-04-running-ignored/Cargo.toml +++ b/listings/ch11-writing-automated-tests/output-only-04-running-ignored/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/output-only-04-running-ignored/output.txt b/listings/ch11-writing-automated-tests/output-only-04-running-ignored/output.txt index 6bddfdb82..b37868d3d 100644 --- a/listings/ch11-writing-automated-tests/output-only-04-running-ignored/output.txt +++ b/listings/ch11-writing-automated-tests/output-only-04-running-ignored/output.txt @@ -1,16 +1,16 @@ $ cargo test -- --ignored Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.61s - Running target/debug/deps/adder-92948b65e88960b4 + Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 1 test test expensive_test ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s Doc-tests adder running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch11-writing-automated-tests/output-only-04-running-ignored/src/lib.rs b/listings/ch11-writing-automated-tests/output-only-04-running-ignored/src/lib.rs index 9a75301e3..2290c699d 100644 --- a/listings/ch11-writing-automated-tests/output-only-04-running-ignored/src/lib.rs +++ b/listings/ch11-writing-automated-tests/output-only-04-running-ignored/src/lib.rs @@ -10,5 +10,3 @@ fn expensive_test() { // code that takes an hour to run } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch11-writing-automated-tests/output-only-05-single-integration/Cargo.toml b/listings/ch11-writing-automated-tests/output-only-05-single-integration/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch11-writing-automated-tests/output-only-05-single-integration/Cargo.toml +++ b/listings/ch11-writing-automated-tests/output-only-05-single-integration/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch11-writing-automated-tests/output-only-05-single-integration/output.txt b/listings/ch11-writing-automated-tests/output-only-05-single-integration/output.txt index dd915c35c..260beaa2d 100644 --- a/listings/ch11-writing-automated-tests/output-only-05-single-integration/output.txt +++ b/listings/ch11-writing-automated-tests/output-only-05-single-integration/output.txt @@ -1,10 +1,10 @@ $ cargo test --test integration_test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.64s - Running target/debug/deps/integration_test-82e7799c1bc62298 + Running tests/integration_test.rs (target/debug/deps/integration_test-82e7799c1bc62298) running 1 test test it_adds_two ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/src/ch11-00-testing.md b/src/ch11-00-testing.md index b6b2d1c74..258b3ab7f 100644 --- a/src/ch11-00-testing.md +++ b/src/ch11-00-testing.md @@ -20,29 +20,27 @@ Correctness in our programs is the extent to which our code does what we intend it to do. Rust is designed with a high degree of concern about the correctness of programs, but correctness is complex and not easy to prove. Rust’s type system shoulders a huge part of this burden, but the type system cannot catch -every kind of incorrectness. As such, Rust includes support for writing -automated software tests within the language. +everything. As such, Rust includes support for writing automated software tests. --> プログラムの正当性は、どこまで自分のコードが意図していることをしているかなのです。 Rustは、プログラムの正当性に重きを置いて設計されていますが、 正当性は複雑で、単純に証明することはありません。Rustの型システムは、 -この重荷の多くの部分を肩代わりしてくれますが、型システムはあらゆる種類の不当性を捕捉してはくれません。 -ゆえに、Rustでは、言語内で自動化されたソフトウェアテストを書くことをサポートしているのです。 +この重荷の多くの部分を肩代わりしてくれますが、型システムはすべてを捕捉してはくれません。 +ゆえに、Rustでは、自動化されたソフトウェアテストを書くことをサポートしているのです。 -例として、渡された何かの数値に2を足す`add_two`という関数を書くとしましょう。 +渡された何かの数値に2を足す`add_two`関数を書くとしましょう。 この関数のシグニチャは、引数に整数を取り、結果として整数を返します。 この関数を実装してコンパイルすると、コンパイラはこれまでに学んできた型チェックと借用チェックを全て行い、 例えば、`String`の値や無効な参照をこの関数に渡していないかなどを確かめるのです。 diff --git a/src/ch11-01-writing-tests.md b/src/ch11-01-writing-tests.md index 0ad818833..493559763 100644 --- a/src/ch11-01-writing-tests.md +++ b/src/ch11-01-writing-tests.md @@ -44,41 +44,41 @@ attribute. Attributes are metadata about pieces of Rust code; one example is the `derive` attribute we used with structs in Chapter 5. To change a function into a test function, add `#[test]` on the line before `fn`. When you run your tests with the `cargo test` command, Rust builds a test runner binary that runs -the functions annotated with the `test` attribute and reports on whether each +the annotated functions and reports on whether each test function passes or fails. --> 最も単純には、Rustにおけるテストは`test`属性で注釈された関数のことです。属性とは、 Rustコードの部品に関するメタデータです; 一例を挙げれば、構造体とともに第5章で使用した`derive`属性です。 関数をテスト関数に変えるには、`fn`の前に`#[test]`を付け加えてください。 -`cargo test`コマンドでテストを実行したら、コンパイラは`test`属性で注釈された関数を走らせるテスト用バイナリをビルドし、 +`cargo test`コマンドでテストを実行したら、コンパイラは注釈された関数を走らせるテスト用バイナリをビルドし、 各テスト関数が通過したか失敗したかを報告します。 新しいライブラリプロジェクトをCargoで作ると、テスト関数付きのテストモジュールが自動的に生成されます。 -このモジュールのおかげで、新しいプロジェクトを始めるたびにテスト関数の正しい構造とか文法をいちいち検索しなくてすみます。 +このモジュールがテストを書くためのテンプレートを提供してくれるので、 +新しいプロジェクトを始めるたびに正しい構造とか文法をいちいち検索しなくてすみます。 ここに好きな数だけテスト関数やテストモジュールを追加すればいいというわけです! -まず、実際にはコードをテストしない、自動生成されたテンプレートのテストで実験して、テストの動作の性質をいくらか学びましょう。 +まずは実際にコードをテストする前に、自動生成されたテンプレートのテストで実験して、テストの動作の性質をいくらか学びましょう。 その後で、以前書いたコードを呼び出し、振る舞いが正しいことをアサーションする、ホンモノのテストを書きましょう。 -`adder`という新しいライブラリプロジェクトを生成しましょう: +2つの数を足す、`adder`という新しいライブラリプロジェクトを生成しましょう: ```console $ cargo new adder --lib @@ -99,8 +99,18 @@ Listing 11-1. ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-01/src/lib.rs:here}} + + +```rust,noplayground +{{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-01/src/lib.rs}} ``` -とりあえず、最初の2行は無視し、関数に集中してその動作法を見ましょう。 -`fn`行の`#[test]`注釈に注目してください: この属性は、これがテスト関数であることを示すので、 +とりあえず、最初の2行は無視し、関数に集中しましょう。 +`#[test]`注釈に注目してください: この属性は、これがテスト関数であることを示すので、 テスト実行機はこの関数をテストとして扱うとわかるのです。さらに、`tests`モジュール内にはテスト関数以外の関数を入れ、 一般的なシナリオをセットアップしたり、共通の処理を行う手助けをしたりもできるので、 -`#[test]`属性でどの関数がテストかを示す必要があるのです。 +必ずどの関数がテストかを示す必要があるのです。 -関数本体は、`assert_eq!`マクロを使用して、2 + 2が4に等しいことをアサーションしています。 +例の関数本体は、`assert_eq!`マクロを使用して、2と2を足した結果を含む`result`が、4に等しいことをアサーションしています。 このアサーションは、典型的なテストのフォーマット例をなしているわけです。走らせてこのテストが通る(訳注:テストが成功する、の意味。英語でpassということから、このように表現される)ことを確かめましょう。 -Cargoがテストをコンパイルし、走らせました。`Compiling`, `Finished`, `Running`の行の後に`running 1 test`の行があります。 -次行が、生成されたテスト関数の`it_works`という名前とこのテストの実行結果、`ok`を示しています。 -テスト実行の総合的なまとめが次に出現します。`test result:ok.`というテキストは、 -全テストが通ったことを意味し、`1 passed; 0 failed`と読める部分は、通過または失敗したテストの数を合計しているのです。 +Cargoがテストをコンパイルし、走らせました。`running 1 test`という行が見えます。 +その次の行は、生成されたテスト関数の`it_works`という名前と、このテストの実行結果が`ok`であることを示しています。 +テスト全体のまとめである`test result:ok.`は、全テストが通ったことを意味し、 +`1 passed; 0 failed`と読める部分は、通過または失敗したテストの数を合計しているのです。 -無視すると指定したテストは何もなかったため、まとめは`0 ignored`と示しています。 +特定の場合にテスト実行しないように、テストを無視するように指定することができます; +これについては後でこの章の[「特に要望のない限りテストを無視する」][ignoring]節で扱います。 +ここではそれを行っていないので、まとめは`0 ignored`と示しています。 +`cargo test` コマンドに引数を渡すことで、名前が文字列にマッチするテストのみを実行することもできます; +*フィルタリング*と呼ばれますが、これについては[「名前でテストの一部を実行する」][subset]節で扱います。 また、実行するテストにフィルタをかけもしなかったので、まとめの最後に`0 filtered out`と表示されています。 -テストを無視することとフィルタすることに関しては次の節、[テストの実行され方を制御する][controlling-how-tests-are-run]で語ります。 @@ -207,13 +220,12 @@ ignore the `Doc-tests` output. 第14章の[テストとしてのドキュメンテーションコメント][doc-comments]節で議論しましょう。今は、`Doc-tests`出力は無視します。 -テストの名前を変更してどうテスト出力が変わるか確かめましょう。`it_works`関数を違う名前、`exploration`などに変えてください。 -そう、以下のように: +それでは必要に応じてテストをカスタマイズしていきましょう。 +まずは`it_works`関数の名前を違う名前に、例えば以下の`exploration`のように変更してください: -別のテストを追加しますが、今回は失敗するテストにしましょう!テスト関数内の何かがパニックすると、 -テストは失敗します。各テストは、新規スレッドで実行され、メインスレッドが、テストスレッドが死んだと確認した時、 -テストは失敗と印づけられます。第9章でパニックを引き起こす最も単純な方法について語りました。 -そう、`panic!`マクロを呼び出すことですね。*src/lib.rs*ファイルがリスト11-3のような見た目になるよう、 -新しいテスト`another`を入力してください。 +それでは別のテストを追加していきます。ただし、今回は失敗するテストにしましょう! +テスト関数内の何かがパニックすると、テストは失敗します。 +各テストは、新規スレッドで実行され、メインスレッドが、テストスレッドが死んだと確認した時、テストは失敗と印づけられます。 +第9章で、パニックを引き起こす最も単純な方法は`panic!`マクロを呼び出すことだと語りました。 +*src/lib.rs*ファイルがリスト11-3のような見た目になるよう、`another`という名前の関数として新しいテストを入力してください。 サマリー行が最後に出力されています: 総合的に言うと、テスト結果は`FAILED`でした。 @@ -333,21 +345,20 @@ let’s look at some macros other than `panic!` that are useful in tests. The `assert!` macro, provided by the standard library, is useful when you want to ensure that some condition in a test evaluates to `true`. We give the `assert!` macro an argument that evaluates to a Boolean. If the value is -`true`, `assert!` does nothing and the test passes. If the value is `false`, -the `assert!` macro calls the `panic!` macro, which causes the test to fail. -Using the `assert!` macro helps us check that our code is functioning in the -way we intend. +`true`, nothing happens and the test passes. If the value is `false`, the +`assert!` macro calls `panic!` to cause the test to fail. Using the `assert!` +macro helps us check that our code is functioning in the way we intend. --> `assert!`マクロは、標準ライブラリで提供されていますが、テスト内の何らかの条件が`true`と評価されることを確かめたいときに有効です。 `assert!`マクロには、論理値に評価される引数を与えます。その値が`true`なら、 -`assert!`は何もせず、テストは通ります。その値が`false`なら、`assert!`マクロは`panic!`マクロを呼び出し、 +何も起こらずにテストは通ります。その値が`false`なら、`assert!`マクロは`panic!`を呼び出し、 テストは失敗します。`assert!`マクロを使用することで、コードが意図した通りに機能していることを確認する助けになるわけです。 第5章のリスト5-15で、`Rectangle`構造体と`can_hold`メソッドを使用しました。リスト11-5でもそれを繰り返しています。 @@ -359,7 +370,7 @@ method, which are repeated here in Listing 11-5. Let’s put this code in the ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-05/src/lib.rs:here}} ``` @@ -388,7 +399,7 @@ has a width of 5 and a height of 1. ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-06/src/lib.rs:here}} ``` @@ -418,8 +429,8 @@ a glob here so anything we define in the outer module is available to this テストは`larger_can_hold_smaller`と名付け、必要な`Rectangle`インスタンスを2つ生成しています。 @@ -443,7 +454,7 @@ rectangle cannot hold a larger rectangle: ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/src/lib.rs:here}} ``` @@ -462,14 +473,14 @@ result, our test will pass if `can_hold` returns `false`: 通るテストが2つ!さて、コードにバグを導入したらテスト結果がどうなるか確認してみましょう。 幅を比較する大なり記号を小なり記号で置き換えて`can_hold`メソッドの実装を変更しましょう: -```rust,not_desired_behavior +```rust,not_desired_behavior,noplayground {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/src/lib.rs:here}} ``` @@ -498,20 +509,20 @@ less than 5. ### `assert_eq!`と`assert_ne!`マクロで等値性をテストする -機能をテストする一般的な方法は、テスト下にあるコードの結果をコードが返すと期待される値と比較して、 -等しいと確かめることです。これを`assert`マクロを使用して`==`演算子を使用した式を渡すことで行うこともできます。 +機能性を検証する一般的な方法は、テスト下にあるコードの結果と、コードが返すと期待される値との、等値性を確かめることです。 +これを`assert`マクロを使用して`==`演算子を使用した式を渡すことで行うこともできます。 しかしながら、これはありふれたテストなので、標準ライブラリには1組のマクロ(`assert_eq!`と`assert_ne!`)が提供され、 このテストをより便利に行うことができます。これらのマクロはそれぞれ、二つの引数を比べ、等しいかと等しくないかを確かめます。 また、アサーションが失敗したら二つの値の出力もし、テストが失敗した*原因*を確認しやすくなります。 @@ -519,12 +530,11 @@ expression, not the values that lead to the `false` value. -リスト11-7において、引数に`2`を加えて結果を返す`add_two`という名前の関数を書いています。 -そして、`assert_eq!`マクロでこの関数をテストしています。 +リスト11-7では、引数に`2`を加える`add_two`という名前の関数を書いて、 +この関数を`assert_eq!`マクロでテストしています。 -`assert_eq!`マクロに与えた第1引数の`4`は、`add_two(2)`の呼び出し結果と等しいです。 +`assert_eq!`マクロに引数として`4`を渡していますが、これは`add_two(2)`の呼び出し結果と等しいです。 このテストの行は`test tests::it_adds_two ... ok`であり、`ok`というテキストはテストが通ったことを示しています! -コードにバグを仕込んで、`assert_eq!`を使ったテストが失敗した時にどんな見た目になるのか確認してみましょう。 +コードにバグを仕込んで、`assert_eq!`が失敗した時にそれがどうなるのか確認してみましょう。 `add_two`関数の実装を代わりに`3`を足すように変えてください: -```rust,not_desired_behavior +```rust,not_desired_behavior,noplayground {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/src/lib.rs:here}} ``` @@ -583,48 +592,51 @@ Run the tests again: ``` -テストがバグを捕捉しました!`it_adds_two`のテストは失敗し、`` assertion failed: `(left == right)` ``というメッセージを表示し、 -`left`は`4`で、`right`は`5`だったと示しています。このメッセージは有用で、デバッグを開始する助けになります: -`assert_eq!`の`left`引数は`4`だったが、`add_two(2)`がある`right`引数は`5`だったことを意味しています。 +テストがバグを捕捉しました! +`it_adds_two`のテストは失敗し、そのメッセージは、 +失敗したアサーションが`` assertion failed: `(left == right)` ``であったこと、 +そして`left`と`right`の値が何だったかを示しています。 +このメッセージはデバッグを開始する助けになります: +`left`引数は`4`だったが、`add_two(2)`がある`right`引数は`5`でした。 +実行中のテストが多数あるときは特に、この出力は役に立つだろうと想像できるでしょう。 -二つの値が等しいとアサーションを行う関数の引数を -`expected`と`actual`と呼び、引数を指定する順序が問題になる言語やテストフレームワークもあることに注意してください。 -ですがRustでは、`left`と`right`と呼ばれ、期待する値とテスト下のコードが生成する値を指定する順序は -問題になりません。今回のテストのアサーションを`assert_eq!(add_two(2), 4)`と書くこともでき、 -そうすると失敗メッセージは、`` assertion failed: `(left == right)` ``となり、 -`left`が`5`で`right`が`4`と表示されるでしょう。 +言語やテストフレームワークによっては、等値性アサーション関数の引数を`expected`と`actual`と呼び、 +引数を指定する順序が重要であることに注意してください。 +ですがRustでは、これらは`left`と`right`と呼ばれ、期待する値とコードが生成する値を指定する順序は重要ではありません。 +今回のテストのアサーションを`assert_eq!(add_two(2), 4)`と書くこともでき、 +そうすると失敗メッセージは、同じく`` assertion failed: `(left == right)` ``を表示するでしょう。 `assert_ne!`マクロは、与えた2つの値が等しくなければ通り、等しければ失敗します。 -このマクロは、値が何になる*だろう*か確信が持てないけれども、コードが意図した通りに動いていれば、 -確実にこの値にはなら*ないだろう*とわかっているような場合に最も有用になります。例えば、 +このマクロは、値が何になる*だろう*か確信が持てないけれども、 +確実にこの値にはなる*べきでない*とわかっているような場合に最も有用になります。例えば、 入力を何らかの手段で変え(て出力す)ることが保証されているけれども、入力の変え方がテストを実行する曜日に依存する関数をテストしているなら、 アサーションすべき最善の事柄は、関数の出力が入力と等しくないことかもしれません。 @@ -632,15 +644,15 @@ to assert might be that the output of the function is not equal to the input. Under the surface, the `assert_eq!` and `assert_ne!` macros use the operators `==` and `!=`, respectively. When the assertions fail, these macros print their arguments using debug formatting, which means the values being compared must -implement the `PartialEq` and `Debug` traits. All the primitive types and most -of the standard library types implement these traits. For structs and enums -that you define, you’ll need to implement `PartialEq` to assert that values of -those types are equal or not equal. You’ll need to implement `Debug` to print -the values when the assertion fails. Because both traits are derivable traits, -as mentioned in Listing 5-12 in Chapter 5, this is usually as straightforward -as adding the `#[derive(PartialEq, Debug)]` annotation to your struct or enum -definition. See Appendix C, [“Derivable Traits,”][derivable-traits] -for more details about these and other derivable traits. +implement the `PartialEq` and `Debug` traits. All primitive types and most of +the standard library types implement these traits. For structs and enums that +you define yourself, you’ll need to implement `PartialEq` to assert equality of +those types. You’ll also need to implement `Debug` to print the values when the +assertion fails. Because both traits are derivable traits, as mentioned in +Listing 5-12 in Chapter 5, this is usually as straightforward as adding the +`#[derive(PartialEq, Debug)]` annotation to your struct or enum definition. See +Appendix C, [“Derivable Traits,”][derivable-traits] for more +details about these and other derivable traits. --> 内部的には、`assert_eq!`と`assert_ne!`マクロは、それぞれ`==`と`!=`演算子を使用しています。 @@ -648,8 +660,8 @@ for more details about these and other derivable traits. 比較対象の値は`PartialEq`と`Debug`トレイトを実装していなければなりません。 すべての組み込み型と、ほぼすべての標準ライブラリの型はこれらのトレイトを実装しています。 自分で定義した構造体やenumについては、 -その型の値が等しいか等しくないかをアサーションするために、`PartialEq`を実装する必要があるでしょう。 -それが失敗した時にその値をプリントできるように、`Debug`を実装する必要もあるでしょう。 +その型の値の等値性をアサーションするために、`PartialEq`を実装する必要があるでしょう。 +それが失敗した時にその値をプリントできるように、`Debug`も実装する必要もあるでしょう。 第5章のリスト5-12で触れたように、どちらのトレイトも導出可能なトレイトなので、 これは通常、単純に構造体やenum定義に`#[derive(PartialEq, Debug)]`という注釈を追加するだけですみます。 これらやその他の導出可能なトレイトに関する詳細については、付録C、[導出可能なトレイト][derivable-traits]をご覧ください。 @@ -662,19 +674,17 @@ for more details about these and other derivable traits. さらに、`assert!`、`assert_eq!`、`assert_ne!`の追加引数として、失敗メッセージと共にカスタムのメッセージが表示されるよう、 -追加することもできます。`assert!`の1つの必須引数の後に、 -あるいは`assert_eq!`と`assert_ne!`の2つの必須引数の後に指定された引数はすべて`format!`マクロに渡されるので、 +追加することもできます。必須引数の後に指定された引数はすべて`format!`マクロに渡されるので、 (format!マクロについては第8章の[`+`演算子、または`format!`マクロで連結][concatenation-with-the--operator-or-the-format-macro]節で議論しました)、 `{}`プレースホルダーを含むフォーマット文字列とこのプレースホルダーに置き換えられる値を渡すことができます。 カスタムメッセージは、アサーションがどんな意味を持つかドキュメント化するのに役に立ちます; @@ -692,8 +702,8 @@ want to test that the name we pass into the function appears in the output: ファイル名: src/lib.rs -```rust -{{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-05-greeter/src/lib.rs:here}} +```rust,noplayground +{{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-05-greeter/src/lib.rs}} ``` -`greeting`が`name`を含まないように変更してこのコードにバグを仕込み、このテストの失敗がどんな風になるのか確かめましょう: +それでは`greeting`が`name`を含まないように変更してこのコードにバグを仕込み、テストの失敗がデフォルトでどんな風になるのか確かめましょう: -```rust,not_desired_behavior +```rust,not_desired_behavior,noplayground {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/src/lib.rs:here}} ``` @@ -732,16 +742,15 @@ Running this test produces the following: この結果は、アサーションが失敗し、どの行にアサーションがあるかを示しているだけです。 -今回の場合、失敗メッセージが`greeting`関数から得た値を出力していればより有用でしょう。 -テスト関数を変更し、 -`greeting`関数から得た実際の値で埋められるプレースホルダーを含むフォーマット文字列からなるカスタムの失敗メッセージを与えてみましょう。 +失敗メッセージが`greeting`関数からの値を出力していればより有用でしょう。 +`greeting`関数から得た実際の値で埋められるプレースホルダーを含むフォーマット文字列からなるカスタムの失敗メッセージを追加してみましょう: ```rust,ignore {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/src/lib.rs:here}} @@ -772,28 +781,27 @@ debug what happened instead of what we were expecting to happen. ### `should_panic`でパニックを確認する -期待する正しい値をコードが返すことを確認することに加えて、想定通りにコードがエラー状態を扱っていることを確認するのも重要です。 +戻り値を確認することに加えて、想定通りにコードがエラー状態を扱っていることを確認することが重要です。 例えば、第9章のリスト9-10で生成した`Guess`型を考えてください。`Guess`を使用する他のコードは、 `Guess`のインスタンスは1から100の範囲の値しか含まないという保証に依存しています。 その範囲外の値で`Guess`インスタンスを生成しようとするとパニックすることを確認するテストを書くことができます。 -これは、テスト関数に`should_panic`という別の属性を追加することで達成できます。 -この属性は、関数内のコードがパニックしたら、テストを通過させます。つまり、 +これは、テスト関数に`should_panic`という属性を追加することで達成できます。 +このテストは、関数内のコードがパニックする場合に通過します。つまり、 関数内のコードがパニックしなかったら、テストは失敗するわけです。 よさそうですね!では、値が100より大きいときに`new`関数がパニックするという条件を除去することでコードにバグを導入しましょう: -```rust,not_desired_behavior +```rust,not_desired_behavior,noplayground {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/src/lib.rs:here}} ``` @@ -864,18 +872,18 @@ means that the code in the test function did not cause a panic. テスト関数のコードがパニックを引き起こさなかったことを意味するのです。 -`should_panic`を使用するテストは不正確なこともあります。なぜなら、コードが何らかのパニックを起こしたことしか示さないからです。 -`should_panic`のテストは、起きると想定していたもの以外の理由でテストがパニックしても通ってしまうのです。 +`should_panic`を使用するテストは不正確なこともあります。 +`should_panic`のテストは、想定していたもの以外の理由でテストがパニックしても通ってしまうのです。 `should_panic`のテストの正確を期すために、`should_panic`属性に`expected`引数を追加することもできます。 このテストハーネスは、失敗メッセージに与えられたテキストが含まれていることを確かめてくれます。 例えば、リスト11-9の修正された`Guess`のコードを考えてください。ここでは、 @@ -887,33 +895,32 @@ different messages depending on whether the value is too small or too large. ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-09/src/lib.rs:here}} ``` -リスト11-9: 状況が特定のパニックメッセージで`panic!`を引き起こすことをテストする +リスト11-9: 指定された部分文字列を含むパニックメッセージで`panic!`することをテストする `should_panic`属性の`expected`引数に置いた値が`Guess::new`関数がパニックしたメッセージの一部になっているので、 このテストは通ります。予想されるパニックメッセージ全体を指定することもでき、今回の場合、 `Guess value must be less than or equal to 100, got 200.`となります。 -`should_panic`の予想される引数に何を指定するかは、パニックメッセージのどこが固有でどこが動的か、 +何を指定するかは、パニックメッセージのどこが固有でどこが動的か、 またテストをどの程度正確に行いたいかによります。今回の場合、パニックメッセージの一部でも、テスト関数内のコードが、 `else if value > 100`の場合を実行していると確認するのに事足りるのです。 @@ -958,20 +965,20 @@ figuring out where our bug is! ### `Result`をテストで使う -これまでは、失敗するとパニックするようなテストを書いてきましたが、 +これまで書いてきたテストは失敗するとパニックしていましたが、 `Result`を使うようなテストを書くこともできます! -以下は、Listing 11-1のテストを、`Result`を使い、パニックする代わりに`Err`を返すように書き直したものです: +以下は、リスト11-1のテストを、`Result`を使い、パニックする代わりに`Err`を返すように書き直したものです: -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs}} ``` `Result`を使うテストに`#[should_panic]`注釈を使うことはできません。 -テストが失敗しなければならないときは、直接`Err`値を返してください。 +操作が`Err`列挙子を返すことをアサーションするためには、`Result`値に対して`?`演算子を使用*しないでください*。 +代わりに、`assert!(value.is_err())`を使用してください。 + +[concatenation-with-the--operator-or-the-format-macro]: +ch08-02-strings.html#演算子またはformatマクロで連結 +[bench]: https://doc.rust-lang.org/unstable-book/library-features/test.html +[ignoring]: ch11-02-running-tests.html#特に要望のない限りテストを無視する +[subset]: ch11-02-running-tests.html#名前でテストの一部を実行する [controlling-how-tests-are-run]: ch11-02-running-tests.html#テストの実行のされ方を制御する [derivable-traits]: appendix-03-derivable-traits.html diff --git a/src/ch11-02-running-tests.md b/src/ch11-02-running-tests.md index 2f9ff5d64..02791a17d 100644 --- a/src/ch11-02-running-tests.md +++ b/src/ch11-02-running-tests.md @@ -7,33 +7,33 @@ `cargo run`がコードをコンパイルし、出来上がったバイナリを走らせるのと全く同様に、 `cargo test`はコードをテストモードでコンパイルし、出来上がったテストバイナリを実行します。 -コマンドラインオプションを指定して`cargo test`の既定動作を変更することができます。 -例えば、`cargo test`で生成されるバイナリの既定動作は、テストを全て並行に実行し、 +`cargo test`で生成されるバイナリの既定動作は、テストを全て並行に実行し、 テスト実行中に生成された出力をキャプチャして出力が表示されるのを防ぎ、 テスト結果に関係する出力を読みやすくすることです。 +ですが、コマンドラインオプションを指定してこの既定動作を変更することができます。 コマンドラインオプションの中には`cargo test`にかかるものや、出来上がったテストバイナリにかかるものがあります。 この2種の引数を区別するために、`cargo test`にかかる引数を`--`という区分記号の後に列挙し、 それからテストバイナリにかかる引数を列挙します。`cargo test --help`を走らせると、`cargo test`で使用できるオプションが表示され、 -`cargo test -- --help`を走らせると、`--`という区分記号の後に使えるオプションが表示されます。 +`cargo test -- --help`を走らせると、区分記号の後に使えるオプションが表示されます。 -複数のテストを実行するとき、標準では、スレッドを使用して並行に走ります。これはつまり、 -テストが早く実行し終わり、コードが機能しているいかんにかかわらず、反応をより早く得られることを意味します。 -テストは同時に実行されているので、テストが相互や共有された環境を含む他の共通の状態に依存してないことを確かめてください。 +複数のテストを実行するとき、デフォルトでは、テストは複数のスレッドを使用して並行に走ります。 +つまり、テストが早く実行し終わり、反応をより早く得られることを意味します。 +テストは同時に実行されるので、テストが他のテストや、共有された環境を含む他の共有状態に依存しないようにする必要があります。 現在の作業対象ディレクトリや環境変数などですね。 例えば、各テストがディスクに*test_output.txt*というファイルを作成し、何らかのデータを書き込むコードを走らせるとしてください。 @@ -87,7 +86,7 @@ the following example: `--test-threads`フラグと使用したいスレッド数をテストバイナリに送ることができます。 以下の例に目を向けてください: -```text +```console $ cargo test -- --test-threads=1 ``` @@ -111,7 +110,7 @@ state. @@ -134,29 +133,8 @@ parameter and returns 10, as well as a test that passes and a test that fails. ファイル名: src/lib.rs -```rust -fn prints_and_returns_10(a: i32) -> i32 { - //{}という値を得た - println!("I got the value {}", a); - 10 -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn this_test_will_pass() { - let value = prints_and_returns_10(4); - assert_eq!(10, value); - } - - #[test] - fn this_test_will_fail() { - let value = prints_and_returns_10(8); - assert_eq!(5, value); - } -} +```rust,panics,noplayground +{{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-10/src/lib.rs}} ``` -通過するテストについても出力される値が見たかったら、出力キャプチャ機能を`--nocapture`フラグで無効化することができます: +通過するテストについても出力される値が見たかったら、`--show-output`で成功するテストの出力も表示するようにRustに指示することができます: -```text -$ cargo test -- --nocapture +```console +$ cargo test -- --show-output ``` -リスト11-10のテストを`--nocapture`フラグと共に再度実行したら、以下のような出力を目の当たりにします: +リスト11-10のテストを`--show-output`フラグと共に再度実行したら、以下のような出力を目の当たりにします: -```text -running 2 tests -I got the value 4 -I got the value 8 -test tests::this_test_will_pass ... ok -thread 'tests::this_test_will_fail' panicked at 'assertion failed: `(left == right)` - left: `5`, - right: `10`', src/lib.rs:19:8 -note: Run with `RUST_BACKTRACE=1` for a backtrace. -test tests::this_test_will_fail ... FAILED - -failures: - -failures: - tests::this_test_will_fail - -test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +```console +{{#include ../listings/ch11-writing-automated-tests/output-only-01-show-output/output.txt}} ``` -テストの一部を走らせる方法を模擬するために、リスト11-11に示したように、 -`add_two`関数用に3つテストを作成し、走らせるテストを選択します。 +テストの一部を走らせる方法を模擬するために、まずリスト11-11に示したように`add_two`関数用に3つテストを作成し、 +そして走らせるテストを選択します。 `one_hundred`という名前のテストだけが走りました; 他の2つのテストはその名前に合致しなかったのです。 -まとめ行の最後に`2 filtered out`と表示することでテスト出力は、このコマンドが走らせた以上のテストがあることを知らせてくれています。 +このテスト出力は、最後に`2 filtered out`と表示することによって、実行されなかったテストがあったことを知らせてくれています。 @@ -435,18 +341,8 @@ here: ファイル名: src/lib.rs -```rust -#[test] -fn it_works() { - assert_eq!(2 + 2, 4); -} - -#[test] -#[ignore] -fn expensive_test() { - // 実行に1時間かかるコード - // code that takes an hour to run -} +```rust,noplayground +{{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/src/lib.rs}} ``` どのテストを走らせるか制御することで、結果が早く出ることを確かめることができるのです。 `ignored`テストの結果を確認することが道理に合い、結果を待つだけの時間ができたときに、 代わりに`cargo test -- --ignored`を走らせることができます。 +無視されているかどうかにかかわらず、すべてのテストを実行したい場合は、`cargo test -- --include-ignored`で実行することができます。 diff --git a/src/ch11-03-test-organization.md b/src/ch11-03-test-organization.md index 09e068739..3215aaf7e 100644 --- a/src/ch11-03-test-organization.md +++ b/src/ch11-03-test-organization.md @@ -7,18 +7,18 @@ 章の初めで触れたように、テストは複雑な鍛錬であり、人によって専門用語や体系化が異なります。 -Rustのコミュニティでは、テストを2つの大きなカテゴリで捉えています: *単体テスト*と*結合テスト*です。 -単体テストは小規模でより集中していて、個別に1回に1モジュールをテストし、非公開のインターフェイスもテストすることがあります。 -結合テストは、完全にライブラリ外になり、他の外部コード同様に自分のコードを使用し、公開インターフェイスのみ使用し、 +Rustのコミュニティでは、テストを2つの大きなカテゴリで捉えています: 単体テストと結合テストです。 +*単体テスト*は小規模でより集中していて、個別に1回に1モジュールをテストし、非公開のインターフェイスもテストすることがあります。 +*結合テスト*は、完全にライブラリ外になり、他の外部コード同様に自分のコードを使用し、公開インターフェイスのみ使用し、 1テストにつき複数のモジュールを用いることもあります。 @@ -85,14 +85,8 @@ this chapter, Cargo generated this code for us: ファイル名: src/lib.rs -```rust -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} +```rust,noplayground +{{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-01/src/lib.rs}} ``` -`internal_adder`関数は`pub`とマークされていないものの、テストも単なるRustのコードであり、 -`tests`モジュールもただのモジュールでしかないので、テスト内で`internal_adder`を普通にインポートし呼び出すことができます。 +`internal_adder`関数は`pub`とマークされていないことに注意してください。 +テストも単なるRustのコードであり、`tests`モジュールもただのモジュールでしかありません。 +[「モジュールツリーの要素を示すためのパス」][paths]節で議論したように、子モジュール内の要素はその祖先モジュール内の要素を使用することができます。 +このテストでは、`use super::*`によって`test`モジュールの親のすべての要素をスコープ内に持ち込み、そしてテストが`internal_adder`を呼び出しています。 非公開関数はテストするべきではないとお考えなら、Rustにはそれを強制するものは何もありません。 プロジェクトディレクトリのトップ階層、*src*の隣に*tests*ディレクトリを作成します。 Cargoは、このディレクトリに結合テストのファイルを探すことを把握しています。 -そして、このディレクトリ内にいくらでもテストファイルを作成することができ、 -Cargoはそれぞれのファイルを個別のクレートとしてコンパイルします。 +テストファイルは好きなだけ作成することができ、Cargoはそれぞれのファイルを個別のクレートとしてコンパイルします。 結合テストを作成しましょう。リスト11-12のコードが*src/lib.rs*ファイルにあるまま、 -*tests*ディレクトリを作成し、*tests/integration_test.rs*という名前の新しいファイルを生成し、 -リスト11-13のコードを入力してください。 +*tests*ディレクトリを作成し、*tests/integration_test.rs*という名前の新しいファイルを生成してください。 +ディレクトリ構造は次のようになるはずです: + +```text +adder +├── Cargo.lock +├── Cargo.toml +├── src +│   └── lib.rs +└── tests + └── integration_test.rs +``` + + + +リスト11-13のコードを*tests/integration_test.rs*ファイルに入力してください: -コードの頂点に`extern crate adder`を追記しましたが、これは単体テストでは必要なかったものです。 -理由は、`tests`ディレクトリのテストはそれぞれ個別のクレートであるため、 -各々ライブラリをインポートする必要があるためです。 +`tests`ディレクトリのファイルはそれぞれ個別のクレートであるため、 +ライブラリを各テストのスコープ内に持ち込む必要があります。 +そのため、コードの先頭に`use adder`を追記していますが、これは単体テストでは必要なかったものです。 -3つの区域の出力が単体テスト、結合テスト、ドックテストを含んでいます。単体テスト用の最初の区域は、 -今まで見てきたものと同じです: 各単体テストに1行(リスト11-12で追加した`internal`という名前のもの)と、 -単体テストのサマリー行です。 +3つの区域の出力が単体テスト、結合テスト、docテストを含んでいます。 +ある区域内のテストがひとつでも失敗していれば、それ以降の区域は実行されないでしょう。 +例えば、単体テストが失敗したら、結合テストとdocテストについての出力はされないでしょう。 +すべての単体テストが通過する場合のみ、これらのテストが実行されるからです。 + + + +単体テスト用の最初の区域は、今まで見てきたものと同じです: +各単体テストに1行(リスト11-12で追加した`internal`という名前のもの)と、単体テストのサマリー行です。 -結合テストの区域は、 -`Running target/debug/deps/integration-test-ce99bcc2479f4607`という行で始まっています(最後のハッシュはあなたの出力とは違うでしょう)。 +結合テストの区域は、`Running tests/integration_test.rs`という行で始まっています。 次に、この結合テストの各テスト関数用の行があり、`Doc-tests adder`区域が始まる直前に、 結合テストの結果用のサマリー行があります。 -単体テスト関数を追加することで単体テスト区域のテスト結果の行が増えたように、 -作成した結合テストファイルにテスト関数を追加することでそのファイルの区域に結果の行が増えることになります。 結合テストファイルはそれぞれ独自の区域があるため、*tests*ディレクトリにさらにファイルを追加すれば、 結合テストの区域が増えることになるでしょう。 @@ -342,15 +319,8 @@ followed by the name of the file: 特定の結合テストファイルにあるテストを全て走らせるには、`cargo test`に`--test`引数、 その後にファイル名を続けて使用してください: -```text -$ cargo test --test integration_test - Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs - Running target/debug/integration_test-952a27e0126bb565 - -running 1 test -test it_adds_two ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +```console +{{#include ../listings/ch11-writing-automated-tests/output-only-05-single-integration/output.txt}} ``` -結合テストを追加するにつれて、*tests*ディレクトリに2つ以上のファイルを作成して体系化したくなるかもしれません; +結合テストを追加するにつれて、*tests*ディレクトリにファイルを作成して体系化したくなるかもしれません; 例えば、テスト対象となる機能でテスト関数をグループ化することができます。前述したように、 *tests*ディレクトリの各ファイルは、個別のクレートとしてコンパイルされます。 - - - -各結合テストファイルをそれ自身のクレートとして扱うと、 -エンドユーザがあなたのクレートを使用するかのように個別のスコープを生成するのに役立ちます。 +これは、エンドユーザがあなたのクレートを使用する場合をより模倣するように個別のスコープを生成するのに役立ちます。 ですが、これは*tests*ディレクトリのファイルが、コードをモジュールとファイルに分ける方法に関して第7章で学んだように、 *src*のファイルとは同じ振る舞いを共有しないことを意味します。 -*tests*ディレクトリのファイルの異なる振る舞いは、複数の結合テストファイルで役に立ちそうなヘルパー関数ができ、 -第7章の「モジュールを別のファイルに移動する」節の手順に従って共通モジュールに抽出しようとした時に最も気付きやすくなります。 +*tests*ディレクトリのファイルの異なる振る舞いは、複数の結合テストファイルで使用するヘルパー関数ができ、 +第7章の[「モジュールを複数のファイルに分割する」][separating-modules-into-files]節の手順に従って共通モジュールに抽出しようとした時に最も気付きやすくなります。 例えば、*tests/common.rs*を作成し、そこに`setup`という名前の関数を配置したら、 複数のテストファイルの複数のテスト関数から呼び出したい`setup`に何らかのコードを追加することができます: @@ -410,11 +374,8 @@ functions in multiple test files: ファイル名: tests/common.rs -```rust -pub fn setup() { - // ここにライブラリテスト固有のコードが来る - // setup code specific to your library's tests would go here -} +```rust,noplayground +{{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/tests/common.rs}} ``` `common`がテスト出力に出現するのを防ぐには、*tests/common.rs*を作成する代わりに、 -*tests/common/mod.rs*を作成します。第7章の「モジュールファイルシステムの規則」節において、 -*module_name/mod.rs*という命名規則をサブモジュールのあるモジュールのファイルに使用しました。 -ここでは`common`にサブモジュールはありませんが、 +*tests/common/mod.rs*を作成します。これでプロジェクトディレクトリは次のようになります: + +```text +├── Cargo.lock +├── Cargo.toml +├── src +│   └── lib.rs +└── tests + ├── common + │   └── mod.rs + └── integration_test.rs +``` + + + +これは第7章の[「別のファイルパス」][alt-paths]節で言及した、コンパイラが理解するもう一つの古い命名規則です。 このように命名することでコンパイラに`common`モジュールを結合テストファイルとして扱わないように指示します。 `setup`関数のコードを*tests/common/mod.rs*に移動し、*tests/common.rs*ファイルを削除すると、 テスト出力に区域はもう表示されなくなります。*tests*ディレクトリのサブディレクトリ内のファイルは個別クレートとしてコンパイルされたり、 @@ -499,19 +453,13 @@ function from the `it_adds_two` test in *tests/integration_test.rs*: ファイル名: tests/integration_test.rs ```rust,ignore -extern crate adder; - -mod common; - -#[test] -fn it_adds_two() { - common::setup(); - assert_eq!(4, adder::add_two(2)); -} +{{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-13-fix-shared-test-code-problem/tests/integration_test.rs}} ``` `mod common;`という宣言は、リスト7-21で模擬したモジュール宣言と同じであることに注意してください。それから、テスト関数内で`common::setup()`関数を呼び出すことができます。 @@ -525,22 +473,21 @@ Note that the mod common; declaration is the same as the module declaration we d もしもプロジェクトが*src/main.rs*ファイルのみを含み、*src/lib.rs*ファイルを持たないバイナリクレートだったら、 -*tests*ディレクトリに結合テストを作成し、 -`extern crate`を使用して*src/main.rs*ファイルに定義された関数をインポートすることはできません。 -ライブラリクレートのみが、他のクレートが呼び出して使用できる関数を晒せるのです; +*tests*ディレクトリに結合テストを作成し、`use`文で*src/main.rs*ファイルに定義された関数をスコープ内に持ち込むことはできません。 +ライブラリクレートのみが、他のクレートが使用できる関数を晒せるのです; バイナリクレートはそれ単体で実行することを意味しています。 Rustのテスト機能は、変更を加えた後でさえ想定通りにコードが機能し続けることを保証して、 @@ -577,7 +524,19 @@ Rustの型システムと所有権ルールにより防がれるバグの種類 この章と以前の章で学んだ知識を結集して、とあるプロジェクトに取り掛かりましょう! + + + +[paths]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html +[separating-modules-into-files]: +ch07-05-separating-modules-into-different-files.html +[alt-paths]: ch07-05-separating-modules-into-different-files.html#別のファイルパス From fcc533b3015b1892ee944df5310f5a1065be5452 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:05 +0900 Subject: [PATCH 13/22] =?UTF-8?q?ch12=20=E5=85=A5=E5=87=BA=E5=8A=9B?= =?UTF-8?q?=E3=83=97=E3=83=AD=E3=82=B8=E3=82=A7=E3=82=AF=E3=83=88:=20?= =?UTF-8?q?=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89=E3=83=A9=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E3=83=97=E3=83=AD=E3=82=B0=E3=83=A9=E3=83=A0=E3=82=92=E6=A7=8B?= =?UTF-8?q?=E7=AF=89=E3=81=99=E3=82=8B=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92?= =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-12-01/Cargo.toml | 3 +- .../listing-12-01/output.txt | 4 +- .../listing-12-01/src/main.rs | 2 +- .../listing-12-02/Cargo.toml | 3 +- .../listing-12-02/output.txt | 2 +- .../listing-12-02/src/main.rs | 6 +- .../listing-12-03/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-03/poem.txt | 6 +- .../listing-12-03/src/main.rs | 4 +- .../listing-12-04/Cargo.toml | 3 +- .../listing-12-04/output.txt | 8 +- .../ch12-an-io-project/listing-12-04/poem.txt | 6 +- .../listing-12-04/src/main.rs | 12 +- .../listing-12-05/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-05/poem.txt | 6 +- .../listing-12-05/src/main.rs | 14 +- .../listing-12-06/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-06/poem.txt | 6 +- .../listing-12-06/src/main.rs | 14 +- .../listing-12-07/Cargo.toml | 3 +- .../listing-12-07/output.txt | 7 +- .../ch12-an-io-project/listing-12-07/poem.txt | 6 +- .../listing-12-07/src/main.rs | 14 +- .../listing-12-08/Cargo.toml | 3 +- .../listing-12-08/output.txt | 7 +- .../ch12-an-io-project/listing-12-08/poem.txt | 6 +- .../listing-12-08/src/main.rs | 15 +- .../listing-12-09/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-09/poem.txt | 6 +- .../listing-12-09/src/main.rs | 16 +- .../listing-12-10/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-10/poem.txt | 6 +- .../listing-12-10/src/main.rs | 21 +- .../listing-12-11/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-11/poem.txt | 6 +- .../listing-12-11/src/main.rs | 20 +- .../listing-12-12/Cargo.toml | 3 +- .../listing-12-12/output.txt | 18 +- .../ch12-an-io-project/listing-12-12/poem.txt | 6 +- .../listing-12-12/src/main.rs | 18 +- .../listing-12-13/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-13/poem.txt | 6 +- .../listing-12-13/src/lib.rs | 12 +- .../listing-12-13/src/main.rs | 9 +- .../listing-12-14/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-14/poem.txt | 6 +- .../listing-12-14/src/lib.rs | 12 +- .../listing-12-14/src/main.rs | 9 +- .../listing-12-15/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-15/poem.txt | 6 +- .../listing-12-15/src/lib.rs | 12 +- .../listing-12-15/src/main.rs | 7 +- .../listing-12-16/Cargo.toml | 3 +- .../listing-12-16/output.txt | 15 +- .../ch12-an-io-project/listing-12-16/poem.txt | 6 +- .../listing-12-16/src/lib.rs | 12 +- .../listing-12-16/src/main.rs | 7 +- .../listing-12-17/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-17/poem.txt | 6 +- .../listing-12-17/src/lib.rs | 11 +- .../listing-12-17/src/main.rs | 7 +- .../listing-12-18/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-18/poem.txt | 6 +- .../listing-12-18/src/lib.rs | 10 +- .../listing-12-18/src/main.rs | 7 +- .../listing-12-19/Cargo.toml | 3 +- .../listing-12-19/output.txt | 10 +- .../ch12-an-io-project/listing-12-19/poem.txt | 6 +- .../listing-12-19/src/lib.rs | 10 +- .../listing-12-19/src/main.rs | 7 +- .../listing-12-20/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-20/poem.txt | 6 +- .../listing-12-20/src/lib.rs | 14 +- .../listing-12-20/src/main.rs | 7 +- .../listing-12-21/Cargo.toml | 3 +- .../listing-12-21/output.txt | 10 +- .../ch12-an-io-project/listing-12-21/poem.txt | 6 +- .../listing-12-21/src/lib.rs | 14 +- .../listing-12-21/src/main.rs | 7 +- .../listing-12-22/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-22/poem.txt | 6 +- .../listing-12-22/src/lib.rs | 22 +- .../listing-12-22/src/main.rs | 7 +- .../listing-12-23/Cargo.toml | 3 +- .../listing-12-23/output.txt | 2 +- .../ch12-an-io-project/listing-12-23/poem.txt | 6 +- .../listing-12-23/src/lib.rs | 26 +- .../listing-12-23/src/main.rs | 7 +- .../listing-12-24/Cargo.toml | 3 +- .../ch12-an-io-project/listing-12-24/poem.txt | 6 +- .../listing-12-24/src/lib.rs | 24 +- .../listing-12-24/src/main.rs | 7 +- .../Cargo.toml | 3 +- .../poem.txt | 6 +- .../src/main.rs | 22 +- .../Cargo.toml | 3 +- .../output.txt | 2 +- .../poem.txt | 6 +- .../src/lib.rs | 12 +- .../src/main.rs | 7 +- .../output-only-01-with-args/Cargo.toml | 3 +- .../output-only-01-with-args/output.txt | 8 +- .../output-only-01-with-args/src/main.rs | 2 +- .../Cargo.toml | 3 +- .../output.txt | 14 +- .../output-only-02-missing-lifetimes/poem.txt | 6 +- .../src/lib.rs | 12 +- .../src/main.rs | 7 +- .../Cargo.toml | 3 +- .../output.txt | 4 +- .../output-only-03-multiple-matches/poem.txt | 6 +- .../src/lib.rs | 12 +- .../src/main.rs | 7 +- .../output-only-04-no-matches/Cargo.toml | 3 +- .../output-only-04-no-matches/output.txt | 2 +- .../output-only-04-no-matches/poem.txt | 6 +- .../output-only-04-no-matches/src/lib.rs | 12 +- .../output-only-04-no-matches/src/main.rs | 7 +- src/ch12-00-an-io-project.md | 70 +- ...h12-01-accepting-command-line-arguments.md | 168 ++--- src/ch12-02-reading-a-file.md | 145 +--- ...improving-error-handling-and-modularity.md | 713 +++++++----------- ...2-04-testing-the-librarys-functionality.md | 314 +++----- ...2-05-working-with-environment-variables.md | 355 ++++----- ...-06-writing-to-stderr-instead-of-stdout.md | 70 +- 125 files changed, 1129 insertions(+), 1594 deletions(-) diff --git a/listings/ch12-an-io-project/listing-12-01/Cargo.toml b/listings/ch12-an-io-project/listing-12-01/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-01/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-01/output.txt b/listings/ch12-an-io-project/listing-12-01/output.txt index d0ef99812..7017af1ab 100644 --- a/listings/ch12-an-io-project/listing-12-01/output.txt +++ b/listings/ch12-an-io-project/listing-12-01/output.txt @@ -2,4 +2,6 @@ $ cargo run Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.61s Running `target/debug/minigrep` -["target/debug/minigrep"] +[src/main.rs:5:5] args = [ + "target/debug/minigrep", +] diff --git a/listings/ch12-an-io-project/listing-12-01/src/main.rs b/listings/ch12-an-io-project/listing-12-01/src/main.rs index aa3056de6..ae7def53d 100644 --- a/listings/ch12-an-io-project/listing-12-01/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-01/src/main.rs @@ -2,5 +2,5 @@ use std::env; fn main() { let args: Vec = env::args().collect(); - println!("{:?}", args); + dbg!(args); } diff --git a/listings/ch12-an-io-project/listing-12-02/Cargo.toml b/listings/ch12-an-io-project/listing-12-02/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-02/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-02/output.txt b/listings/ch12-an-io-project/listing-12-02/output.txt index f759eea00..6ef87f7ce 100644 --- a/listings/ch12-an-io-project/listing-12-02/output.txt +++ b/listings/ch12-an-io-project/listing-12-02/output.txt @@ -1,4 +1,4 @@ -$ cargo run test sample.txt +$ cargo run -- test sample.txt Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.0s Running `target/debug/minigrep test sample.txt` diff --git a/listings/ch12-an-io-project/listing-12-02/src/main.rs b/listings/ch12-an-io-project/listing-12-02/src/main.rs index 8daf125c6..41717ea2d 100644 --- a/listings/ch12-an-io-project/listing-12-02/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-02/src/main.rs @@ -4,8 +4,10 @@ fn main() { let args: Vec = env::args().collect(); let query = &args[1]; - let filename = &args[2]; + let file_path = &args[2]; + // "{}を検索します" println!("Searching for {}", query); - println!("In file {}", filename); + // "ファイル{}の中で" + println!("In file {}", file_path); } diff --git a/listings/ch12-an-io-project/listing-12-03/Cargo.toml b/listings/ch12-an-io-project/listing-12-03/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-03/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-03/poem.txt b/listings/ch12-an-io-project/listing-12-03/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-03/poem.txt +++ b/listings/ch12-an-io-project/listing-12-03/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-03/src/main.rs b/listings/ch12-an-io-project/listing-12-03/src/main.rs index 8daf125c6..ae2fa7bb1 100644 --- a/listings/ch12-an-io-project/listing-12-03/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-03/src/main.rs @@ -4,8 +4,8 @@ fn main() { let args: Vec = env::args().collect(); let query = &args[1]; - let filename = &args[2]; + let file_path = &args[2]; println!("Searching for {}", query); - println!("In file {}", filename); + println!("In file {}", file_path); } diff --git a/listings/ch12-an-io-project/listing-12-04/Cargo.toml b/listings/ch12-an-io-project/listing-12-04/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-04/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-04/output.txt b/listings/ch12-an-io-project/listing-12-04/output.txt index 75e7863ef..6582ca169 100644 --- a/listings/ch12-an-io-project/listing-12-04/output.txt +++ b/listings/ch12-an-io-project/listing-12-04/output.txt @@ -1,14 +1,14 @@ -$ cargo run the poem.txt +$ cargo run -- the poem.txt Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.0s Running `target/debug/minigrep the poem.txt` Searching for the In file poem.txt With text: -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-04/poem.txt b/listings/ch12-an-io-project/listing-12-04/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-04/poem.txt +++ b/listings/ch12-an-io-project/listing-12-04/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-04/src/main.rs b/listings/ch12-an-io-project/listing-12-04/src/main.rs index 9a0eade56..bb3c7e715 100644 --- a/listings/ch12-an-io-project/listing-12-04/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-04/src/main.rs @@ -8,15 +8,17 @@ fn main() { let args: Vec = env::args().collect(); let query = &args[1]; - let filename = &args[2]; + let file_path = &args[2]; println!("Searching for {}", query); // ANCHOR: here - println!("In file {}", filename); + println!("In file {}", file_path); - let contents = fs::read_to_string(filename) - .expect("Something went wrong reading the file"); + let contents = fs::read_to_string(file_path) + // "ファイルを読み込むことができるはずでした" + .expect("Should have been able to read the file"); - println!("With text:\n{}", contents); + // "テキスト:\n{contents}" + println!("With text:\n{contents}"); } // ANCHOR_END: here diff --git a/listings/ch12-an-io-project/listing-12-05/Cargo.toml b/listings/ch12-an-io-project/listing-12-05/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-05/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-05/poem.txt b/listings/ch12-an-io-project/listing-12-05/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-05/poem.txt +++ b/listings/ch12-an-io-project/listing-12-05/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-05/src/main.rs b/listings/ch12-an-io-project/listing-12-05/src/main.rs index fb8805687..061591833 100644 --- a/listings/ch12-an-io-project/listing-12-05/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-05/src/main.rs @@ -5,25 +5,25 @@ use std::fs; fn main() { let args: Vec = env::args().collect(); - let (query, filename) = parse_config(&args); + let (query, file_path) = parse_config(&args); // --snip-- // ANCHOR_END: here println!("Searching for {}", query); - println!("In file {}", filename); + println!("In file {}", file_path); - let contents = fs::read_to_string(filename) - .expect("Something went wrong reading the file"); + let contents = fs::read_to_string(file_path) + .expect("Should have been able to read the file"); - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); // ANCHOR: here } fn parse_config(args: &[String]) -> (&str, &str) { let query = &args[1]; - let filename = &args[2]; + let file_path = &args[2]; - (query, filename) + (query, file_path) } // ANCHOR_END: here diff --git a/listings/ch12-an-io-project/listing-12-06/Cargo.toml b/listings/ch12-an-io-project/listing-12-06/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-06/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-06/poem.txt b/listings/ch12-an-io-project/listing-12-06/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-06/poem.txt +++ b/listings/ch12-an-io-project/listing-12-06/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-06/src/main.rs b/listings/ch12-an-io-project/listing-12-06/src/main.rs index b5d89bc98..c77e848d8 100644 --- a/listings/ch12-an-io-project/listing-12-06/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-06/src/main.rs @@ -8,27 +8,27 @@ fn main() { let config = parse_config(&args); println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); - let contents = fs::read_to_string(config.filename) - .expect("Something went wrong reading the file"); + let contents = fs::read_to_string(config.file_path) + .expect("Should have been able to read the file"); // --snip-- // ANCHOR_END: here - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); // ANCHOR: here } struct Config { query: String, - filename: String, + file_path: String, } fn parse_config(args: &[String]) -> Config { let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Config { query, filename } + Config { query, file_path } } // ANCHOR_END: here diff --git a/listings/ch12-an-io-project/listing-12-07/Cargo.toml b/listings/ch12-an-io-project/listing-12-07/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-07/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-07/output.txt b/listings/ch12-an-io-project/listing-12-07/output.txt index 8c8d53aa8..852153546 100644 --- a/listings/ch12-an-io-project/listing-12-07/output.txt +++ b/listings/ch12-an-io-project/listing-12-07/output.txt @@ -2,5 +2,8 @@ $ cargo run Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.0s Running `target/debug/minigrep` -thread 'main' panicked at 'index out of bounds: the len is 1 but the index is 1', src/main.rs:27:21 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'main' panicked at src/main.rs:27:21: +index out of bounds: the len is 1 but the index is 1 +(スレッド'main'はsrc/main.rs:27:21でパニックしました: +境界外アクセス: 長さは1なのに添え字も1です) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/listings/ch12-an-io-project/listing-12-07/poem.txt b/listings/ch12-an-io-project/listing-12-07/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-07/poem.txt +++ b/listings/ch12-an-io-project/listing-12-07/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-07/src/main.rs b/listings/ch12-an-io-project/listing-12-07/src/main.rs index 36d35ceaf..ff6c29420 100644 --- a/listings/ch12-an-io-project/listing-12-07/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-07/src/main.rs @@ -9,12 +9,12 @@ fn main() { // ANCHOR_END: here println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); - let contents = fs::read_to_string(config.filename) - .expect("Something went wrong reading the file"); + let contents = fs::read_to_string(config.file_path) + .expect("Should have been able to read the file"); - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); // ANCHOR: here // --snip-- @@ -25,16 +25,16 @@ fn main() { // ANCHOR_END: here struct Config { query: String, - filename: String, + file_path: String, } // ANCHOR: here impl Config { fn new(args: &[String]) -> Config { let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Config { query, filename } + Config { query, file_path } } } // ANCHOR_END: here diff --git a/listings/ch12-an-io-project/listing-12-08/Cargo.toml b/listings/ch12-an-io-project/listing-12-08/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-08/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-08/output.txt b/listings/ch12-an-io-project/listing-12-08/output.txt index fa5d235eb..af2d0fcdc 100644 --- a/listings/ch12-an-io-project/listing-12-08/output.txt +++ b/listings/ch12-an-io-project/listing-12-08/output.txt @@ -2,5 +2,8 @@ $ cargo run Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.0s Running `target/debug/minigrep` -thread 'main' panicked at 'not enough arguments', src/main.rs:26:13 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'main' panicked at src/main.rs:26:13: +not enough arguments +(スレッド'main'はsrc/main.rs:26:13でパニックしました: +引数が足りません) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/listings/ch12-an-io-project/listing-12-08/poem.txt b/listings/ch12-an-io-project/listing-12-08/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-08/poem.txt +++ b/listings/ch12-an-io-project/listing-12-08/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-08/src/main.rs b/listings/ch12-an-io-project/listing-12-08/src/main.rs index dddf10bd4..7d4fe63cc 100644 --- a/listings/ch12-an-io-project/listing-12-08/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-08/src/main.rs @@ -7,17 +7,17 @@ fn main() { let config = Config::new(&args); println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); - let contents = fs::read_to_string(config.filename) - .expect("Something went wrong reading the file"); + let contents = fs::read_to_string(config.file_path) + .expect("Should have been able to read the file"); - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); } struct Config { query: String, - filename: String, + file_path: String, } impl Config { @@ -25,14 +25,15 @@ impl Config { // --snip-- fn new(args: &[String]) -> Config { if args.len() < 3 { + // "引数が足りません" panic!("not enough arguments"); } // --snip-- // ANCHOR_END: here let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Config { query, filename } + Config { query, file_path } } } diff --git a/listings/ch12-an-io-project/listing-12-09/Cargo.toml b/listings/ch12-an-io-project/listing-12-09/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-09/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-09/poem.txt b/listings/ch12-an-io-project/listing-12-09/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-09/poem.txt +++ b/listings/ch12-an-io-project/listing-12-09/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-09/src/main.rs b/listings/ch12-an-io-project/listing-12-09/src/main.rs index 83f46ee37..3418e718c 100644 --- a/listings/ch12-an-io-project/listing-12-09/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-09/src/main.rs @@ -7,30 +7,30 @@ fn main() { let config = Config::new(&args); println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); - let contents = fs::read_to_string(config.filename) - .expect("Something went wrong reading the file"); + let contents = fs::read_to_string(config.file_path) + .expect("Should have been able to read the file"); - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); } struct Config { query: String, - filename: String, + file_path: String, } // ANCHOR: here impl Config { - fn new(args: &[String]) -> Result { + fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } // ANCHOR_END: here diff --git a/listings/ch12-an-io-project/listing-12-10/Cargo.toml b/listings/ch12-an-io-project/listing-12-10/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-10/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-10/poem.txt b/listings/ch12-an-io-project/listing-12-10/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-10/poem.txt +++ b/listings/ch12-an-io-project/listing-12-10/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-10/src/main.rs b/listings/ch12-an-io-project/listing-12-10/src/main.rs index c8aeb1d37..ad2312c96 100644 --- a/listings/ch12-an-io-project/listing-12-10/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-10/src/main.rs @@ -6,8 +6,9 @@ use std::process; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + // "引数解析時の問題: {err}" + println!("Problem parsing arguments: {err}"); process::exit(1); }); @@ -15,28 +16,28 @@ fn main() { // ANCHOR_END: here println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); - let contents = fs::read_to_string(config.filename) - .expect("Something went wrong reading the file"); + let contents = fs::read_to_string(config.file_path) + .expect("Should have been able to read the file"); - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); } struct Config { query: String, - filename: String, + file_path: String, } impl Config { - fn new(args: &[String]) -> Result { + fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } diff --git a/listings/ch12-an-io-project/listing-12-11/Cargo.toml b/listings/ch12-an-io-project/listing-12-11/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-11/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-11/poem.txt b/listings/ch12-an-io-project/listing-12-11/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-11/poem.txt +++ b/listings/ch12-an-io-project/listing-12-11/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-11/src/main.rs b/listings/ch12-an-io-project/listing-12-11/src/main.rs index 974b503b7..3f476b975 100644 --- a/listings/ch12-an-io-project/listing-12-11/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-11/src/main.rs @@ -9,23 +9,23 @@ fn main() { // ANCHOR_END: here let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); // ANCHOR: here println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); run(config); } fn run(config: Config) { - let contents = fs::read_to_string(config.filename) - .expect("Something went wrong reading the file"); + let contents = fs::read_to_string(config.file_path) + .expect("Should have been able to read the file"); - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); } // --snip-- @@ -33,18 +33,18 @@ fn run(config: Config) { struct Config { query: String, - filename: String, + file_path: String, } impl Config { - fn new(args: &[String]) -> Result { + fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } diff --git a/listings/ch12-an-io-project/listing-12-12/Cargo.toml b/listings/ch12-an-io-project/listing-12-12/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-12/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-12/output.txt b/listings/ch12-an-io-project/listing-12-12/output.txt index 565479d0c..9fcebd7de 100644 --- a/listings/ch12-an-io-project/listing-12-12/output.txt +++ b/listings/ch12-an-io-project/listing-12-12/output.txt @@ -1,23 +1,29 @@ $ cargo run the poem.txt Compiling minigrep v0.1.0 (file:///projects/minigrep) -warning: unused `std::result::Result` that must be used +warning: unused `Result` that must be used +(警告: 使用されなければならない`Result`が未使用です) --> src/main.rs:19:5 | 19 | run(config); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ | - = note: `#[warn(unused_must_use)]` on by default = note: this `Result` may be an `Err` variant, which should be handled + = note: `#[warn(unused_must_use)]` on by default +help: use `let _ = ...` to ignore the resulting value + | +19 | let _ = run(config); + | +++++++ +warning: `minigrep` (bin "minigrep") generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 0.71s Running `target/debug/minigrep the poem.txt` Searching for the In file poem.txt With text: -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-12/poem.txt b/listings/ch12-an-io-project/listing-12-12/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-12/poem.txt +++ b/listings/ch12-an-io-project/listing-12-12/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-12/src/main.rs b/listings/ch12-an-io-project/listing-12-12/src/main.rs index f2e0e6b9f..ab5fdb894 100644 --- a/listings/ch12-an-io-project/listing-12-12/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-12/src/main.rs @@ -11,22 +11,22 @@ use std::error::Error; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); run(config); } // ANCHOR: here fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); Ok(()) } @@ -34,18 +34,18 @@ fn run(config: Config) -> Result<(), Box> { struct Config { query: String, - filename: String, + file_path: String, } impl Config { - fn new(args: &[String]) -> Result { + fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } diff --git a/listings/ch12-an-io-project/listing-12-13/Cargo.toml b/listings/ch12-an-io-project/listing-12-13/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-13/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-13/poem.txt b/listings/ch12-an-io-project/listing-12-13/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-13/poem.txt +++ b/listings/ch12-an-io-project/listing-12-13/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-13/src/lib.rs b/listings/ch12-an-io-project/listing-12-13/src/lib.rs index 5b2850a5d..1a3c48089 100644 --- a/listings/ch12-an-io-project/listing-12-13/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-13/src/lib.rs @@ -4,11 +4,11 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { // --snip-- // ANCHOR_END: here if args.len() < 3 { @@ -16,9 +16,9 @@ impl Config { } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) // ANCHOR: here } } @@ -26,9 +26,9 @@ impl Config { pub fn run(config: Config) -> Result<(), Box> { // --snip-- // ANCHOR_END: here - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); Ok(()) // ANCHOR: here diff --git a/listings/ch12-an-io-project/listing-12-13/src/main.rs b/listings/ch12-an-io-project/listing-12-13/src/main.rs index b2447dce9..09756ca3f 100644 --- a/listings/ch12-an-io-project/listing-12-13/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-13/src/main.rs @@ -4,17 +4,16 @@ use std::process; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); if let Err(e) = run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-14/Cargo.toml b/listings/ch12-an-io-project/listing-12-14/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-14/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-14/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-14/poem.txt b/listings/ch12-an-io-project/listing-12-14/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-14/poem.txt +++ b/listings/ch12-an-io-project/listing-12-14/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-14/src/lib.rs b/listings/ch12-an-io-project/listing-12-14/src/lib.rs index 2ba2fd196..4f3a4e865 100644 --- a/listings/ch12-an-io-project/listing-12-14/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-14/src/lib.rs @@ -3,26 +3,26 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); Ok(()) } diff --git a/listings/ch12-an-io-project/listing-12-14/src/main.rs b/listings/ch12-an-io-project/listing-12-14/src/main.rs index 5eb4024f5..3b76009b5 100644 --- a/listings/ch12-an-io-project/listing-12-14/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-14/src/main.rs @@ -9,20 +9,19 @@ fn main() { // ANCHOR_END: here let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); // ANCHOR: here if let Err(e) = minigrep::run(config) { // --snip-- // ANCHOR_END: here - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); // ANCHOR: here } diff --git a/listings/ch12-an-io-project/listing-12-15/Cargo.toml b/listings/ch12-an-io-project/listing-12-15/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-15/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-15/poem.txt b/listings/ch12-an-io-project/listing-12-15/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-15/poem.txt +++ b/listings/ch12-an-io-project/listing-12-15/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-15/src/lib.rs b/listings/ch12-an-io-project/listing-12-15/src/lib.rs index 22ec38178..20c4a782b 100644 --- a/listings/ch12-an-io-project/listing-12-15/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-15/src/lib.rs @@ -3,24 +3,24 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; Ok(()) } @@ -42,5 +42,3 @@ Pick three."; } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch12-an-io-project/listing-12-15/src/main.rs b/listings/ch12-an-io-project/listing-12-15/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/listing-12-15/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-15/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-16/Cargo.toml b/listings/ch12-an-io-project/listing-12-16/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-16/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-16/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-16/output.txt b/listings/ch12-an-io-project/listing-12-16/output.txt index a7a676ec3..893171bc4 100644 --- a/listings/ch12-an-io-project/listing-12-16/output.txt +++ b/listings/ch12-an-io-project/listing-12-16/output.txt @@ -1,7 +1,7 @@ $ cargo test Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished test [unoptimized + debuginfo] target(s) in 0.97s - Running target/debug/deps/minigrep-4672b652f7794785 + Running unittests src/lib.rs (target/debug/deps/minigrep-9cd200e5fac0fc94) running 1 test test tests::one_result ... FAILED @@ -9,15 +9,16 @@ test tests::one_result ... FAILED failures: ---- tests::one_result stdout ---- -thread 'main' panicked at 'assertion failed: `(left == right)` - left: `["safe, fast, productive."]`, - right: `[]`', src/lib.rs:44:9 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::one_result' panicked at src/lib.rs:44:9: +assertion `left == right` failed + left: ["safe, fast, productive."] + right: [] +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::one_result -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch12-an-io-project/listing-12-16/poem.txt b/listings/ch12-an-io-project/listing-12-16/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-16/poem.txt +++ b/listings/ch12-an-io-project/listing-12-16/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-16/src/lib.rs b/listings/ch12-an-io-project/listing-12-16/src/lib.rs index 2fc5b4f72..f5e593484 100644 --- a/listings/ch12-an-io-project/listing-12-16/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-16/src/lib.rs @@ -3,24 +3,24 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; Ok(()) } @@ -46,5 +46,3 @@ Pick three."; assert_eq!(vec!["safe, fast, productive."], search(query, contents)); } } - -fn main() {} diff --git a/listings/ch12-an-io-project/listing-12-16/src/main.rs b/listings/ch12-an-io-project/listing-12-16/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/listing-12-16/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-16/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-17/Cargo.toml b/listings/ch12-an-io-project/listing-12-17/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-17/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-17/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-17/poem.txt b/listings/ch12-an-io-project/listing-12-17/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-17/poem.txt +++ b/listings/ch12-an-io-project/listing-12-17/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-17/src/lib.rs b/listings/ch12-an-io-project/listing-12-17/src/lib.rs index 0b094ce28..239042b45 100644 --- a/listings/ch12-an-io-project/listing-12-17/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-17/src/lib.rs @@ -3,24 +3,24 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; Ok(()) } @@ -28,6 +28,7 @@ pub fn run(config: Config) -> Result<(), Box> { // ANCHOR: here pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { for line in contents.lines() { + // 行に対して何かする // do something with line } } diff --git a/listings/ch12-an-io-project/listing-12-17/src/main.rs b/listings/ch12-an-io-project/listing-12-17/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/listing-12-17/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-17/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-18/Cargo.toml b/listings/ch12-an-io-project/listing-12-18/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-18/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-18/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-18/poem.txt b/listings/ch12-an-io-project/listing-12-18/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-18/poem.txt +++ b/listings/ch12-an-io-project/listing-12-18/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-18/src/lib.rs b/listings/ch12-an-io-project/listing-12-18/src/lib.rs index c9d1f529d..a05d046d7 100644 --- a/listings/ch12-an-io-project/listing-12-18/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-18/src/lib.rs @@ -3,24 +3,24 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; Ok(()) } diff --git a/listings/ch12-an-io-project/listing-12-18/src/main.rs b/listings/ch12-an-io-project/listing-12-18/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/listing-12-18/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-18/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-19/Cargo.toml b/listings/ch12-an-io-project/listing-12-19/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-19/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-19/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-19/output.txt b/listings/ch12-an-io-project/listing-12-19/output.txt index fa1490152..9b2078cb8 100644 --- a/listings/ch12-an-io-project/listing-12-19/output.txt +++ b/listings/ch12-an-io-project/listing-12-19/output.txt @@ -1,22 +1,22 @@ $ cargo test Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished test [unoptimized + debuginfo] target(s) in 1.22s - Running target/debug/deps/minigrep-4672b652f7794785 + Running unittests src/lib.rs (target/debug/deps/minigrep-9cd200e5fac0fc94) running 1 test test tests::one_result ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - Running target/debug/deps/minigrep-caf9dbee196c78b9 + Running unittests src/main.rs (target/debug/deps/minigrep-9cd200e5fac0fc94) running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests minigrep running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch12-an-io-project/listing-12-19/poem.txt b/listings/ch12-an-io-project/listing-12-19/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-19/poem.txt +++ b/listings/ch12-an-io-project/listing-12-19/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-19/src/lib.rs b/listings/ch12-an-io-project/listing-12-19/src/lib.rs index de8897b8d..f5d3ffa9f 100644 --- a/listings/ch12-an-io-project/listing-12-19/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-19/src/lib.rs @@ -3,24 +3,24 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; Ok(()) } diff --git a/listings/ch12-an-io-project/listing-12-19/src/main.rs b/listings/ch12-an-io-project/listing-12-19/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/listing-12-19/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-19/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-20/Cargo.toml b/listings/ch12-an-io-project/listing-12-20/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-20/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-20/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-20/poem.txt b/listings/ch12-an-io-project/listing-12-20/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-20/poem.txt +++ b/listings/ch12-an-io-project/listing-12-20/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-20/src/lib.rs b/listings/ch12-an-io-project/listing-12-20/src/lib.rs index 52ba2bd51..a757f7f55 100644 --- a/listings/ch12-an-io-project/listing-12-20/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-20/src/lib.rs @@ -3,27 +3,27 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; for line in search(&config.query, &contents) { - println!("{}", line); + println!("{line}"); } Ok(()) @@ -74,5 +74,3 @@ Trust me."; } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch12-an-io-project/listing-12-20/src/main.rs b/listings/ch12-an-io-project/listing-12-20/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/listing-12-20/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-20/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-21/Cargo.toml b/listings/ch12-an-io-project/listing-12-21/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-21/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-21/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-21/output.txt b/listings/ch12-an-io-project/listing-12-21/output.txt index 3d7cf26d1..dafeb7862 100644 --- a/listings/ch12-an-io-project/listing-12-21/output.txt +++ b/listings/ch12-an-io-project/listing-12-21/output.txt @@ -1,23 +1,23 @@ $ cargo test Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished test [unoptimized + debuginfo] target(s) in 1.33s - Running target/debug/deps/minigrep-4672b652f7794785 + Running unittests src/lib.rs (target/debug/deps/minigrep-9cd200e5fac0fc94) running 2 tests test tests::case_insensitive ... ok test tests::case_sensitive ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - Running target/debug/deps/minigrep-caf9dbee196c78b9 + Running unittests src/main.rs (target/debug/deps/minigrep-9cd200e5fac0fc94) running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests minigrep running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/listings/ch12-an-io-project/listing-12-21/poem.txt b/listings/ch12-an-io-project/listing-12-21/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-21/poem.txt +++ b/listings/ch12-an-io-project/listing-12-21/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-21/src/lib.rs b/listings/ch12-an-io-project/listing-12-21/src/lib.rs index 873c8b53d..3aaa04082 100644 --- a/listings/ch12-an-io-project/listing-12-21/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-21/src/lib.rs @@ -3,27 +3,27 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; for line in search(&config.query, &contents) { - println!("{}", line); + println!("{line}"); } Ok(()) @@ -90,5 +90,3 @@ Trust me."; ); } } - -fn main() {} diff --git a/listings/ch12-an-io-project/listing-12-21/src/main.rs b/listings/ch12-an-io-project/listing-12-21/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/listing-12-21/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-21/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-22/Cargo.toml b/listings/ch12-an-io-project/listing-12-22/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-22/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-22/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-22/poem.txt b/listings/ch12-an-io-project/listing-12-22/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-22/poem.txt +++ b/listings/ch12-an-io-project/listing-12-22/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-22/src/lib.rs b/listings/ch12-an-io-project/listing-12-22/src/lib.rs index 2df82b7e2..c3f4723f1 100644 --- a/listings/ch12-an-io-project/listing-12-22/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-22/src/lib.rs @@ -4,36 +4,36 @@ use std::fs; // ANCHOR: here pub struct Config { pub query: String, - pub filename: String, - pub case_sensitive: bool, + pub file_path: String, + pub ignore_case: bool, } // ANCHOR_END: here impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } // ANCHOR: there pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - let results = if config.case_sensitive { - search(&config.query, &contents) - } else { + let results = if config.ignore_case { search_case_insensitive(&config.query, &contents) + } else { + search(&config.query, &contents) }; for line in results { - println!("{}", line); + println!("{line}"); } Ok(()) @@ -99,5 +99,3 @@ Trust me."; ); } } - -fn main() {} diff --git a/listings/ch12-an-io-project/listing-12-22/src/main.rs b/listings/ch12-an-io-project/listing-12-22/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/listing-12-22/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-22/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-23/Cargo.toml b/listings/ch12-an-io-project/listing-12-23/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-23/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-23/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-23/output.txt b/listings/ch12-an-io-project/listing-12-23/output.txt index 0f0f07f75..eaffc2f24 100644 --- a/listings/ch12-an-io-project/listing-12-23/output.txt +++ b/listings/ch12-an-io-project/listing-12-23/output.txt @@ -1,4 +1,4 @@ -$ cargo run to poem.txt +$ cargo run -- to poem.txt Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.0s Running `target/debug/minigrep to poem.txt` diff --git a/listings/ch12-an-io-project/listing-12-23/poem.txt b/listings/ch12-an-io-project/listing-12-23/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-23/poem.txt +++ b/listings/ch12-an-io-project/listing-12-23/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-23/src/lib.rs b/listings/ch12-an-io-project/listing-12-23/src/lib.rs index e6dc51a0e..20eda2197 100644 --- a/listings/ch12-an-io-project/listing-12-23/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-23/src/lib.rs @@ -8,42 +8,42 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, - pub case_sensitive: bool, + pub file_path: String, + pub ignore_case: bool, } // ANCHOR: here impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); + let ignore_case = env::var("IGNORE_CASE").is_ok(); Ok(Config { query, - filename, - case_sensitive, + file_path, + ignore_case, }) } } // ANCHOR_END: here pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - let results = if config.case_sensitive { - search(&config.query, &contents) - } else { + let results = if config.ignore_case { search_case_insensitive(&config.query, &contents) + } else { + search(&config.query, &contents) }; for line in results { - println!("{}", line); + println!("{line}"); } Ok(()) @@ -108,5 +108,3 @@ Trust me."; ); } } - -fn main() {} diff --git a/listings/ch12-an-io-project/listing-12-23/src/main.rs b/listings/ch12-an-io-project/listing-12-23/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/listing-12-23/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-23/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/listing-12-24/Cargo.toml b/listings/ch12-an-io-project/listing-12-24/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/listing-12-24/Cargo.toml +++ b/listings/ch12-an-io-project/listing-12-24/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/listing-12-24/poem.txt b/listings/ch12-an-io-project/listing-12-24/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/listing-12-24/poem.txt +++ b/listings/ch12-an-io-project/listing-12-24/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/listing-12-24/src/lib.rs b/listings/ch12-an-io-project/listing-12-24/src/lib.rs index fe1dccf4e..292b09789 100644 --- a/listings/ch12-an-io-project/listing-12-24/src/lib.rs +++ b/listings/ch12-an-io-project/listing-12-24/src/lib.rs @@ -4,40 +4,40 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, - pub case_sensitive: bool, + pub file_path: String, + pub ignore_case: bool, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); + let ignore_case = env::var("IGNORE_CASE").is_ok(); Ok(Config { query, - filename, - case_sensitive, + file_path, + ignore_case, }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - let results = if config.case_sensitive { - search(&config.query, &contents) - } else { + let results = if config.ignore_case { search_case_insensitive(&config.query, &contents) + } else { + search(&config.query, &contents) }; for line in results { - println!("{}", line); + println!("{line}"); } Ok(()) diff --git a/listings/ch12-an-io-project/listing-12-24/src/main.rs b/listings/ch12-an-io-project/listing-12-24/src/main.rs index 9e38553c5..1278a6c17 100644 --- a/listings/ch12-an-io-project/listing-12-24/src/main.rs +++ b/listings/ch12-an-io-project/listing-12-24/src/main.rs @@ -7,14 +7,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - eprintln!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + eprintln!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - eprintln!("Application error: {}", e); - + eprintln!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/Cargo.toml b/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/Cargo.toml +++ b/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/poem.txt b/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/poem.txt +++ b/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/src/main.rs b/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/src/main.rs index 44bcfeab3..9b8d16055 100644 --- a/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/src/main.rs +++ b/listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/src/main.rs @@ -10,45 +10,45 @@ fn main() { // ANCHOR_END: here let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); // ANCHOR: here println!("Searching for {}", config.query); - println!("In file {}", config.filename); + println!("In file {}", config.file_path); if let Err(e) = run(config) { - println!("Application error: {}", e); - + // "アプリケーションエラー: {e}" + println!("Application error: {e}"); process::exit(1); } } // ANCHOR_END: here fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - println!("With text:\n{}", contents); + println!("With text:\n{contents}"); Ok(()) } struct Config { query: String, - filename: String, + file_path: String, } impl Config { - fn new(args: &[String]) -> Result { + fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } diff --git a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/Cargo.toml b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/Cargo.toml +++ b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/output.txt b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/output.txt index 91532d0cd..a5a4ef8c2 100644 --- a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/output.txt +++ b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/output.txt @@ -1,4 +1,4 @@ -$ cargo run frog poem.txt +$ cargo run -- frog poem.txt Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.38s Running `target/debug/minigrep frog poem.txt` diff --git a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/poem.txt b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/poem.txt +++ b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/src/lib.rs b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/src/lib.rs index ede4eb49a..e06eae4cd 100644 --- a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/src/lib.rs +++ b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/src/lib.rs @@ -3,28 +3,28 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } // ANCHOR: here pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; for line in search(&config.query, &contents) { - println!("{}", line); + println!("{line}"); } Ok(()) diff --git a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/src/main.rs b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/no-listing-02-using-search-in-run/src/main.rs +++ b/listings/ch12-an-io-project/no-listing-02-using-search-in-run/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/output-only-01-with-args/Cargo.toml b/listings/ch12-an-io-project/output-only-01-with-args/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/output-only-01-with-args/Cargo.toml +++ b/listings/ch12-an-io-project/output-only-01-with-args/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/output-only-01-with-args/output.txt b/listings/ch12-an-io-project/output-only-01-with-args/output.txt index eb88d9a9b..ef5743967 100644 --- a/listings/ch12-an-io-project/output-only-01-with-args/output.txt +++ b/listings/ch12-an-io-project/output-only-01-with-args/output.txt @@ -1,5 +1,9 @@ -$ cargo run needle haystack +$ cargo run -- needle haystack Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 1.57s Running `target/debug/minigrep needle haystack` -["target/debug/minigrep", "needle", "haystack"] +[src/main.rs:5:5] args = [ + "target/debug/minigrep", + "needle", + "haystack", +] diff --git a/listings/ch12-an-io-project/output-only-01-with-args/src/main.rs b/listings/ch12-an-io-project/output-only-01-with-args/src/main.rs index aa3056de6..ae7def53d 100644 --- a/listings/ch12-an-io-project/output-only-01-with-args/src/main.rs +++ b/listings/ch12-an-io-project/output-only-01-with-args/src/main.rs @@ -2,5 +2,5 @@ use std::env; fn main() { let args: Vec = env::args().collect(); - println!("{:?}", args); + dbg!(args); } diff --git a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/Cargo.toml b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/Cargo.toml +++ b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/output.txt b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/output.txt index b76084b0f..0b725d6b2 100644 --- a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/output.txt +++ b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/output.txt @@ -1,16 +1,18 @@ $ cargo build Compiling minigrep v0.1.0 (file:///projects/minigrep) error[E0106]: missing lifetime specifier +(エラー: ライフタイム指定子が欠けています) --> src/lib.rs:28:51 | 28 | pub fn search(query: &str, contents: &str) -> Vec<&str> { - | ^ expected lifetime parameter + | ---- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `query` or `contents` - -error: aborting due to previous error + (ヘルプ: この関数の戻り値は、借用された値を含んでいますが、シグニチャにはそれが、`query`か`contents`から借用されたものであるかが示されていません) +help: consider introducing a named lifetime parameter + | +28 | pub fn search<'a>(query: &'a str, contents: &'a str) -> Vec<&'a str> { + | ++++ ++ ++ ++ For more information about this error, try `rustc --explain E0106`. -error: could not compile `minigrep`. - -To learn more, run the command again with --verbose. +error: could not compile `minigrep` (lib) due to 1 previous error diff --git a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/poem.txt b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/poem.txt +++ b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/src/lib.rs b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/src/lib.rs index c60405c21..df623bdea 100644 --- a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/src/lib.rs +++ b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/src/lib.rs @@ -3,24 +3,24 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; Ok(()) } @@ -46,5 +46,3 @@ Pick three."; assert_eq!(vec!["safe, fast, productive."], search(query, contents)); } } - -fn main() {} diff --git a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/src/main.rs b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/output-only-02-missing-lifetimes/src/main.rs +++ b/listings/ch12-an-io-project/output-only-02-missing-lifetimes/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/output-only-03-multiple-matches/Cargo.toml b/listings/ch12-an-io-project/output-only-03-multiple-matches/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/output-only-03-multiple-matches/Cargo.toml +++ b/listings/ch12-an-io-project/output-only-03-multiple-matches/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/output-only-03-multiple-matches/output.txt b/listings/ch12-an-io-project/output-only-03-multiple-matches/output.txt index c0ab7efd9..b46835766 100644 --- a/listings/ch12-an-io-project/output-only-03-multiple-matches/output.txt +++ b/listings/ch12-an-io-project/output-only-03-multiple-matches/output.txt @@ -1,7 +1,7 @@ -$ cargo run body poem.txt +$ cargo run -- body poem.txt Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.0s Running `target/debug/minigrep body poem.txt` -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? How dreary to be somebody! diff --git a/listings/ch12-an-io-project/output-only-03-multiple-matches/poem.txt b/listings/ch12-an-io-project/output-only-03-multiple-matches/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/output-only-03-multiple-matches/poem.txt +++ b/listings/ch12-an-io-project/output-only-03-multiple-matches/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/output-only-03-multiple-matches/src/lib.rs b/listings/ch12-an-io-project/output-only-03-multiple-matches/src/lib.rs index ede4eb49a..e06eae4cd 100644 --- a/listings/ch12-an-io-project/output-only-03-multiple-matches/src/lib.rs +++ b/listings/ch12-an-io-project/output-only-03-multiple-matches/src/lib.rs @@ -3,28 +3,28 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } // ANCHOR: here pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; for line in search(&config.query, &contents) { - println!("{}", line); + println!("{line}"); } Ok(()) diff --git a/listings/ch12-an-io-project/output-only-03-multiple-matches/src/main.rs b/listings/ch12-an-io-project/output-only-03-multiple-matches/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/output-only-03-multiple-matches/src/main.rs +++ b/listings/ch12-an-io-project/output-only-03-multiple-matches/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch12-an-io-project/output-only-04-no-matches/Cargo.toml b/listings/ch12-an-io-project/output-only-04-no-matches/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch12-an-io-project/output-only-04-no-matches/Cargo.toml +++ b/listings/ch12-an-io-project/output-only-04-no-matches/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch12-an-io-project/output-only-04-no-matches/output.txt b/listings/ch12-an-io-project/output-only-04-no-matches/output.txt index 4cd6c8a0a..a53624f83 100644 --- a/listings/ch12-an-io-project/output-only-04-no-matches/output.txt +++ b/listings/ch12-an-io-project/output-only-04-no-matches/output.txt @@ -1,4 +1,4 @@ -$ cargo run monomorphization poem.txt +$ cargo run -- monomorphization poem.txt Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.0s Running `target/debug/minigrep monomorphization poem.txt` diff --git a/listings/ch12-an-io-project/output-only-04-no-matches/poem.txt b/listings/ch12-an-io-project/output-only-04-no-matches/poem.txt index 208e35a5e..870752731 100644 --- a/listings/ch12-an-io-project/output-only-04-no-matches/poem.txt +++ b/listings/ch12-an-io-project/output-only-04-no-matches/poem.txt @@ -1,7 +1,7 @@ -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us - don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/listings/ch12-an-io-project/output-only-04-no-matches/src/lib.rs b/listings/ch12-an-io-project/output-only-04-no-matches/src/lib.rs index ede4eb49a..e06eae4cd 100644 --- a/listings/ch12-an-io-project/output-only-04-no-matches/src/lib.rs +++ b/listings/ch12-an-io-project/output-only-04-no-matches/src/lib.rs @@ -3,28 +3,28 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, + pub file_path: String, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - Ok(Config { query, filename }) + Ok(Config { query, file_path }) } } // ANCHOR: here pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; for line in search(&config.query, &contents) { - println!("{}", line); + println!("{line}"); } Ok(()) diff --git a/listings/ch12-an-io-project/output-only-04-no-matches/src/main.rs b/listings/ch12-an-io-project/output-only-04-no-matches/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch12-an-io-project/output-only-04-no-matches/src/main.rs +++ b/listings/ch12-an-io-project/output-only-04-no-matches/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/src/ch12-00-an-io-project.md b/src/ch12-00-an-io-project.md index ed88cf734..e8212cab9 100644 --- a/src/ch12-00-an-io-project.md +++ b/src/ch12-00-an-io-project.md @@ -18,44 +18,45 @@ the Rust concepts you now have under your belt. Rustの速度、安全性、単バイナリ出力、クロスプラットフォームサポートにより、コマンドラインツールを作るのにふさわしい言語なので、 -このプロジェクトでは、独自の伝統的なコマンドラインツールの`grep`(**g**lobally search a **r**egular **e**xpression +このプロジェクトでは、独自の伝統的なコマンドライン検索ツールの`grep`(**g**lobally search a **r**egular **e**xpression and **p**rint: 正規表現をグローバルで検索し表示する)を作成していきます。最も単純な使用法では、 `grep`は指定したファイルから指定した文字列を検索します。そうするには、 -`grep`は引数としてファイル名と文字列を受け取ります。それからファイルを読み込んでそのファイル内で文字列引数を含む行を探し、 +`grep`は引数としてファイルパスと文字列を受け取ります。それからファイルを読み込んでそのファイル内で文字列引数を含む行を探し、 検索した行を出力するのです。 -その過程で、多くのコマンドラインツールが使用している端末の機能を使用させる方法を示します。 +その過程で、他の多くのコマンドラインツールが使用している端末の機能を使用させる方法を示します。 環境変数の値を読み取ってユーザがこのツールの振る舞いを設定できるようにします。また、 -標準出力(`stdout`)の代わりに、標準エラーに出力(`stderr`)するので、例えば、 +エラーメッセージを標準出力(`stdout`)の代わりに標準エラー(`stderr`)に出力するので、例えば、 ユーザはエラーメッセージは画面上で確認しつつ、成功した出力はファイルにリダイレクトできます。 Rustコミュニティのあるメンバであるアンドリュー・ガラント(Andrew Gallant)が既に全機能装備の非常に高速な`grep`、 -`ripgrep`と呼ばれるものを作成しました。比較対象として、我々の`grep`はとても単純ですが、 +`ripgrep`と呼ばれるものを作成しました。比較対象として、我々のバージョンはとても単純ですが、 この章により、`ripgrep`のような現実世界のプロジェクトを理解するのに必要な背景知識の一部を身に付けられるでしょう。 -* コードを体系化する(モジュール、第7章で学んだことを使用) -* ベクタと文字列を使用する(コレクション、第8章) -* エラーを処理する(第9章) -* 適切な箇所でトレイトとライフタイムを使用する(第10章) -* テストを記述する(第11章) +* コードを体系化する([第7章][ch7]でモジュールについて学んだことを使用) +* ベクタと文字列を使用する(コレクション、[第8章][ch8]) +* エラーを処理する([第9章][ch9]) +* 適切な箇所でトレイトとライフタイムを使用する([第10章][ch10]) +* テストを記述する([第11章][ch11]) -さらに、クロージャ、イテレータ、トレイトオブジェクトなど、第13章、17章で詳しく講義するものもちょっとだけ紹介します。 +さらに、クロージャ、イテレータ、トレイトオブジェクトなど、[第13章][ch13]、[第17章][ch17]で詳しく講義するものもちょっとだけ紹介します。 + +[ch7]: ch07-00-managing-growing-projects-with-packages-crates-and-modules.html +[ch8]: ch08-00-common-collections.html +[ch9]: ch09-00-error-handling.html +[ch10]: ch10-00-generics.html +[ch11]: ch11-00-testing.html +[ch13]: ch13-00-functional-features.html +[ch17]: ch17-00-oop.html diff --git a/src/ch12-01-accepting-command-line-arguments.md b/src/ch12-01-accepting-command-line-arguments.md index 39543877e..3e7c1bc41 100644 --- a/src/ch12-01-accepting-command-line-arguments.md +++ b/src/ch12-01-accepting-command-line-arguments.md @@ -13,30 +13,38 @@ on your system. いつものように、`cargo new`で新しいプロジェクトを作りましょう。プロジェクトを`minigrep`と名付けて、 既に自分のシステムに存在するかもしれない`grep`ツールと区別しましょう。 +```console +$ cargo new minigrep + Created binary (application) `minigrep` project +$ cd minigrep +``` + -最初の仕事は、`minigrep`を二つの引数を受け付けるようにすることです: ファイル名と検索する文字列ですね。 -つまり、`cargo run`で検索文字列と検索を行うファイルへのパスと共にプログラムを実行できるようになりたいということです。 +最初の仕事は、`minigrep`を二つの引数を受け付けるようにすることです: ファイルパスと検索する文字列ですね。 +つまり、`cargo run`、以降の引数が`cargo`に対するものではなく自分のプログラムに対するものであることを示すハイフン2個、 +検索文字列、そして検索を行うファイルへのパスを渡して、プログラムを実行できるようになりたいということです。 こんな感じにね: -```text -$ cargo run searchstring example-filename.txt +```console +$ cargo run -- searchstring example-filename.txt ``` 今現在は、`cargo new`で生成されたプログラムは、与えた引数を処理できません。 -[Crates.io](https://crates.io/)に存在する既存のライブラリには、 +[crates.io](https://crates.io/)に存在する既存のライブラリには、 コマンドライン引数を受け付けるプログラムを書く手助けをしてくれるものもありますが、ちょうどこの概念を学んでいる最中なので、 この能力を自分で実装しましょう。 @@ -48,28 +56,30 @@ just learning this concept, let’s implement this capability ourselves. -`minigrep`が渡したコマンドライン引数の値を読み取れるようにするために、Rustの標準ライブラリで提供されている関数が必要になり、 -それは、`std::env::args`です。この関数は、`minigrep`に与えられたコマンドライン引数の*イテレータ*を返します。 -イテレータについてはまだ議論していません(完全には第13章で講義します)が、とりあえずイテレータに関しては、 -2つの詳細のみ知っていればいいです: イテレータは一連の値を生成することと、イテレータに対して`collect`関数を呼び出し、 +`minigrep`が渡したコマンドライン引数の値を読み取れるようにするために、 +Rustの標準ライブラリで提供されている`std::env::args`関数が必要になります。 +この関数は、`minigrep`に渡されたコマンドライン引数のイテレータを返します。 +イテレータについては[第13章][ch13]で詳しく講義します。 +とりあえずイテレータに関しては、2つの詳細のみ知っていればいいです: +イテレータは一連の値を生成することと、イテレータに対して`collect`メソッドを呼び出し、 イテレータが生成する要素全部を含むベクタなどのコレクションに変えられることです。 -リスト12-1のコードを使用して`minigrep`プログラムに渡されたあらゆるコマンドライン引数を読み取れるようにし、 -それからその値をベクタとして集結させてください。 +リスト12-1のコードを使用することで、`minigrep`プログラムに渡されたあらゆるコマンドライン引数を読み取り、 +それからその値をベクタに集めることができます。 まず、`std::env`モジュールを`use`文でスコープに導入したので、`args`関数が使用できます。 `std::env::args`関数は、2レベルモジュールがネストされていることに注目してください。 -第7章で議論したように、希望の関数が2モジュール以上ネストされている場合、 -関数ではなく親モジュールをスコープに導入するのが因習的です。そうすることで、 +[第7章][ch7-idiomatic-use]で議論したように、希望の関数が2モジュール以上ネストされている場合、 +関数ではなく親モジュールをスコープに導入しています。そうすることで、 `std::env`から別の関数も容易に使用することができます。また、 `use std::env::args`を追記し、関数を`args`とするだけで呼び出すのに比べて曖昧でもありません。 というのも、`args`は現在のモジュールに定義されている関数と容易に見間違えられるかもしれないからです。 @@ -120,7 +125,7 @@ current module. > Unicode. If your program needs to accept arguments containing invalid > Unicode, use `std::env::args_os` instead. That function returns an iterator > that produces `OsString` values instead of `String` values. We’ve chosen to -> use `std::env::args` here for simplicity because `OsString` values differ +> use `std::env::args` here for simplicity, because `OsString` values differ > per platform and are more complex to work with than `String` values. --> @@ -150,21 +155,19 @@ isn’t able to infer the kind of collection you want. コンパイラには、あなたが欲しているコレクションの種類が推論できないからです。 -最後に、デバッグ整形機の`:?`を使用してベクタを出力しています。引数なしでコードを走らせてみて、 -それから引数二つで試してみましょう: +最後に、デバッグマクロを使用してベクタを出力しています。 +まずは引数なしでコードを走らせてみて、それから引数二つで試してみましょう: -```text -$ cargo run ---snip-- -["target/debug/minigrep"] +```console +{{#include ../listings/ch12-an-io-project/listing-12-01/output.txt}} +``` -$ cargo run needle haystack ---snip-- -["target/debug/minigrep", "needle", "haystack"] +```console +{{#include ../listings/ch12-an-io-project/output-only-01-with-args/output.txt}} ``` -引数のベクタの値を出力すると、プログラムはコマンドライン引数として指定された値にアクセスできることが説明されました。 +現時点でプログラムはコマンドライン引数として指定された値にアクセスできます。 さて、プログラムの残りを通して使用できるように、二つの引数の値を変数に保存する必要があります。 それをしているのがリスト12-2です。 @@ -205,42 +208,30 @@ throughout the rest of the program. We do that in Listing 12-2. ファイル名: src/main.rs -```rust,should_panic -use std::env; - -fn main() { - let args: Vec = env::args().collect(); - - let query = &args[1]; - let filename = &args[2]; - - // {}を探しています - println!("Searching for {}", query); - // {}というファイルの中 - println!("In file {}", filename); -} +```rust,should_panic,noplayground +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-02/src/main.rs}} ``` -リスト12-2: クエリ引数とファイル名引数を保持する変数を生成 +リスト12-2: クエリ引数とファイルパス引数を保持する変数を生成 ベクタを出力した時に確認したように、プログラム名がベクタの最初の値、`args[0]`を占めているので、 -添え字`1`から始めます。`minigrep`が取る最初の引数は、検索する文字列なので、 -最初の引数への参照を変数`query`に置きました。2番目の引数はファイル名でしょうから、 -2番目の引数への参照は変数`filename`に置きました。 +引数を添え字`1`から始めます。`minigrep`が取る最初の引数は、検索する文字列なので、 +最初の引数への参照を変数`query`に置きました。2番目の引数はファイルパスでしょうから、 +2番目の引数への参照は変数`file_path`に置きました。 + +[ch13]: ch13-00-functional-features.html +[ch7-idiomatic-use]: ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#慣例に従ったuseパスを作る diff --git a/src/ch12-02-reading-a-file.md b/src/ch12-02-reading-a-file.md index c9ee7049e..700d1e215 100644 --- a/src/ch12-02-reading-a-file.md +++ b/src/ch12-02-reading-a-file.md @@ -5,20 +5,19 @@ ## ファイルを読み込む -では、`filename`コマンドライン引数で指定されたファイルを読み込む機能を追加しましょう。 -まず、テスト実行するためのサンプルファイルが必要ですね: `minigrep`が動作していることを確かめるために使用するのに最適なファイルは、 -複数行にわたって同じ単語の繰り返しのある少量のテキストです。リスト12-3は、 -うまくいくであろうエミリー・ディキンソン(Emily Dickinson)の詩です! -プロジェクトのルート階層に*poem.txt*というファイルを作成し、この詩「私は誰でもない!あなたは誰?」を入力してください。 +では、`file_path`引数で指定されたファイルを読み込む機能を追加しましょう。 +まず、テスト実行するためのサンプルファイルが必要ですね: +複数行にわたって、同じ単語の繰り返しのある、少量のテキストを含むようなファイルを使いましょう。 +リスト12-3は、ちょうど良さそうなエミリー・ディキンソン(Emily Dickinson)の詩です! +プロジェクトのルート階層に*poem.txt*というファイルを作成し、この詩“I’m Nobody! Who are you?”を入力してください。 -テキストを適当な場所に置いて、*src/main.rs*を編集し、ファイルを開くコードを追加してください。 +テキストを適当な場所に置いて、*src/main.rs*を編集し、ファイルを読むコードを追加してください。 リスト12-4に示したようにですね。 -最初に、もう何個か`use`文を追記して、標準ライブラリの関係のある箇所を持ってきています: -ファイルを扱うのに`std::fs::File`が必要ですし、 -`std::io::prelude::*`はファイル入出力を含む入出力処理をするのに有用なトレイトを色々含んでいます。 -言語が一般的な初期化処理で特定の型や関数を自動的にスコープに導入するように、 -`std::io`モジュールにはそれ独自の共通の型や関数の初期化処理があり、入出力を行う際に必要になるわけです。 -標準の初期化処理とは異なり、`std::io`の初期化処理には明示的に`use`文を加えなければなりません。 +最初に、`use`文で、標準ライブラリの関係のある箇所を持ってきています: +ファイルを扱うのには`std::fs`が必要です。 -`main`に3文を追記しました: 一つ目が、`File::open`関数を呼んで`filename`変数の値に渡して、 -ファイルへの可変なハンドルを得る処理です。二つ目が、`contents`という名の変数を生成して、 -可変で空の`String`を割り当てる処理です。この変数が、ファイル読み込み後に中身を保持します。 -三つ目が、ファイルハンドルに対して`read_to_string`を呼び出し、引数として`contents`への可変参照を渡す処理です。 +`main`に追加した`fs::read_to_string`文は、`file_path`を受け取り、そのファイルを開き、 +そのファイルの内容を含む`std::io::Result`を返します。 -それらの行の後に、今回もファイル読み込み後に`contents`の値を出力する一時的な`println!`文を追記したので、 +その後、今回もファイル読み込み後に`contents`の値を出力する一時的な`println!`文を追記しているので、 ここまでプログラムがきちんと動作していることを確認できます。 素晴らしい!コードがファイルの中身を読み込み、出力するようになりました。しかし、このコードにはいくつか欠陥があります。 -`main`関数が複数の責任を受け持っています: 一般に、各関数がただ一つの責任だけを持つようになれば、 +現時点で、`main`関数は複数の責任を受け持っています: 一般に、各関数がただ一つの責任だけを持つようになれば、 関数は明確かつ、管理しやすくなります。もう一つの問題点は、できうる限りのエラー処理を怠っていることです。 まだプログラムが小規模なので、これらの欠陥は大きな問題にはなりませんが、プログラムが大規模になるにつれ、 それを綺麗に解消するのは困難になっていきます。プログラムを開発する際に早い段階でリファクタリングを行うのは、 diff --git a/src/ch12-03-improving-error-handling-and-modularity.md b/src/ch12-03-improving-error-handling-and-modularity.md index 02ff941ad..e6e2edae5 100644 --- a/src/ch12-03-improving-error-handling-and-modularity.md +++ b/src/ch12-03-improving-error-handling-and-modularity.md @@ -6,56 +6,50 @@ プログラムを改善するために、プログラムの構造と起こりうるエラーに対処する方法に関連する4つの問題を修正していきましょう。 - - - -1番目は、`main`関数が2つの仕事を受け持っていることです: 引数を解析し、ファイルを開いています。 -このような小さな関数なら、これは、大した問題ではありませんが、`main`内でプログラムを巨大化させ続けたら、 -`main`関数が扱う個別の仕事の数も増えていきます。関数が責任を受け持つごとに、 +1番目は、`main`関数が2つの仕事を受け持っていることです: 引数を解析し、ファイルを読んでいます。 +プログラムが大きくなるにつれて、`main`関数が扱う個別の仕事の数も増えていきます。関数が責任を受け持つごとに、 正しいことを確認しにくくなり、テストも行いづらくなり、機能を壊さずに変更するのも困難になっていきます。 機能を小分けして、各関数が1つの仕事のみに責任を持つようにするのが最善です。 -この問題は、2番目の問題にも結びついています: `query`と`filename`はプログラムの設定用変数ですが、 -`f`や`contents`といった変数は、プログラムのロジックを担っています。`main`が長くなるほど、 +この問題は、2番目の問題にも結びついています: `query`と`file_path`はプログラムの設定用変数ですが、 +`contents`などの変数は、プログラムのロジックを担っています。`main`が長くなるほど、 スコープに入れるべき変数も増えます。そして、スコープにある変数が増えれば、各々の目的を追うのも大変になるわけです。 設定用変数を一つの構造に押し込め、目的を明瞭化するのが最善です。 -3番目の問題は、ファイルを開き損ねた時に`expect`を使ってエラーメッセージを出力しているのに、 -エラーメッセージが`ファイルが見つかりませんでした`としか表示しないことです。 -ファイルを開く行為は、ファイルが存在しない以外にもいろんな方法で失敗することがあります: -例えば、ファイルは存在するかもしれないけれど、開く権限がないかもしれないなどです。 -現時点では、そのような状況になった時、「ファイルが見つかりませんでした」というエラーメッセージを出力し、 -これはユーザに間違った情報を与えるのです。 +3番目の問題は、ファイルを読み込み損ねた時に`expect`を使ってエラーメッセージを出力しているのに、 +エラーメッセージが`Should have been able to read the file`としか表示しないことです。 +ファイルを読む行為は、いろんな方法で失敗することがあります: +例えば、ファイルが無いのかもしれないし、それを開く権限が無いのかもしれません。 +現時点では、状況にかかわらず、すべてに対して同一のエラーメッセージを出力していて、 +これではユーザに何の情報も与えていないでしょう! @@ -92,22 +86,22 @@ Let’s address these four problems by refactoring our project. `main`関数に複数の仕事の責任を割り当てるという構造上の問題は、多くのバイナリプロジェクトでありふれています。 -結果として、`main`が肥大化し始めた際にバイナリプログラムの個別の責任を分割するためにガイドラインとして活用できる工程をRustコミュニティは、 +結果として、`main`が肥大化し始めた際にバイナリプログラムの個別の責任を分割するためのガイドラインをRustコミュニティは、 開発しました。この工程は、以下のような手順になっています: * プログラムを*main.rs*と*lib.rs*に分け、ロジックを*lib.rs*に移動する。 @@ -135,17 +129,17 @@ should be limited to the following: このパターンは、責任の分離についてです: *main.rs*はプログラムの実行を行い、 そして、*lib.rs*が手にある仕事のロジック全てを扱います。`main`関数を直接テストすることはできないので、 この構造により、プログラムのロジック全てを*lib.rs*の関数に移すことでテストできるようになります。 -*main.rs*に残る唯一のコードは、読めばその正当性が評価できるだけ小規模になるでしょう。 +*main.rs*に残るコードは、読めばその正当性が評価できるだけ小規模になるでしょう。 この工程に従って、プログラムのやり直しをしましょう。 それでもまだ、コマンドライン引数をベクタに集結させていますが、`main`関数内で引数の値の添え字1を変数`query`に、 -添え字2を変数`filename`に代入する代わりに、ベクタ全体を`parse_config`関数に渡しています。 +添え字2を変数`file_path`に代入する代わりに、ベクタ全体を`parse_config`関数に渡しています。 そして、`parse_config`関数にはどの引数がどの変数に入り、それらの値を`main`に返すというロジックが存在します。 -まだ`main`内に`query`と`filename`という変数を生成していますが、もう`main`は、 +まだ`main`内に`query`と`file_path`という変数を生成していますが、もう`main`は、 コマンドライン引数と変数がどう対応するかを決定する責任は持ちません。 このやり直しは、私たちの小規模なプログラムにはやりすぎに思えるかもしれませんが、 @@ -244,8 +225,8 @@ the right abstraction yet. Another indicator that shows there’s room for improvement is the `config` part of `parse_config`, which implies that the two values we return are related and are both part of one configuration value. We’re not currently conveying this -meaning in the structure of the data other than grouping the two values into -a tuple; we could put the two values into one struct and give each of the +meaning in the structure of the data other than by grouping the two values into +a tuple; we’ll instead put the two values into one struct and give each of the struct fields a meaningful name. Doing so will make it easier for future maintainers of this code to understand how the different values relate to each other and what their purpose is. @@ -254,17 +235,9 @@ other and what their purpose is. まだ改善の余地があると示してくれる他の徴候は、`parse_config`の`config`の部分であり、 返却している二つの値は関係があり、一つの設定値の一部にどちらもなることを暗示しています。 現状では、一つのタプルにまとめていること以外、この意味をデータの構造に載せていません; -この二つの値を1構造体に置き換え、構造体のフィールドそれぞれに意味のある名前をつけることもできるでしょう。 +この二つの値を1構造体に置き換え、構造体のフィールドそれぞれに意味のある名前をつけましょう。 そうすることで将来このコードのメンテナンス者が、異なる値が相互に関係する仕方や、目的を理解しやすくできるでしょう。 - - -> 注釈: この複雑型(complex type)がより適切な時に組み込みの値を使うアンチパターンを、 -> *primitive obsession*(`訳注`: 初めて聞いた表現。*組み込み型強迫観念*といったところだろうか)と呼ぶ人もいます。 - @@ -277,34 +250,8 @@ Listing 12-6 shows the improvements to the `parse_config` function. ファイル名: src/main.rs -```rust,should_panic -# use std::env; -# use std::fs::File; -# -fn main() { - let args: Vec = env::args().collect(); - - let config = parse_config(&args); - - println!("Searching for {}", config.query); - println!("In file {}", config.filename); - - let mut f = File::open(config.filename).expect("file not found"); - - // --snip-- -} - -struct Config { - query: String, - filename: String, -} - -fn parse_config(args: &[String]) -> Config { - let query = args[1].clone(); - let filename = args[2].clone(); - - Config { query, filename } -} +```rust,should_panic,noplayground +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-06/src/main.rs:here}} ``` -`query`と`filename`というフィールドを持つよう定義された`Config`という構造体を追加しました。 +`query`と`file_path`というフィールドを持つよう定義された`Config`という構造体を追加しました。 `parse_config`のシグニチャは、これで`Config`値を返すと示すようになりました。`parse_config`の本体では、 以前は`args`の`String`値を参照する文字列スライスを返していましたが、 今では所有する`String`値を含むように`Config`を定義しています。`main`の`args`変数は引数値の所有者であり、 @@ -333,17 +280,16 @@ ownership of the values in `args`. Rustの借用規則に違反してしまうことを意味します。 -`String`のデータは、多くの異なる手法で管理できますが、最も単純だけれどもどこか非効率的な手段は、 +`String`のデータを管理する方法は複数あります; 最も単純だけれども多少非効率的な手段は、 値に対して`clone`メソッドを呼び出すことです。これにより、`Config`インスタンスが所有するデータの総コピーが生成されるので、 文字列データへの参照を保持するよりも時間とメモリを消費します。ですが、データをクローンすることで、 コードがとても素直にもなります。というのも、参照のライフタイムを管理する必要がないからです。 @@ -353,21 +299,22 @@ trade-off. > ### The Trade-Offs of Using `clone` > > There’s a tendency among many Rustaceans to avoid using `clone` to fix -> ownership problems because of its runtime cost. In Chapter 13, you’ll learn -> how to use more efficient methods in this type of situation. But for now, -> it’s okay to copy a few strings to continue making progress because we’ll -> make these copies only once and your filename and query string are very -> small. It’s better to have a working program that’s a bit inefficient than to -> try to hyperoptimize code on your first pass. As you become more experienced -> with Rust, it’ll be easier to start with the most efficient solution, but for -> now, it’s perfectly acceptable to call `clone`. +> ownership problems because of its runtime cost. In +> [Chapter 13][ch13], you’ll learn how to use more efficient +> methods in this type of situation. But for now, it’s okay to copy a few +> strings to continue making progress because you’ll make these copies only +> once and your file path and query string are very small. It’s better to have +> a working program that’s a bit inefficient than to try to hyperoptimize code +> on your first pass. As you become more experienced with Rust, it’ll be +> easier to start with the most efficient solution, but for now, it’s +> perfectly acceptable to call `clone`. --> > ### `clone`を使用する代償 > > 実行時コストのために`clone`を使用して所有権問題を解消するのを避ける傾向が多くのRustaceanにあります。 -> 第13章で、この種の状況においてより効率的なメソッドの使用法を学ぶでしょう。ですがとりあえずは、 -> これらのコピーをするのは1回だけですし、ファイル名とクエリ文字列は非常に小さなものなので、 +> [第13章][ch13]で、この種の状況においてより効率的なメソッドの使用法を学ぶでしょう。ですがとりあえずは、 +> これらのコピーをするのは1回だけですし、ファイルパスとクエリ文字列は非常に小さなものなので、 > いくつかの文字列をコピーして進捗するのは良しとしましょう。最初の通り道でコードを究極的に効率化しようとするよりも、 > ちょっと非効率的でも動くプログラムを用意する方がいいでしょう。もっとRustの経験を積めば、 > 最も効率的な解決法から開始することも簡単になるでしょうが、今は、`clone`を呼び出すことは完璧に受け入れられることです。 @@ -375,21 +322,21 @@ trade-off. `main`を更新したので、`parse_config`から返された`Config`のインスタンスを`config`という変数に置くようになり、 -以前は個別の`query`と`filename`変数を使用していたコードを更新したので、代わりに`Config`構造体のフィールドを使用するようになりました。 +以前は個別の`query`と`file_path`変数を使用していたコードを更新したので、代わりに`Config`構造体のフィールドを使用するようになりました。 -これでコードは`query`と`filename`が関連していることと、その目的がプログラムの振る舞い方を設定するということをより明確に伝えます。 +これでコードは`query`と`file_path`が関連していることと、その目的がプログラムの振る舞い方を設定するということをより明確に伝えます。 これらの値を使用するあらゆるコードは、`config`インスタンスの目的の名前を冠したフィールドにそれらを発見することを把握しています。 ここまでで、コマンドライン引数を解析する責任を負ったロジックを`main`から抽出し、`parse_config`関数に配置しました。 -そうすることで`query`と`filename`の値が関連し、その関係性がコードに載っていることを確認する助けになりました。 -それから`Config`構造体を追加して`query`と`filename`の関係する目的を名前付けし、 +そうすることで`query`と`file_path`の値が関連し、その関係性がコードに載っていることを確認する助けになりました。 +それから`Config`構造体を追加して`query`と`file_path`の関係する目的を名前付けし、 構造体のフィールド名として`parse_config`関数からその値の名前を返すことができています。 `境界外アクセス: 長さは1なのに添え字も1です`という行は、プログラマ向けのエラーメッセージです。 -エンドユーザが起きたことと代わりにすべきことを理解する手助けにはならないでしょう。これを今修正しましょう。 +エンドユーザが代わりにすべきことを理解する手助けにはならないでしょう。これを今修正しましょう。 リスト12-8で、`new`関数に、添え字1と2にアクセスする前にスライスが十分長いことを実証するチェックを追加しています。 -スライスの長さが十分でなければ、プログラムはパニックし、`境界外インデックス`よりもいいエラーメッセージを表示します。 +スライスの長さが十分でなければ、プログラムはパニックし、より良いエラーメッセージを表示します。 -このコードは、リスト9-9で記述した`value`引数が正常な値の範囲外だった時に`panic!`を呼び出した`Guess::new`関数と似ています。 +このコードは、`value`引数が正常な値の範囲外だった時に`panic!`を呼び出していた、[リスト9-13の中で書いた`Guess::new`関数][ch9-custom-types]と似ています。 ここでは、値の範囲を確かめる代わりに、`args`の長さが少なくとも3であることを確かめていて、 関数の残りの部分は、この条件が満たされているという前提のもとで処理を行うことができます。 `args`に2要素以下しかなければ、この条件は真になり、`panic!`マクロを呼び出して、即座にプログラムを終了させます。 @@ -579,60 +488,62 @@ arguments again to see what the error looks like now: では、`new`のこの追加の数行がある状態で、再度引数なしでプログラムを走らせ、エラーがどんな見た目か確かめましょう: -```text -$ cargo run - Compiling minigrep v0.1.0 (file:///projects/minigrep) - Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs - Running `target/debug/minigrep` -thread 'main' panicked at 'not enough arguments', src/main.rs:30:12 -(スレッド'main'は「引数が足りません」でパニックしました) -note: Run with `RUST_BACKTRACE=1` for a backtrace. +```console +{{#include ../listings/ch12-an-io-project/listing-12-08/output.txt}} ``` この出力の方がマシです: これでエラーメッセージが合理的になりました。ですが、 ユーザに与えたくない追加の情報も含まれてしまっています。おそらく、 -ここではリスト9-9で使用したテクニックを使用するのは最善ではありません: -`panic!`の呼び出しは、第9章で議論したように、使用の問題よりもプログラミング上の問題により適しています。 -代わりに、第9章で学んだもう一つのテクニックを使用することができます。成功か失敗かを示唆する`Result`を返すことです。 +ここではリスト9-13で使用したテクニックを使用するのは最善ではありません: +`panic!`の呼び出しは、[第9章で議論したように][ch9-error-guidelines]、使用の問題よりもプログラミング上の問題により適しています。 +代わりに、第9章で学んだもう一つのテクニックを使用しましょう。成功か失敗かを示唆する[`Result`を返す][ch9-result]ことです。 + -#### `panic!`を呼び出す代わりに`new`から`Result`を返す + + +#### `panic!`を呼び出す代わりに`Result`を返す 代わりに、成功時には`Config`インスタンスを含み、エラー時には問題に言及する`Result`値を返すことができます。 -`Config::new`が`main`と対話する時、`Result`型を使用して問題があったと信号を送ることができます。 +また、多くのプログラマは`new`関数は決して失敗しないことを期待するので、関数名を`new`から`build`に変更します。 +`Config::build`が`main`と対話する時、`Result`型を使用して問題があったと信号を送ることができます。 それから`main`を変更して、`panic!`呼び出しが引き起こしていた`thread 'main'`と`RUST_BACKTRACE`に関する周囲のテキストがない、 ユーザ向けのより実用的なエラーに`Err`列挙子を変換することができます。 -リスト12-9は、`Config::new`の戻り値に必要な変更と`Result`を返すのに必要な関数の本体を示しています。 +リスト12-9は、新しく`Config::build`と呼ばれる関数の戻り値に必要な変更と、`Result`を返すのに必要な関数の本体を示しています。 `main`も更新するまで、これはコンパイルできないことに注意してください。その更新は次のリストで行います。 -リスト12-9: `Config::new`から`Result`を返却する +リスト12-9: `Config::build`から`Result`を返却する -`new`関数は、これで、成功時には`Config`インスタンスを、エラー時には`&'static str`を伴う`Result`を返すようになりました。 -第10章の「静的ライフタイム」節から`&'static str`は文字列リテラルの型であることを思い出してください。 -これは、今はエラーメッセージの型になっています。 +`build`関数は、成功時には`Config`インスタンスを、エラー時には`&'static str`を伴う`Result`を返すようになりました。 +ここ使うエラー値は常に、`'static`ライフタイムを持つ文字列リテラルになります。 -`new`関数の本体で2つ変更を行いました: 十分な数の引数をユーザが渡さなかった場合に`panic!`を呼び出す代わりに、 +関数の本体で2つ変更を行いました: 十分な数の引数をユーザが渡さなかった場合に`panic!`を呼び出す代わりに、 今は`Err`値を返し、`Config`戻り値を`Ok`に包んでいます。これらの変更により、関数が新しい型シグニチャに適合するわけです。 -`Config::new`から`Err`値を返すことにより、`main`関数は、`new`関数から返ってくる`Result`値を処理し、 +`Config::build`から`Err`値を返すことにより、`main`関数は、`build`関数から返ってくる`Result`値を処理し、 エラー時により綺麗にプロセスから抜け出すことができます。 + -#### `Config::new`を呼び出し、エラーを処理する + + +#### `Config::build`を呼び出し、エラーを処理する エラーケースを処理し、ユーザフレンドリーなメッセージを出力するために、`main`を更新して、 -リスト12-10に示したように`Config::new`から返されている`Result`を処理する必要があります。 +リスト12-10に示したように`Config::build`から返されている`Result`を処理する必要があります。 また、`panic!`からコマンドラインツールを0以外のエラーコードで抜け出す責任も奪い取り、 -手作業でそれも実装します。0以外の終了コードは、 +代わりに手作業でそれを実装します。0以外の終了コードは、 我々のプログラムを呼び出したプロセスにプログラムがエラー状態で終了したことを通知する慣習です。 -リスト12-10: 新しい`Config`作成に失敗したら、エラーコードで終了する +リスト12-10: `Config`構築に失敗したら、エラーコードで終了する -このリストにおいて、以前には講義していないメソッドを使用しました: `unwrap_or_else`です。 +このリストにおいて、まだ詳しく扱っていないメソッドを使用しました: `unwrap_or_else`です。 これは標準ライブラリで`Result`に定義されています。`unwrap_or_else`を使うことで、 `panic!`ではない何らか独自のエラー処理を定義できるのです。この`Result`が`Ok`値だったら、 このメソッドの振る舞いは`unwrap`に似ています: `Ok`が包んでいる中身の値を返すのです。 しかし、値が`Err`値なら、このメソッドは、*クロージャ*内でコードを呼び出し、 -クロージャは私たちが定義し、引数として`unwrap_or_else`に渡す匿名関数です。クロージャについては第13章で詳しく講義します。 -とりあえず、`unwrap_or_else`は、今回リスト12-9で追加した`not enough arguments`という静的文字列の`Err`の中身を、 +クロージャは私たちが定義し、引数として`unwrap_or_else`に渡す匿名関数です。クロージャについては[第13章][ch13]で詳しく講義します。 +とりあえず、`unwrap_or_else`は、今回リスト12-9で追加した`"not enough arguments"`という静的文字列の`Err`の中身を、 縦棒の間に出現する`err`引数のクロージャに渡していることだけ知っておく必要があります。 クロージャのコードはそれから、実行された時に`err`値を使用できます。 -新規`use`行を追加して標準ライブラリから`process`をインポートしました。クロージャ内のエラー時に走るコードは、 +新規`use`行を追加して標準ライブラリから`process`をスコープ内に持ち込みました。クロージャ内のエラー時に走るコードは、 たった2行です: `err`の値を出力し、それから`process::exit`を呼び出します。`process::exit`関数は、 即座にプログラムを停止させ、渡された数字を終了コードとして返します。これは、リスト12-8で使用した`panic!`ベースの処理と似ていますが、 もう余計な出力はされません。試しましょう: -```text -$ cargo run - Compiling minigrep v0.1.0 (file:///projects/minigrep) - Finished dev [unoptimized + debuginfo] target(s) in 0.48 secs - Running `target/debug/minigrep` -Problem parsing arguments: not enough arguments +```console +{{#include ../listings/ch12-an-io-project/listing-12-10/output.txt}} ``` これで設定解析のリファクタリングが終了したので、プログラムのロジックに目を向けましょう。 -「バイナリプロジェクトの責任の分離」で述べたように、 +[「バイナリプロジェクトの責任の分離」](#バイナリプロジェクトの責任の分離)で述べたように、 現在`main`関数に存在する設定のセットアップやエラー処理に関わらない全てのロジックを保持することになる`run`という関数を抽出します。 やり終わったら、`main`は簡潔かつ視察で確かめやすくなり、他のロジック全部に対してテストを書くことができるでしょう。 @@ -833,26 +722,7 @@ defining the function in *src/main.rs*. ファイル名: src/main.rs ```rust,ignore -fn main() { - // --snip-- - - println!("Searching for {}", config.query); - println!("In file {}", config.filename); - - run(config); -} - -fn run(config: Config) { - let mut f = File::open(config.filename).expect("file not found"); - - let mut contents = String::new(); - f.read_to_string(&mut contents) - .expect("something went wrong reading the file"); - - println!("With text:\n{}", contents); -} - -// --snip-- +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-11/src/main.rs:here}} ``` -残りのプログラムロジックが`run`関数に隔離されたので、リスト12-9の`Config::new`のように、 +残りのプログラムロジックが`run`関数に隔離されたので、リスト12-9の`Config::build`のように、 エラー処理を改善することができます。`expect`を呼び出してプログラムにパニックさせる代わりに、 `run`関数は、何か問題が起きた時に`Result`を返します。これにより、 さらにエラー処理周りのロジックをユーザに優しい形で`main`に統合することができます。 @@ -906,20 +776,7 @@ signature and body of `run`. ファイル名: src/main.rs ```rust,ignore -use std::error::Error; - -// --snip-- - -fn run(config: Config) -> Result<(), Box> { - let mut f = File::open(config.filename)?; - - let mut contents = String::new(); - f.read_to_string(&mut contents)?; - - println!("With text:\n{}", contents); - - Ok(()) -} +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-12/src/main.rs:here}} ``` エラー型については、*トレイトオブジェクト*の`Box`を使用しました(同時に冒頭で`use`文により、 -`std::error::Error`をスコープに導入しています)。トレイトオブジェクトについては、第17章で講義します。 +`std::error::Error`をスコープに導入しています)。トレイトオブジェクトについては、[第17章][ch17]で講義します。 とりあえず、`Box`は、関数が`Error`トレイトを実装する型を返すことを意味しますが、 戻り値の型を具体的に指定しなくても良いことを知っておいてください。これにより、 エラーケースによって異なる型のエラー値を返す柔軟性を得ます。`dyn` キーワードは、"dynamic"の略です。 -2番目に、`expect`の呼び出しよりも`?`演算子を選択して取り除きました。第9章で語りましたね。 -エラーでパニックするのではなく、`?`演算子は呼び出し元が処理できるように、現在の関数からエラー値を返します。 +2番目に、[第9章][ch9-question-mark]で書いたのと同様に、`?`演算子で`expect`の呼び出しを置き換えました。 +エラーでパニックするのではなく、`?`は呼び出し元が処理できるように、現在の関数からエラー値を返します。 3番目に、`run`関数は今、成功時に`Ok`値を返すようになりました。`run`関数の成功型は、 @@ -984,14 +843,8 @@ When you run this code, it will compile but will display a warning: このコードを実行すると、コンパイルは通るものの、警告が表示されるでしょう: -```text -warning: unused `std::result::Result` which must be used -(警告: 使用されなければならない`std::result::Result`が未使用です) - --> src/main.rs:18:5 - | -18 | run(config); - | ^^^^^^^^^^^^ -= note: #[warn(unused_must_use)] on by default +```console +{{#include ../listings/ch12-an-io-project/listing-12-12/output.txt}} ``` -リスト12-10の`Config::new`に対して行った方法に似たテクニックを使用してエラーを確認し、扱いますが、 +リスト12-10の`Config::build`に対して行った方法に似たテクニックを使用してエラーを確認し、扱いますが、 少し違いがあります: `unwrap_or_else`ではなく、`if let`で`run`が`Err`値を返したかどうかを確認し、そうなら`process::exit(1)`を呼び出しています。 -`run`関数は、`Config::new`が`Config`インスタンスを返すのと同じように`unwrap`したい値を返すことはありません。 -`run`は成功時に`()`を返すので、エラーを検知することにのみ興味があり、`()`でしかないので、 -`unwrap_or_else`に包まれた値を返してもらう必要はないのです。 +`run`関数は、`Config::build`が`Config`インスタンスを返すのと同じように`unwrap`したい値を返すことはありません。 +`run`は成功時に`()`を返すので、エラーを検知することにのみ興味があり、 +ただの`()`でしかない包まれた値を、`unwrap_or_else`に返してもらう必要はないのです。 -ここまで`minigrep`は良さそうですね!では、テストを行え、*src/main.rs*ファイルの責任が減らせるように、 -*src/main.rs*ファイルを分割し、一部のコードを*src/lib.rs*ファイルに置きましょう。 +ここまで`minigrep`は良さそうですね! +では、*src/main.rs*ファイルを分割し、一部のコードを*src/lib.rs*ファイルに置きましょう。 +そのようにして、コードをテストし、*src/main.rs*ファイルの責任を減らすことができます。 * `run`関数定義 * 関係する`use`文 * `Config`の定義 -* `Config::new`関数定義 +* `Config::build`関数定義 @@ -1115,25 +958,8 @@ compile until we modify *src/main.rs* in Listing 12-14. ファイル名: src/lib.rs -```rust,ignore -use std::error::Error; -use std::fs::File; -use std::io::prelude::*; - -pub struct Config { - pub query: String, - pub filename: String, -} - -impl Config { - pub fn new(args: &[String]) -> Result { - // --snip-- - } -} - -pub fn run(config: Config) -> Result<(), Box> { - // --snip-- -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-13/src/lib.rs:here}} ``` -ここでは、寛大に`pub`を使用しています: `Config`のフィールドと`new`メソッドと`run`関数です。 +ここでは寛大に`pub`キーワードを使用しています: `Config`のフィールドと`build`メソッドと`run`関数です。 これでテスト可能な公開APIのあるライブラリクレートができました! -リスト12-14: `minigrep`クレートを*src/main.rs*のスコープに持っていく +リスト12-14: *src/main.rs*で`minigrep`ライブラリクレートを使用する -ライブラリクレートをバイナリクレートに持っていくのに、`extern crate minigrep`を使用しています。 -それから`use minigrep::Config`行を追加して`Config`型をスコープに持ってきて、 +`use minigrep::Config`の行を追加することで、`Config`型をライブラリクレートからバイナリクレートのスコープに持ってきて、 `run`関数にクレート名を接頭辞として付けます。これで全機能が連結され、動くはずです。 `cargo run`でプログラムを走らせて、すべてがうまくいっていることを確かめてください。 @@ -1220,3 +1033,19 @@ write some tests! 古いコードでは大変だけれども、新しいコードでは楽なことをして新発見のモジュール性を活用しましょう: テストを書くのです! + + + +[ch13]: ch13-00-functional-features.html +[ch9-custom-types]: ch09-03-to-panic-or-not-to-panic.html#検証のために独自の型を作る +[ch9-error-guidelines]: ch09-03-to-panic-or-not-to-panic.html#エラー処理のガイドライン +[ch9-result]: ch09-02-recoverable-errors-with-result.html +[ch17]: ch17-00-oop.html +[ch9-question-mark]: ch09-02-recoverable-errors-with-result.html#エラー委譲のショートカット-演算子 diff --git a/src/ch12-04-testing-the-librarys-functionality.md b/src/ch12-04-testing-the-librarys-functionality.md index 1e9f12cfe..6fcc81582 100644 --- a/src/ch12-04-testing-the-librarys-functionality.md +++ b/src/ch12-04-testing-the-librarys-functionality.md @@ -1,5 +1,5 @@ ## テスト駆動開発でライブラリの機能を開発する @@ -9,30 +9,26 @@ Now that we’ve extracted the logic into *src/lib.rs* and left the argument collecting and error handling in *src/main.rs*, it’s much easier to write tests for the core functionality of our code. We can call functions directly with various arguments and check return values without having to call our binary -from the command line. Feel free to write some tests for the functionality in -the `Config::new` and `run` functions on your own. +from the command line. --> 今や、ロジックを*src/lib.rs*に抜き出し、引数集めとエラー処理を*src/main.rs*に残したので、 コードの核となる機能のテストを書くのが非常に容易になりました。いろんな引数で関数を直接呼び出し、 -コマンドラインからバイナリを呼び出す必要なく戻り値を確認できます。ご自由に`Config::new`や`run`関数の機能のテストは、 -ご自身でお書きください。 +コマンドラインからバイナリを呼び出す必要なく戻り値を確認できます。 -この節では、テスト駆動開発(TDD)過程を活用して`minigrep`プログラムに検索ロジックを追加します。 -このソフトウェア開発テクニックは、以下の手順に従います: +この節では、以下の手順に従ってテスト駆動開発(TDD)プロセスを活用して、`minigrep`プログラムに検索ロジックを追加します: @@ -42,12 +38,12 @@ continue to pass. 4. 手順1から繰り返す! -この過程は、ソフトウェアを書く多くの方法のうちの一つに過ぎませんが、TDDによりコードデザインも駆動することができます。 +TDDはソフトウェアを書く多くの方法のうちの一つに過ぎませんが、コードデザインを駆動するために役立てることができます。 テストを通過させるコードを書く前にテストを書くことで、過程を通して高いテストカバー率を保つ助けになります。 もう必要ないので、プログラムの振る舞いを確認していた`println!`文を*src/lib.rs*と*src/main.rs*から削除しましょう。 -それから*src/lib.rs*で、テスト関数のある`test`モジュールを追加します。第11章のようにですね。 -このテスト関数が`search`関数に欲しい振る舞いを指定します: クエリとそれを検索するテキストを受け取り、 +それから*src/lib.rs*で、テスト関数のある`tests`モジュールを追加してください。[第11章][ch11-anatomy]のようにですね。 +このテスト関数が`search`関数に欲しい振る舞いを指定します: クエリと検索対象のテキストを受け取り、 クエリを含む行だけをテキストから返します。リスト12-15にこのテストを示していますが、まだコンパイルは通りません。 -このテストは、`"duct"`という文字列を検索します。検索対象の文字列は3行で、うち1行だけが`"duct"`を含みます。 +このテストは、`"duct"`という文字列を検索します。検索対象の文字列は3行で、うち1行だけが`"duct"`を含みます +(開き二重引用符の後のバックスラッシュは、この文字列リテラルの内容の先頭に改行文字を置かないように、 +コンパイラに指示しているということに注意してください)。 `search`関数から返る値が想定している行だけを含むことをアサーションします。 -このテストを走らせ、失敗するところを観察することはできません。このテストはコンパイルもできないからです: -まだ`search`関数が存在していません!ゆえに今度は、空のベクタを常に返す`search`関数の定義を追加することで、 +このテストを走らせ、失敗するところを観察することは、まだできません。このテストはコンパイルもできないからです: +まだ`search`関数が存在していません!TDDの原則に従って、空のベクタを常に返す`search`関数の定義を追加することで、 テストをコンパイルし走らせるだけのコードを追記します。リスト12-16に示したようにですね。そうすれば、 テストはコンパイルでき、失敗するはずです。なぜなら、空のベクタは、 `"safe, fast, productive."`という行を含むベクタとは合致しないからです。 @@ -152,10 +129,8 @@ containing the line `"safe, fast, productive."`. ファイル名: src/lib.rs -```rust -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { - vec![] -} +```rust,noplayground +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-16/src/lib.rs:here}} ``` -明示的なライフタイムの`'a`が`search`のシグニチャで定義され、`contents`引数と戻り値で使用されていることに注目してください。 -第10章からライフタイム仮引数は、どの実引数のライフタイムが戻り値のライフタイムに関連づけられているかを指定することを思い出してください。 +`search`のシグニチャ内で、明示的なライフタイム`'a`を定義し、そのライフタイムを`contents`引数と戻り値で使用していることに注目してください。 +[第10章][ch10-lifetimes]からライフタイム仮引数は、どの実引数のライフタイムが戻り値のライフタイムに関連づけられているかを指定することを思い出してください。 この場合、返却されるベクタは、 (`query`引数ではなく)`contents`引数のスライスを参照する文字列スライスを含むべきと示唆しています。 @@ -205,41 +181,32 @@ get this error: ライフタイム注釈を忘れてこの関数をコンパイルしようとすると、こんなエラーが出ます: -```text -error[E0106]: missing lifetime specifier -(エラー: ライフタイム指定子が欠けています) - --> src/lib.rs:5:51 - | -5 | pub fn search(query: &str, contents: &str) -> Vec<&str> { - | ^ expected lifetime -parameter - | - = help: this function's return type contains a borrowed value, but the - signature does not say whether it is borrowed from `query` or `contents` - (助言: この関数の戻り値は、借用された値を含んでいますが、シグニチャにはそれが、 - `query`か`contents`から借用されたものであるかが示されていません) +```console +{{#include ../listings/ch12-an-io-project/output-only-02-missing-lifetimes/output.txt}} ``` -コンパイラには、二つの引数のどちらが必要なのか知る由がないので、教えてあげる必要があるのです。 +コンパイラには、二つの引数のどちらが必要なのか知る由がないので、明示的に教えてあげる必要があるのです。 `contents`がテキストを全て含む引数で、合致するそのテキストの一部を返したいので、 `contents`がライフタイム記法で戻り値に関連づくはずの引数であることをプログラマは知っています。 -他のプログラミング言語では、シグニチャで引数と戻り値を関連づける必要はありません。これは奇妙に思えるかもしれませんが、 -時間とともに楽になっていきます。この例を第10章、「ライフタイムで参照を有効化する」節と比較したくなるかもしれません。 +他のプログラミング言語では、シグニチャで引数と戻り値を関連づける必要はありませんが、この実践は時間とともに楽になっていくでしょう。 +この例を第10章の[「ライフタイムで参照を検証する」][validating-references-with-lifetimes]節と比較してみるといいかもしれません。 -`lines`メソッドはイテレータを返します。イテレータについて詳しくは、第13章で話しますが、 -リスト3-5でこのようなイテレータの使用法は見かけたことを思い出してください。 +`lines`メソッドはイテレータを返します。イテレータについて詳しくは、[第13章][ch13-iterators]で話しますが、 +[リスト3-5][ch3-iter]でこのようなイテレータの使用法は見かけたことを思い出してください。 そこでは、イテレータに`for`ループを使用してコレクションの各要素に対して何らかのコードを走らせていました。 + +ここまでで機能を組み上げてきました。これをコンパイルできるようにするためには、 +関数のシグネチャでそうすると示したように、本体から値を返す必要があります。 + @@ -411,13 +352,13 @@ line contains the string in `query` #### 合致した行を保存する -また、クエリ文字列を含む行を保存する方法が必要です。そのために、`for`ループの前に可変なベクタを生成し、 +この関数を完成させるには、返そうとしている、合致した行を保存する方法が必要です。そのために、`for`ループの前に可変なベクタを生成し、 `push`メソッドを呼び出して`line`をベクタに保存することができます。`for`ループの後でベクタを返却します。 リスト12-19のようにですね。 @@ -428,17 +369,7 @@ shown in Listing 12-19. ファイル名: src/lib.rs ```rust,ignore -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { - let mut results = Vec::new(); - - for line in contents.lines() { - if line.contains(query) { - results.push(line); - } - } - - results -} +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-19/src/lib.rs:here}} ``` ここで、テストが通過するよう保ったまま、同じ機能を保持しながら、検索関数の実装をリファクタリングする機会を考えることもできます。 検索関数のコードは悪すぎるわけではありませんが、イテレータの有用な機能の一部を活用していません。 -この例には第13章で再度触れ、そこでは、イテレータをより深く探究し、さらに改善する方法に目を向けます。 +この例には[第13章][ch13-iterators]で再度触れ、そこでは、イテレータをより深く探究し、さらに改善する方法に目を向けます。 + +[validating-references-with-lifetimes]: +ch10-03-lifetime-syntax.html#ライフタイムで参照を検証する +[ch11-anatomy]: ch11-01-writing-tests.html#テスト関数の構成 +[ch10-lifetimes]: ch10-03-lifetime-syntax.html +[ch3-iter]: ch03-05-control-flow.html#forでコレクションを覗き見る +[ch13-iterators]: ch13-02-iterators.html diff --git a/src/ch12-05-working-with-environment-variables.md b/src/ch12-05-working-with-environment-variables.md index 25a767ef7..fc7f34a95 100644 --- a/src/ch12-05-working-with-environment-variables.md +++ b/src/ch12-05-working-with-environment-variables.md @@ -8,15 +8,14 @@ We’ll improve `minigrep` by adding an extra feature: an option for case-insensitive searching that the user can turn on via an environment variable. We could make this feature a command line option and require that -users enter it each time they want it to apply, but instead we’ll use an -environment variable. Doing so allows our users to set the environment variable -once and have all their searches be case insensitive in that terminal session. +users enter it each time they want it to apply, but by instead making it an +environment variable, we allow our users to set the environment variable once +and have all their searches be case insensitive in that terminal session. --> おまけの機能を追加して`minigrep`を改善します: 環境変数でユーザがオンにできる大文字小文字無視の検索用のオプションです。 この機能をコマンドラインオプションにして、適用したい度にユーザが入力しなければならないようにすることもできますが、 -代わりに環境変数を使用します。そうすることでユーザは1回環境変数をセットすれば、そのターミナルセッションの間は、 -大文字小文字無視の検索を行うことができるようになるわけです。 +代わりに環境変数とすることで、ユーザは1回環境変数をセットすれば、そのターミナルセッションの間は大文字小文字無視の検索を行うことができるようにします。 -環境変数がオンの場合に呼び出す`search_case_insensitive`関数を新しく追加したいです。テスト駆動開発の過程に従い続けるので、 +まず、環境変数が値を持つ場合に呼び出される`search_case_insensitive`関数を新しく追加します。テスト駆動開発の過程に従い続けるので、 最初の手順は、今回も失敗するテストを書くことです。新しい`search_case_insensitive`関数用の新規テストを追加し、 古いテストを`one_result`から`case_sensitive`に名前変更して、二つのテストの差異を明確化します。 リスト12-20に示したようにですね。 @@ -44,47 +43,8 @@ tests, as shown in Listing 12-20. ファイル名: src/lib.rs -```rust -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn case_sensitive() { - let query = "duct"; -// Rust -// 安全かつ高速で生産的 -// 三つを選んで -// ガムテープ - let contents = "\ -Rust: -safe, fast, productive. -Pick three. -Duct tape."; - - assert_eq!( - vec!["safe, fast, productive."], - search(query, contents) - ); - } - - #[test] - fn case_insensitive() { - let query = "rUsT"; -// (最後の行のみ) -// 私を信じて - let contents = "\ -Rust: -safe, fast, productive. -Pick three. -Trust me."; - - assert_eq!( - vec!["Rust:", "Trust me."], - search_case_insensitive(query, contents) - ); - } -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-20/src/lib.rs:here}} ``` -大文字小文字を区別*しない*検索の新しいテストは、クエリに"rUsT"を使用しています。 -追加直前の`search_case_insensitive`関数では、"rUsT"というクエリは、 -両方ともクエリとは大文字小文字が異なるのに、大文字Rの"Rust:"を含む行と、 -`“Trust me.”`という行にもマッチするはずです。これが失敗するテストであり、まだ`search_case_insensitive`関数を定義していないので、 +大文字小文字を区別*しない*検索の新しいテストは、クエリに`"rUsT"`を使用しています。 +追加直前の`search_case_insensitive`関数では、`"rUsT"`というクエリは、 +両方ともクエリとは大文字小文字が異なるのに、大文字Rの`"Rust:"`を含む行と、 +`"Trust me."`という行にもマッチするはずです。これが失敗するテストであり、まだ`search_case_insensitive`関数を定義していないので、 コンパイルは失敗するでしょう。リスト12-16の`search`関数で行ったのと同様に空のベクタを常に返すような仮実装を追加し、テストがコンパイルされるものの、失敗する様をご自由に確認してください。 まず、`query`文字列を小文字化し、同じ名前の覆い隠された変数に保存します。ユーザのクエリが`"rust"`や`"RUST"`、 `"Rust"`、`"rUsT"`などだったりしても、`"rust"`であり、大文字小文字を区別しないかのようにクエリを扱えるように、 `to_lowercase`をクエリに対して呼び出すことは必須です。 +`to_lowercase`は基本的なUnicodeを処理しますが、100%正確ではありません。 +現実のアプリケーションを書いているとしたら、ここでもう少し処理を入れたくなるでしょうが、 +この節は環境変数についての節であってUnicodeについての節ではないので、ここではそのままにしておきましょう。 @@ -198,17 +154,12 @@ a string slice. アンド記号を追加する必要があります。`contains`のシグニチャは、文字列スライスを取るよう定義されているからです。 - - -次に、各`line`が`query`を含むか確かめる前に`to_lowercase`の呼び出しを追加し、全文字を小文字化しています。 +次に、各`line`に対して`to_lowercase`の呼び出しを追加し、全文字を小文字化しています。 今や`line`と`query`を小文字に変換したので、クエリが大文字であろうと小文字であろうとマッチを検索するでしょう。 -論理値を持つ`case_sensitive`フィールドを追加したことに注意してください。次に、`run`関数に、 -`case_sensitive`フィールドの値を確認し、`search`関数か`search_case_insensitive`関数を呼ぶかを決定するのに使ってもらう必要があります。 -リスト12-22のようにですね。それでも、これはまだコンパイルできないことに注意してください。 +論理値を持つ`ignore_case`フィールドを追加しました。次に、`run`関数に、 +`ignore_case`フィールドの値を確認し、`search`関数か`search_case_insensitive`関数を呼ぶかを決定するのに使ってもらう必要があります。 +リスト12-22のようにですね。それでも、これはまだコンパイルできません。 -リスト12-22: `config.case_sensitive`の値に基づいて`search`か`search_case_insensitive`を呼び出す +リスト12-22: `config.ignore_case`の値に基づいて`search`か`search_case_insensitive`を呼び出す 最後に、環境変数を確認する必要があります。環境変数を扱う関数は、標準ライブラリの`env`モジュールにあるので、 -`use std::env;`行で*src/lib.rs*の冒頭でそのモジュールをスコープに持ってくる必要があります。そして、 -`env`モジュールから`var`関数を使用して`CASE_INSENSITIVE`という環境変数のチェックを行います。 +*src/lib.rs*の冒頭でそのモジュールをスコープ内に持ち込みます。そして、 +`env`モジュールから`var`関数を使用して、`IGNORE_CASE`という環境変数に何らかの値が設定されているかチェックします。 リスト12-23のようにですね。 -リスト12-23: `CASE_INSENSITIVE`という環境変数のチェックを行う +リスト12-23: `IGNORE_CASE`という環境変数に何らかの値が設定されているかチェックする -ここで、`case_sensitive`という新しい変数を生成しています。その値をセットするために、 -`env::var`関数を呼び出し、`CASE_INSENSITIVE`環境変数の名前を渡しています。`env::var`関数は、 -環境変数がセットされていたら、環境変数の値を含む`Ok`列挙子の成功値になる`Result`を返します。 +ここで、`ignore_case`という新しい変数を生成しています。その値をセットするために、 +`env::var`関数を呼び出し、`IGNORE_CASE`環境変数の名前を渡しています。`env::var`関数は、 +環境変数に何らかの値がセットされていたら、環境変数の値を含む`Ok`列挙子の成功値になる`Result`を返します。 環境変数がセットされていなければ、`Err`列挙子を返すでしょう。 -`Result`の`is_err`メソッドを使用して、エラーでありゆえに、セットされていないことを確認しています。 -これは大文字小文字を区別する検索をす*べき*ことを意味します。`CASE_INSENSITIVE`環境変数が何かにセットされていれば、 -`is_err`はfalseを返し、プログラムは大文字小文字を区別しない検索を実行するでしょう。環境変数の*値*はどうでもよく、 -セットされているかどうかだけ気にするので、`unwrap`や`expect`あるいは、他のここまで見かけた`Result`のメソッドではなく、 -`is_err`をチェックしています。 +`Result`の`is_ok`メソッドを使用して、環境変数が設定されているか、つまりプログラムが大文字小文字を区別しない検索を行うべきかどうかを、 +チェックしています。`IGNORE_CASE`環境変数が何にも設定されていなければ、 +`is_ok`はfalseを返し、プログラムは大文字小文字を区別する検索を実行するでしょう。環境変数の*値*はどうでもよく、 +セットされているかどうかだけ気にするので、`unwrap`や`expect`あるいは、他のここまで見かけた`Result`のメソッドを使用するのではなく、 +`is_ok`をチェックしています。 -`case_sensitive`変数の値を`Config`インスタンスに渡しているので、リスト12-22で実装したように、 -`run`関数はその値を読み取り、`search`か`search_case_insensitive`を呼び出すか決定できるのです。 +`ignore_case`変数の値を`Config`インスタンスに渡しているので、リスト12-22で実装したように、 +`run`関数はその値を読み取り、`search_case_insensitive`か`search`を呼び出すか決定できるのです。 -まだ機能しているようです!では、`CASE_INSENSITIVE`を1にしつつ、同じクエリの`to`でプログラムを実行しましょう。 +まだ機能しているようです!では、`IGNORE_CASE`を1にしつつ、同じクエリの`to`でプログラムを実行しましょう。 + +```console +$ IGNORE_CASE=1 cargo run -- to poem.txt +``` + +PowerShellを使用しているなら、環境変数の設定とプログラムの実行を別々のコマンドとして実行する必要があるでしょう: + +```console +PS> $Env:IGNORE_CASE=1; cargo run -- to poem.txt +``` + + -PowerShellを使用しているなら、1コマンドではなく、2コマンドで環境変数をセットし、プログラムを実行する必要があるでしょう: +これを実行すると、`IGNORE_CASE`は以降のシェルセッションでも残り続けるでしょう。 +これは`Remove-Item`コマンドレットで解除することができます: -```text -$ $env:CASE_INSENSITIVE=1 -$ cargo run to poem.txt +```console +PS> Remove-Item Env:IGNORE_CASE ``` + 大文字も含む可能性のある"to"を含有する行が得られるはずです: -```text -$ CASE_INSENSITIVE=1 cargo run to poem.txt - Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs - Running `target/debug/minigrep to poem.txt` + + +```console Are you nobody, too? How dreary to be somebody! To tell your name the livelong day @@ -474,17 +373,17 @@ variables. 引数*と*環境変数で同じ設定を行うことができるプログラムもあります。そのような場合、 プログラムはどちらが優先されるか決定します。自身の別の鍛錬として、コマンドライン引数か、 環境変数で大文字小文字の区別を制御できるようにしてみてください。 -片方は大文字小文字を区別するようにセットされ、もう片方は区別しないようにセットしてプログラムが実行された時に、 +片方は大文字小文字を区別するようにセットされ、もう片方は無視するようにセットしてプログラムが実行された時に、 コマンドライン引数と環境変数のどちらの優先度が高くなるかを決めてください。 -現時点では、すべての出力を`println!`関数を使用して端末に書き込んでいます。多くの端末は、 -2種類の出力を提供します: 普通の情報用の*標準出力*(`stdout`)とエラーメッセージ用の*標準エラー出力*(`stderr`)です。 +現時点では、すべての出力を`println!`マクロを使用して端末に書き込んでいます。多くの端末には、 +2種類の出力があります: 普通の情報用の*標準出力*(`stdout`)とエラーメッセージ用の*標準エラー出力*(`stderr`)です。 この差異のおかげで、ユーザは、エラーメッセージを画面に表示しつつ、 プログラムの成功した出力をファイルにリダイレクトすることを選択できます。 -`println!`関数は、標準出力に出力する能力しかないので、標準エラーに出力するには他のものを使用しなければなりません。 +`println!`マクロは、標準出力に出力する能力しかないので、標準エラーに出力するには他のものを使用しなければなりません。 ### エラーが書き込まれる場所を確認する @@ -35,9 +35,9 @@ have to use something else to print to standard error. First, let’s observe how the content printed by `minigrep` is currently being written to standard output, including any error messages we want to write to standard error instead. We’ll do that by redirecting the standard output stream -to a file while also intentionally causing an error. We won’t redirect the -standard error stream, so any content sent to standard error will continue to -display on the screen. +to a file while intentionally causing an error. We won’t redirect the standard +error stream, so any content sent to standard error will continue to display on +the screen. --> まず、`minigrep`に出力される中身が、代わりに標準エラーに書き込みたいいかなるエラーメッセージも含め、 @@ -58,15 +58,15 @@ we’re about to see that it saves the error message output to a file instead! 目撃するところです! -この動作をデモする方法は、`>`と標準出力ストリームをリダイレクトする先のファイル名、*output.txt*でプログラムを走らせることによります。 +この動作をデモするために、`>`と、標準出力ストリームをリダイレクトする先のファイルパスである*output.txt*を付けて、プログラムを走らせましょう。 引数は何も渡さず、そうするとエラーが起きるはずです: -```text +```console $ cargo run > output.txt ``` @@ -88,7 +88,7 @@ Problem parsing arguments: not enough arguments そうです。エラーメッセージは標準出力に出力されているのです。このようなエラーメッセージは標準エラーに出力され、 @@ -121,20 +121,7 @@ instead. ファイル名: src/main.rs ```rust,ignore -fn main() { - let args: Vec = env::args().collect(); - - let config = Config::new(&args).unwrap_or_else(|err| { - eprintln!("Problem parsing arguments: {}", err); - process::exit(1); - }); - - if let Err(e) = minigrep::run(config) { - eprintln!("Application error: {}", e); - - process::exit(1); - } -} +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-24/src/main.rs:here}} ``` -`println!`を`eprintln!`に変えてから、再度同じようにプログラムを実行しましょう。 -引数なしかつ、標準出力を`>`でリダイレクトしてね: +それでは再度同じように、引数なしで、標準出力を`>`でリダイレクトしつつ、プログラムを実行しましょう: -```text +```console $ cargo run > output.txt Problem parsing arguments: not enough arguments ``` @@ -171,8 +157,8 @@ redirect standard output to a file, like so: 再度、標準出力をファイルにリダイレクトしてエラーは起こさない引数でプログラムを走らせましょう。以下のようにですね: -```text -$ cargo run to poem.txt > output.txt +```console +$ cargo run -- to poem.txt > output.txt ``` この章では、ここまでに学んできた主要な概念の一部を念押しし、Rustで入出力処理を行う方法を講義しました。 コマンドライン引数、ファイル、環境変数、そしてエラー出力に`eprintln!`マクロを使用することで、 -もう、コマンドラインアプリケーションを書く準備ができています。以前の章の概念を使用することで、 +もう、コマンドラインアプリケーションを書く準備ができています。以前の章の概念と組み合わせて、 コードはうまく体系化され、適切なデータ構造に効率的にデータを保存し、エラーをうまく扱い、 よくテストされるでしょう。 From 239347a201037f3c62841e81ae51c964309ada97 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:05 +0900 Subject: [PATCH 14/22] =?UTF-8?q?ch13=20=E9=96=A2=E6=95=B0=E5=9E=8B?= =?UTF-8?q?=E8=A8=80=E8=AA=9E=E3=81=AE=E6=A9=9F=E8=83=BD:=20=E3=82=A4?= =?UTF-8?q?=E3=83=86=E3=83=AC=E3=83=BC=E3=82=BF=E3=81=A8=E3=82=AF=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=83=A3=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92?= =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-12-23-reproduced/Cargo.toml | 3 +- .../listing-12-23-reproduced/src/lib.rs | 26 +- .../listing-12-23-reproduced/src/main.rs | 7 +- .../listing-12-24-reproduced/Cargo.toml | 3 +- .../listing-12-24-reproduced/src/lib.rs | 24 +- .../listing-12-24-reproduced/src/main.rs | 7 +- .../listing-13-01/Cargo.lock | 5 +- .../listing-13-01/Cargo.toml | 5 +- .../listing-13-01/output.txt | 6 + .../listing-13-01/src/main.rs | 60 +- .../listing-13-02/Cargo.toml | 3 +- .../listing-13-02/src/main.rs | 30 +- .../listing-13-03/Cargo.lock | 2 +- .../listing-13-03/Cargo.toml | 5 +- .../listing-13-03/output.txt | 33 + .../listing-13-03/src/main.rs | 41 +- .../listing-13-04/Cargo.toml | 5 +- .../listing-13-04/output.txt | 8 + .../listing-13-04/src/main.rs | 42 +- .../listing-13-05/Cargo.toml | 5 +- .../listing-13-05/output.txt | 6 + .../listing-13-05/src/main.rs | 38 +- .../listing-13-06/Cargo.lock | 6 - .../listing-13-06/Cargo.toml | 7 +- .../listing-13-06/src/main.rs | 37 +- .../listing-13-07/.rustfmt.toml | 2 + .../listing-13-07/Cargo.lock | 6 - .../listing-13-07/Cargo.toml | 5 +- .../listing-13-07/output.txt | 18 + .../listing-13-07/src/main.rs | 39 +- .../listing-13-08/.rustfmt.toml | 2 + .../listing-13-08/Cargo.lock | 6 - .../listing-13-08/Cargo.toml | 7 +- .../listing-13-08/output.txt | 32 +- .../listing-13-08/src/main.rs | 25 +- .../listing-13-09/.rustfmt.toml | 2 + .../listing-13-09/Cargo.toml | 5 +- .../listing-13-09/src/main.rs | 28 +- .../listing-13-10/Cargo.lock | 2 +- .../listing-13-10/Cargo.toml | 5 +- .../listing-13-10/src/main.rs | 37 +- .../listing-13-11/Cargo.lock | 2 +- .../listing-13-11/Cargo.toml | 5 +- .../listing-13-11/src/main.rs | 67 +- .../listing-13-12/Cargo.lock | 2 +- .../listing-13-12/Cargo.toml | 5 +- .../src/lib.rs | 2 - .../listing-13-12/src/main.rs | 9 - .../listing-13-13/Cargo.toml | 3 +- .../listing-13-13/src/lib.rs | 15 + .../listing-13-13/src/main.rs | 7 - .../listing-13-14/Cargo.toml | 3 +- .../listing-13-14/output.txt | 20 + .../listing-13-14/src/main.rs | 8 +- .../listing-13-15/Cargo.toml | 3 +- .../src/main.rs | 4 +- .../listing-13-16/Cargo.lock | 2 +- .../listing-13-16/Cargo.toml | 5 +- .../listing-13-16/src/lib.rs | 51 +- .../listing-13-17/Cargo.lock | 6 - .../listing-13-17/Cargo.toml | 7 - .../listing-13-17/output.txt | 13 - .../listing-13-18/Cargo.lock | 2 +- .../listing-13-18/Cargo.toml | 5 +- .../{listing-13-25 => listing-13-18}/poem.txt | 0 .../src/lib.rs | 24 +- .../listing-13-18/src/main.rs | 23 +- .../listing-13-19/Cargo.lock | 2 +- .../listing-13-19/Cargo.toml | 5 +- .../{listing-13-26 => listing-13-19}/poem.txt | 0 .../listing-13-19/src/lib.rs | 131 +- .../src/main.rs | 7 +- .../listing-13-20/Cargo.lock | 2 +- .../listing-13-20/Cargo.toml | 5 +- .../{listing-13-27 => listing-13-20}/poem.txt | 0 .../listing-13-20/src/lib.rs | 116 +- .../src/main.rs | 7 +- .../listing-13-21/Cargo.lock | 6 - .../listing-13-21/Cargo.toml | 7 - .../listing-13-21/src/lib.rs | 26 - .../listing-13-22/Cargo.lock | 2 +- .../listing-13-22/Cargo.toml | 5 +- .../{listing-13-29 => listing-13-22}/poem.txt | 0 .../listing-13-22/src/lib.rs | 117 +- .../src/main.rs | 7 +- .../listing-13-23/Cargo.lock | 6 - .../listing-13-23/Cargo.toml | 7 - .../listing-13-23/src/lib.rs | 53 - .../listing-13-25/Cargo.lock | 6 - .../listing-13-25/Cargo.toml | 7 - .../listing-13-25/src/main.rs | 23 - .../listing-13-26/Cargo.lock | 6 - .../listing-13-26/Cargo.toml | 7 - .../listing-13-26/src/lib.rs | 107 -- .../listing-13-27/Cargo.lock | 6 - .../listing-13-27/Cargo.toml | 7 - .../listing-13-27/src/lib.rs | 113 -- .../listing-13-29/Cargo.lock | 6 - .../listing-13-29/Cargo.toml | 7 - .../listing-13-29/src/lib.rs | 106 -- .../Cargo.lock | 6 - .../Cargo.toml | 7 - .../output.txt | 23 - .../src/lib.rs | 47 - .../Cargo.lock | 6 - .../Cargo.toml | 7 - .../output.txt | 16 - .../src/main.rs | 11 - .../no-listing-03-move-closures/Cargo.lock | 6 - .../no-listing-03-move-closures/Cargo.toml | 7 - .../no-listing-03-move-closures/output.txt | 22 - .../no-listing-03-move-closures/src/main.rs | 11 - src/SUMMARY.md | 4 +- src/ch13-00-functional-features.md | 18 +- src/ch13-01-closures.md | 1575 ++++++----------- src/ch13-02-iterators.md | 589 ++---- src/ch13-03-improving-our-io-project.md | 267 ++- src/ch13-04-performance.md | 18 +- 118 files changed, 1498 insertions(+), 2982 deletions(-) create mode 100644 listings/ch13-functional-features/listing-13-01/output.txt create mode 100644 listings/ch13-functional-features/listing-13-03/output.txt create mode 100644 listings/ch13-functional-features/listing-13-04/output.txt create mode 100644 listings/ch13-functional-features/listing-13-05/output.txt delete mode 100644 listings/ch13-functional-features/listing-13-06/Cargo.lock create mode 100644 listings/ch13-functional-features/listing-13-07/.rustfmt.toml delete mode 100644 listings/ch13-functional-features/listing-13-07/Cargo.lock create mode 100644 listings/ch13-functional-features/listing-13-07/output.txt create mode 100644 listings/ch13-functional-features/listing-13-08/.rustfmt.toml delete mode 100644 listings/ch13-functional-features/listing-13-08/Cargo.lock create mode 100644 listings/ch13-functional-features/listing-13-09/.rustfmt.toml rename listings/ch13-functional-features/{listing-13-15 => listing-13-12}/src/lib.rs (96%) delete mode 100644 listings/ch13-functional-features/listing-13-12/src/main.rs create mode 100644 listings/ch13-functional-features/listing-13-13/src/lib.rs delete mode 100644 listings/ch13-functional-features/listing-13-13/src/main.rs create mode 100644 listings/ch13-functional-features/listing-13-14/output.txt rename listings/ch13-functional-features/{listing-13-17 => listing-13-15}/src/main.rs (51%) delete mode 100644 listings/ch13-functional-features/listing-13-17/Cargo.lock delete mode 100644 listings/ch13-functional-features/listing-13-17/Cargo.toml delete mode 100644 listings/ch13-functional-features/listing-13-17/output.txt rename listings/ch13-functional-features/{listing-13-25 => listing-13-18}/poem.txt (100%) rename listings/ch13-functional-features/{listing-13-25 => listing-13-18}/src/lib.rs (79%) rename listings/ch13-functional-features/{listing-13-26 => listing-13-19}/poem.txt (100%) rename listings/ch13-functional-features/{listing-13-27 => listing-13-19}/src/main.rs (51%) rename listings/ch13-functional-features/{listing-13-27 => listing-13-20}/poem.txt (100%) rename listings/ch13-functional-features/{listing-13-29 => listing-13-20}/src/main.rs (51%) delete mode 100644 listings/ch13-functional-features/listing-13-21/Cargo.lock delete mode 100644 listings/ch13-functional-features/listing-13-21/Cargo.toml delete mode 100644 listings/ch13-functional-features/listing-13-21/src/lib.rs rename listings/ch13-functional-features/{listing-13-29 => listing-13-22}/poem.txt (100%) rename listings/ch13-functional-features/{listing-13-26 => listing-13-22}/src/main.rs (51%) delete mode 100644 listings/ch13-functional-features/listing-13-23/Cargo.lock delete mode 100644 listings/ch13-functional-features/listing-13-23/Cargo.toml delete mode 100644 listings/ch13-functional-features/listing-13-23/src/lib.rs delete mode 100644 listings/ch13-functional-features/listing-13-25/Cargo.lock delete mode 100644 listings/ch13-functional-features/listing-13-25/Cargo.toml delete mode 100644 listings/ch13-functional-features/listing-13-25/src/main.rs delete mode 100644 listings/ch13-functional-features/listing-13-26/Cargo.lock delete mode 100644 listings/ch13-functional-features/listing-13-26/Cargo.toml delete mode 100644 listings/ch13-functional-features/listing-13-26/src/lib.rs delete mode 100644 listings/ch13-functional-features/listing-13-27/Cargo.lock delete mode 100644 listings/ch13-functional-features/listing-13-27/Cargo.toml delete mode 100644 listings/ch13-functional-features/listing-13-27/src/lib.rs delete mode 100644 listings/ch13-functional-features/listing-13-29/Cargo.lock delete mode 100644 listings/ch13-functional-features/listing-13-29/Cargo.toml delete mode 100644 listings/ch13-functional-features/listing-13-29/src/lib.rs delete mode 100644 listings/ch13-functional-features/no-listing-01-failing-cacher-test/Cargo.lock delete mode 100644 listings/ch13-functional-features/no-listing-01-failing-cacher-test/Cargo.toml delete mode 100644 listings/ch13-functional-features/no-listing-01-failing-cacher-test/output.txt delete mode 100644 listings/ch13-functional-features/no-listing-01-failing-cacher-test/src/lib.rs delete mode 100644 listings/ch13-functional-features/no-listing-02-functions-cant-capture/Cargo.lock delete mode 100644 listings/ch13-functional-features/no-listing-02-functions-cant-capture/Cargo.toml delete mode 100644 listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt delete mode 100644 listings/ch13-functional-features/no-listing-02-functions-cant-capture/src/main.rs delete mode 100644 listings/ch13-functional-features/no-listing-03-move-closures/Cargo.lock delete mode 100644 listings/ch13-functional-features/no-listing-03-move-closures/Cargo.toml delete mode 100644 listings/ch13-functional-features/no-listing-03-move-closures/output.txt delete mode 100644 listings/ch13-functional-features/no-listing-03-move-closures/src/main.rs diff --git a/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.toml b/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.toml +++ b/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-12-23-reproduced/src/lib.rs b/listings/ch13-functional-features/listing-12-23-reproduced/src/lib.rs index 5397d7f61..e54343d24 100644 --- a/listings/ch13-functional-features/listing-12-23-reproduced/src/lib.rs +++ b/listings/ch13-functional-features/listing-12-23-reproduced/src/lib.rs @@ -4,42 +4,42 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, - pub case_sensitive: bool, + pub file_path: String, + pub ignore_case: bool, } // ANCHOR: ch13 impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); + let ignore_case = env::var("IGNORE_CASE").is_ok(); Ok(Config { query, - filename, - case_sensitive, + file_path, + ignore_case, }) } } // ANCHOR_END: ch13 pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - let results = if config.case_sensitive { - search(&config.query, &contents) - } else { + let results = if config.ignore_case { search_case_insensitive(&config.query, &contents) + } else { + search(&config.query, &contents) }; for line in results { - println!("{}", line); + println!("{line}"); } Ok(()) @@ -104,5 +104,3 @@ Trust me."; ); } } - -fn main() {} diff --git a/listings/ch13-functional-features/listing-12-23-reproduced/src/main.rs b/listings/ch13-functional-features/listing-12-23-reproduced/src/main.rs index 53af83fdb..a4f8a7411 100644 --- a/listings/ch13-functional-features/listing-12-23-reproduced/src/main.rs +++ b/listings/ch13-functional-features/listing-12-23-reproduced/src/main.rs @@ -6,14 +6,13 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - println!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - println!("Application error: {}", e); - + println!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.toml b/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.toml index 82606426f..64c2a3f52 100644 --- a/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.toml +++ b/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-12-24-reproduced/src/lib.rs b/listings/ch13-functional-features/listing-12-24-reproduced/src/lib.rs index fe1dccf4e..292b09789 100644 --- a/listings/ch13-functional-features/listing-12-24-reproduced/src/lib.rs +++ b/listings/ch13-functional-features/listing-12-24-reproduced/src/lib.rs @@ -4,40 +4,40 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, - pub case_sensitive: bool, + pub file_path: String, + pub ignore_case: bool, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); + let ignore_case = env::var("IGNORE_CASE").is_ok(); Ok(Config { query, - filename, - case_sensitive, + file_path, + ignore_case, }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - let results = if config.case_sensitive { - search(&config.query, &contents) - } else { + let results = if config.ignore_case { search_case_insensitive(&config.query, &contents) + } else { + search(&config.query, &contents) }; for line in results { - println!("{}", line); + println!("{line}"); } Ok(()) diff --git a/listings/ch13-functional-features/listing-12-24-reproduced/src/main.rs b/listings/ch13-functional-features/listing-12-24-reproduced/src/main.rs index ec27e67f9..f9d179c8c 100644 --- a/listings/ch13-functional-features/listing-12-24-reproduced/src/main.rs +++ b/listings/ch13-functional-features/listing-12-24-reproduced/src/main.rs @@ -7,8 +7,8 @@ use minigrep::Config; fn main() { let args: Vec = env::args().collect(); - let config = Config::new(&args).unwrap_or_else(|err| { - eprintln!("Problem parsing arguments: {}", err); + let config = Config::build(&args).unwrap_or_else(|err| { + eprintln!("Problem parsing arguments: {err}"); process::exit(1); }); @@ -16,8 +16,7 @@ fn main() { // ANCHOR_END: ch13 if let Err(e) = minigrep::run(config) { - eprintln!("Application error: {}", e); - + eprintln!("Application error: {e}"); process::exit(1); } // ANCHOR: ch13 diff --git a/listings/ch13-functional-features/listing-13-01/Cargo.lock b/listings/ch13-functional-features/listing-13-01/Cargo.lock index 75ff09e51..6f974d1ba 100644 --- a/listings/ch13-functional-features/listing-13-01/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-01/Cargo.lock @@ -1,6 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "workout-app" +name = "shirt-company" version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-01/Cargo.toml b/listings/ch13-functional-features/listing-13-01/Cargo.toml index 8e64540e7..1eb392dfa 100644 --- a/listings/ch13-functional-features/listing-13-01/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-01/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "workout-app" +name = "shirt-company" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-01/output.txt b/listings/ch13-functional-features/listing-13-01/output.txt new file mode 100644 index 000000000..b64a4d8dc --- /dev/null +++ b/listings/ch13-functional-features/listing-13-01/output.txt @@ -0,0 +1,6 @@ +$ cargo run + Compiling shirt-company v0.1.0 (file:///projects/shirt-company) + Finished dev [unoptimized + debuginfo] target(s) in 0.27s + Running `target/debug/shirt-company` +The user with preference Some(Red) gets Red +The user with preference None gets Blue diff --git a/listings/ch13-functional-features/listing-13-01/src/main.rs b/listings/ch13-functional-features/listing-13-01/src/main.rs index 97eace01d..503acca51 100644 --- a/listings/ch13-functional-features/listing-13-01/src/main.rs +++ b/listings/ch13-functional-features/listing-13-01/src/main.rs @@ -1,12 +1,54 @@ -// ANCHOR: here -use std::thread; -use std::time::Duration; +#[derive(Debug, PartialEq, Copy, Clone)] +enum ShirtColor { + Red, + Blue, +} + +struct Inventory { + shirts: Vec, +} + +impl Inventory { + fn giveaway(&self, user_preference: Option) -> ShirtColor { + user_preference.unwrap_or_else(|| self.most_stocked()) + } -fn simulated_expensive_calculation(intensity: u32) -> u32 { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - intensity + fn most_stocked(&self) -> ShirtColor { + let mut num_red = 0; + let mut num_blue = 0; + + for color in &self.shirts { + match color { + ShirtColor::Red => num_red += 1, + ShirtColor::Blue => num_blue += 1, + } + } + if num_red > num_blue { + ShirtColor::Red + } else { + ShirtColor::Blue + } + } } -// ANCHOR_END: here -fn main() {} +fn main() { + let store = Inventory { + shirts: vec![ShirtColor::Blue, ShirtColor::Red, ShirtColor::Blue], + }; + + let user_pref1 = Some(ShirtColor::Red); + let giveaway1 = store.giveaway(user_pref1); + println!( + // "好み{:?}を持つユーザは{:?}を得ます" + "The user with preference {:?} gets {:?}", + user_pref1, giveaway1 + ); + + let user_pref2 = None; + let giveaway2 = store.giveaway(user_pref2); + println!( + // "好み{:?}を持つユーザは{:?}を得ます" + "The user with preference {:?} gets {:?}", + user_pref2, giveaway2 + ); +} diff --git a/listings/ch13-functional-features/listing-13-02/Cargo.toml b/listings/ch13-functional-features/listing-13-02/Cargo.toml index 8e64540e7..f09a737d4 100644 --- a/listings/ch13-functional-features/listing-13-02/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "workout-app" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-02/src/main.rs b/listings/ch13-functional-features/listing-13-02/src/main.rs index 96d06c77d..b3f4cc2c2 100644 --- a/listings/ch13-functional-features/listing-13-02/src/main.rs +++ b/listings/ch13-functional-features/listing-13-02/src/main.rs @@ -1,19 +1,33 @@ use std::thread; use std::time::Duration; -fn simulated_expensive_calculation(intensity: u32) -> u32 { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - intensity -} +fn generate_workout(intensity: u32, random_number: u32) { + // ANCHOR: here + let expensive_closure = |num: u32| -> u32 { + println!("calculating slowly..."); + thread::sleep(Duration::from_secs(2)); + num + }; + // ANCHOR_END: here -fn generate_workout(intensity: u32, random_number: u32) {} + if intensity < 25 { + println!("Today, do {} pushups!", expensive_closure(intensity)); + println!("Next, do {} situps!", expensive_closure(intensity)); + } else { + if random_number == 3 { + println!("Take a break today! Remember to stay hydrated!"); + } else { + println!( + "Today, run for {} minutes!", + expensive_closure(intensity) + ); + } + } +} -// ANCHOR: here fn main() { let simulated_user_specified_value = 10; let simulated_random_number = 7; generate_workout(simulated_user_specified_value, simulated_random_number); } -// ANCHOR_END: here diff --git a/listings/ch13-functional-features/listing-13-03/Cargo.lock b/listings/ch13-functional-features/listing-13-03/Cargo.lock index 75ff09e51..c190d3a41 100644 --- a/listings/ch13-functional-features/listing-13-03/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-03/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "workout-app" +name = "closure-example" version = "0.1.0" diff --git a/listings/ch13-functional-features/listing-13-03/Cargo.toml b/listings/ch13-functional-features/listing-13-03/Cargo.toml index 8e64540e7..914c4cfaa 100644 --- a/listings/ch13-functional-features/listing-13-03/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-03/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "workout-app" +name = "closure-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-03/output.txt b/listings/ch13-functional-features/listing-13-03/output.txt new file mode 100644 index 000000000..5b85da43c --- /dev/null +++ b/listings/ch13-functional-features/listing-13-03/output.txt @@ -0,0 +1,33 @@ +$ cargo run + Compiling closure-example v0.1.0 (file:///projects/closure-example) +error[E0308]: mismatched types +(エラー: 型が合いません) + --> src/main.rs:5:29 + | +5 | let n = example_closure(5); + | --------------- ^- help: try using a conversion method: `.to_string()` + | | | (ヘルプ: 変換メソッド`.to_string()`を使用してみてください) + | | | + | | expected `String`, found integer + | | (`String`を予期していましたが、整数が見つかりました) + | arguments to this function are incorrect + | (この関数への引数が正しくありません) + | +note: expected because the closure was earlier called with an argument of type `String` +(注釈: クロージャは以前に型`String`を持つ引数とともに呼ばれているため、これが予期されています) + --> src/main.rs:4:29 + | +4 | let s = example_closure(String::from("hello")); + | --------------- ^^^^^^^^^^^^^^^^^^^^^ expected because this argument is of type `String` + | | (この引数が型`String`を持つことから予期されています) + | | + | in this closure call + | (このクロージャ呼び出しで) +note: closure parameter defined here + --> src/main.rs:2:28 + | +2 | let example_closure = |x| x; + | ^ + +For more information about this error, try `rustc --explain E0308`. +error: could not compile `closure-example` (bin "closure-example") due to 1 previous error diff --git a/listings/ch13-functional-features/listing-13-03/src/main.rs b/listings/ch13-functional-features/listing-13-03/src/main.rs index d43c9b211..ebb2489bf 100644 --- a/listings/ch13-functional-features/listing-13-03/src/main.rs +++ b/listings/ch13-functional-features/listing-13-03/src/main.rs @@ -1,39 +1,8 @@ -use std::thread; -use std::time::Duration; - -fn simulated_expensive_calculation(intensity: u32) -> u32 { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - intensity -} - -// ANCHOR: here -fn generate_workout(intensity: u32, random_number: u32) { - if intensity < 25 { - println!( - "Today, do {} pushups!", - simulated_expensive_calculation(intensity) - ); - println!( - "Next, do {} situps!", - simulated_expensive_calculation(intensity) - ); - } else { - if random_number == 3 { - println!("Take a break today! Remember to stay hydrated!"); - } else { - println!( - "Today, run for {} minutes!", - simulated_expensive_calculation(intensity) - ); - } - } -} -// ANCHOR_END: here - fn main() { - let simulated_user_specified_value = 10; - let simulated_random_number = 7; + // ANCHOR: here + let example_closure = |x| x; - generate_workout(simulated_user_specified_value, simulated_random_number); + let s = example_closure(String::from("hello")); + let n = example_closure(5); + // ANCHOR_END: here } diff --git a/listings/ch13-functional-features/listing-13-04/Cargo.toml b/listings/ch13-functional-features/listing-13-04/Cargo.toml index 8e64540e7..914c4cfaa 100644 --- a/listings/ch13-functional-features/listing-13-04/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-04/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "workout-app" +name = "closure-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-04/output.txt b/listings/ch13-functional-features/listing-13-04/output.txt new file mode 100644 index 000000000..64d763b51 --- /dev/null +++ b/listings/ch13-functional-features/listing-13-04/output.txt @@ -0,0 +1,8 @@ +$ cargo run + Compiling closure-example v0.1.0 (file:///projects/closure-example) + Finished dev [unoptimized + debuginfo] target(s) in 0.43s + Running `target/debug/closure-example` +Before defining closure: [1, 2, 3] +Before calling closure: [1, 2, 3] +From closure: [1, 2, 3] +After calling closure: [1, 2, 3] diff --git a/listings/ch13-functional-features/listing-13-04/src/main.rs b/listings/ch13-functional-features/listing-13-04/src/main.rs index fabe0fb01..55d214791 100644 --- a/listings/ch13-functional-features/listing-13-04/src/main.rs +++ b/listings/ch13-functional-features/listing-13-04/src/main.rs @@ -1,32 +1,14 @@ -use std::thread; -use std::time::Duration; - -fn simulated_expensive_calculation(intensity: u32) -> u32 { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - intensity -} - -// ANCHOR: here -fn generate_workout(intensity: u32, random_number: u32) { - let expensive_result = simulated_expensive_calculation(intensity); - - if intensity < 25 { - println!("Today, do {} pushups!", expensive_result); - println!("Next, do {} situps!", expensive_result); - } else { - if random_number == 3 { - println!("Take a break today! Remember to stay hydrated!"); - } else { - println!("Today, run for {} minutes!", expensive_result); - } - } -} -// ANCHOR_END: here - fn main() { - let simulated_user_specified_value = 10; - let simulated_random_number = 7; - - generate_workout(simulated_user_specified_value, simulated_random_number); + let list = vec![1, 2, 3]; + // "クロージャの定義前: {:?}" + println!("Before defining closure: {:?}", list); + + // "クロージャから: {:?}" + let only_borrows = || println!("From closure: {:?}", list); + + // "クロージャの呼び出し前: {:?}" + println!("Before calling closure: {:?}", list); + only_borrows(); + // "クロージャの呼び出し後: {:?}" + println!("After calling closure: {:?}", list); } diff --git a/listings/ch13-functional-features/listing-13-05/Cargo.toml b/listings/ch13-functional-features/listing-13-05/Cargo.toml index 8e64540e7..914c4cfaa 100644 --- a/listings/ch13-functional-features/listing-13-05/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-05/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "workout-app" +name = "closure-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-05/output.txt b/listings/ch13-functional-features/listing-13-05/output.txt new file mode 100644 index 000000000..ce0ad5e37 --- /dev/null +++ b/listings/ch13-functional-features/listing-13-05/output.txt @@ -0,0 +1,6 @@ +$ cargo run + Compiling closure-example v0.1.0 (file:///projects/closure-example) + Finished dev [unoptimized + debuginfo] target(s) in 0.43s + Running `target/debug/closure-example` +Before defining closure: [1, 2, 3] +After calling closure: [1, 2, 3, 7] diff --git a/listings/ch13-functional-features/listing-13-05/src/main.rs b/listings/ch13-functional-features/listing-13-05/src/main.rs index 6984a27a0..bd820c1fc 100644 --- a/listings/ch13-functional-features/listing-13-05/src/main.rs +++ b/listings/ch13-functional-features/listing-13-05/src/main.rs @@ -1,33 +1,11 @@ -use std::thread; -use std::time::Duration; - -fn generate_workout(intensity: u32, random_number: u32) { - // ANCHOR: here - let expensive_closure = |num| { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - num - }; - // ANCHOR_END: here - - if intensity < 25 { - println!("Today, do {} pushups!", expensive_closure(intensity)); - println!("Next, do {} situps!", expensive_closure(intensity)); - } else { - if random_number == 3 { - println!("Take a break today! Remember to stay hydrated!"); - } else { - println!( - "Today, run for {} minutes!", - expensive_closure(intensity) - ); - } - } -} - fn main() { - let simulated_user_specified_value = 10; - let simulated_random_number = 7; + let mut list = vec![1, 2, 3]; + // "クロージャの定義前: {:?}" + println!("Before defining closure: {:?}", list); + + let mut borrows_mutably = || list.push(7); - generate_workout(simulated_user_specified_value, simulated_random_number); + borrows_mutably(); + // "クロージャの呼び出し後: {:?}" + println!("After calling closure: {:?}", list); } diff --git a/listings/ch13-functional-features/listing-13-06/Cargo.lock b/listings/ch13-functional-features/listing-13-06/Cargo.lock deleted file mode 100644 index 75ff09e51..000000000 --- a/listings/ch13-functional-features/listing-13-06/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "workout-app" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-06/Cargo.toml b/listings/ch13-functional-features/listing-13-06/Cargo.toml index 8e64540e7..8085ade0f 100644 --- a/listings/ch13-functional-features/listing-13-06/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-06/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "workout-app" +name = "closure-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/listings/ch13-functional-features/listing-13-06/src/main.rs b/listings/ch13-functional-features/listing-13-06/src/main.rs index 8850e58a7..b83612da5 100644 --- a/listings/ch13-functional-features/listing-13-06/src/main.rs +++ b/listings/ch13-functional-features/listing-13-06/src/main.rs @@ -1,33 +1,12 @@ use std::thread; -use std::time::Duration; - -// ANCHOR: here -fn generate_workout(intensity: u32, random_number: u32) { - let expensive_closure = |num| { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - num - }; - - if intensity < 25 { - println!("Today, do {} pushups!", expensive_closure(intensity)); - println!("Next, do {} situps!", expensive_closure(intensity)); - } else { - if random_number == 3 { - println!("Take a break today! Remember to stay hydrated!"); - } else { - println!( - "Today, run for {} minutes!", - expensive_closure(intensity) - ); - } - } -} -// ANCHOR_END: here fn main() { - let simulated_user_specified_value = 10; - let simulated_random_number = 7; - - generate_workout(simulated_user_specified_value, simulated_random_number); + let list = vec![1, 2, 3]; + // "クロージャの定義前: {:?}" + println!("Before defining closure: {:?}", list); + + // "スレッドから: {:?}" + thread::spawn(move || println!("From thread: {:?}", list)) + .join() + .unwrap(); } diff --git a/listings/ch13-functional-features/listing-13-07/.rustfmt.toml b/listings/ch13-functional-features/listing-13-07/.rustfmt.toml new file mode 100644 index 000000000..ee10c634b --- /dev/null +++ b/listings/ch13-functional-features/listing-13-07/.rustfmt.toml @@ -0,0 +1,2 @@ +struct_lit_width = 50 + diff --git a/listings/ch13-functional-features/listing-13-07/Cargo.lock b/listings/ch13-functional-features/listing-13-07/Cargo.lock deleted file mode 100644 index 75ff09e51..000000000 --- a/listings/ch13-functional-features/listing-13-07/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "workout-app" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-07/Cargo.toml b/listings/ch13-functional-features/listing-13-07/Cargo.toml index 8e64540e7..4a279a450 100644 --- a/listings/ch13-functional-features/listing-13-07/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-07/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "workout-app" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-07/output.txt b/listings/ch13-functional-features/listing-13-07/output.txt new file mode 100644 index 000000000..f18fce46e --- /dev/null +++ b/listings/ch13-functional-features/listing-13-07/output.txt @@ -0,0 +1,18 @@ +$ cargo run + Compiling rectangles v0.1.0 (file:///projects/rectangles) + Finished dev [unoptimized + debuginfo] target(s) in 0.41s + Running `target/debug/rectangles` +[ + Rectangle { + width: 3, + height: 5, + }, + Rectangle { + width: 7, + height: 12, + }, + Rectangle { + width: 10, + height: 1, + }, +] diff --git a/listings/ch13-functional-features/listing-13-07/src/main.rs b/listings/ch13-functional-features/listing-13-07/src/main.rs index b3f4cc2c2..73a25e5f9 100644 --- a/listings/ch13-functional-features/listing-13-07/src/main.rs +++ b/listings/ch13-functional-features/listing-13-07/src/main.rs @@ -1,33 +1,16 @@ -use std::thread; -use std::time::Duration; - -fn generate_workout(intensity: u32, random_number: u32) { - // ANCHOR: here - let expensive_closure = |num: u32| -> u32 { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - num - }; - // ANCHOR_END: here - - if intensity < 25 { - println!("Today, do {} pushups!", expensive_closure(intensity)); - println!("Next, do {} situps!", expensive_closure(intensity)); - } else { - if random_number == 3 { - println!("Take a break today! Remember to stay hydrated!"); - } else { - println!( - "Today, run for {} minutes!", - expensive_closure(intensity) - ); - } - } +#[derive(Debug)] +struct Rectangle { + width: u32, + height: u32, } fn main() { - let simulated_user_specified_value = 10; - let simulated_random_number = 7; + let mut list = [ + Rectangle { width: 10, height: 1 }, + Rectangle { width: 3, height: 5 }, + Rectangle { width: 7, height: 12 }, + ]; - generate_workout(simulated_user_specified_value, simulated_random_number); + list.sort_by_key(|r| r.width); + println!("{:#?}", list); } diff --git a/listings/ch13-functional-features/listing-13-08/.rustfmt.toml b/listings/ch13-functional-features/listing-13-08/.rustfmt.toml new file mode 100644 index 000000000..ee10c634b --- /dev/null +++ b/listings/ch13-functional-features/listing-13-08/.rustfmt.toml @@ -0,0 +1,2 @@ +struct_lit_width = 50 + diff --git a/listings/ch13-functional-features/listing-13-08/Cargo.lock b/listings/ch13-functional-features/listing-13-08/Cargo.lock deleted file mode 100644 index c190d3a41..000000000 --- a/listings/ch13-functional-features/listing-13-08/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "closure-example" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-08/Cargo.toml b/listings/ch13-functional-features/listing-13-08/Cargo.toml index 54b904e41..703c9d977 100644 --- a/listings/ch13-functional-features/listing-13-08/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-08/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "closure-example" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/listings/ch13-functional-features/listing-13-08/output.txt b/listings/ch13-functional-features/listing-13-08/output.txt index d859957f2..187daec33 100644 --- a/listings/ch13-functional-features/listing-13-08/output.txt +++ b/listings/ch13-functional-features/listing-13-08/output.txt @@ -1,17 +1,19 @@ $ cargo run - Compiling closure-example v0.1.0 (file:///projects/closure-example) -error[E0308]: mismatched types - --> src/main.rs:5:29 - | -5 | let n = example_closure(5); - | ^ - | | - | expected struct `std::string::String`, found integer - | help: try using a conversion method: `5.to_string()` + Compiling rectangles v0.1.0 (file:///projects/rectangles) +error[E0507]: cannot move out of `value`, a captured variable in an `FnMut` closure +(エラー: `FnMut`クロージャ内にキャプチャされた変数`value`からムーブすることはできません) + --> src/main.rs:18:30 + | +15 | let value = String::from("by key called"); + | ----- captured outer variable + | (キャプチャされる外側の変数) +16 | +17 | list.sort_by_key(|r| { + | --- captured by this `FnMut` closure + | (この`FnMut`クロージャによってキャプチャされています) +18 | sort_operations.push(value); + | ^^^^^ move occurs because `value` has type `String`, which does not implement the `Copy` trait + | (`value`は型`String`を持ち、`Copy`トレイトを実装しないので、ムーブが発生します) -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. -error: could not compile `closure-example`. - -To learn more, run the command again with --verbose. +For more information about this error, try `rustc --explain E0507`. +error: could not compile `rectangles` (bin "rectangles") due to 1 previous error diff --git a/listings/ch13-functional-features/listing-13-08/src/main.rs b/listings/ch13-functional-features/listing-13-08/src/main.rs index ebb2489bf..afeb3e8af 100644 --- a/listings/ch13-functional-features/listing-13-08/src/main.rs +++ b/listings/ch13-functional-features/listing-13-08/src/main.rs @@ -1,8 +1,23 @@ +#[derive(Debug)] +struct Rectangle { + width: u32, + height: u32, +} + fn main() { - // ANCHOR: here - let example_closure = |x| x; + let mut list = [ + Rectangle { width: 10, height: 1 }, + Rectangle { width: 3, height: 5 }, + Rectangle { width: 7, height: 12 }, + ]; + + let mut sort_operations = vec![]; + // "by keyが呼ばれました" + let value = String::from("by key called"); - let s = example_closure(String::from("hello")); - let n = example_closure(5); - // ANCHOR_END: here + list.sort_by_key(|r| { + sort_operations.push(value); + r.width + }); + println!("{:#?}", list); } diff --git a/listings/ch13-functional-features/listing-13-09/.rustfmt.toml b/listings/ch13-functional-features/listing-13-09/.rustfmt.toml new file mode 100644 index 000000000..ee10c634b --- /dev/null +++ b/listings/ch13-functional-features/listing-13-09/.rustfmt.toml @@ -0,0 +1,2 @@ +struct_lit_width = 50 + diff --git a/listings/ch13-functional-features/listing-13-09/Cargo.toml b/listings/ch13-functional-features/listing-13-09/Cargo.toml index 54ab6f217..4a279a450 100644 --- a/listings/ch13-functional-features/listing-13-09/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-09/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "cacher" +name = "rectangles" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-09/src/main.rs b/listings/ch13-functional-features/listing-13-09/src/main.rs index 3fd4ed067..21b856e12 100644 --- a/listings/ch13-functional-features/listing-13-09/src/main.rs +++ b/listings/ch13-functional-features/listing-13-09/src/main.rs @@ -1,11 +1,21 @@ -// ANCHOR: here -struct Cacher -where - T: Fn(u32) -> u32, -{ - calculation: T, - value: Option, +#[derive(Debug)] +struct Rectangle { + width: u32, + height: u32, } -// ANCHOR_END: here -fn main() {} +fn main() { + let mut list = [ + Rectangle { width: 10, height: 1 }, + Rectangle { width: 3, height: 5 }, + Rectangle { width: 7, height: 12 }, + ]; + + let mut num_sort_operations = 0; + list.sort_by_key(|r| { + num_sort_operations += 1; + r.width + }); + // "{:#?}、{num_sort_operations}回の操作でソートされました" + println!("{:#?}, sorted in {num_sort_operations} operations", list); +} diff --git a/listings/ch13-functional-features/listing-13-10/Cargo.lock b/listings/ch13-functional-features/listing-13-10/Cargo.lock index e090432bc..e91eaa8d4 100644 --- a/listings/ch13-functional-features/listing-13-10/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-10/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "cacher" +name = "iterators" version = "0.1.0" diff --git a/listings/ch13-functional-features/listing-13-10/Cargo.toml b/listings/ch13-functional-features/listing-13-10/Cargo.toml index 54ab6f217..2652a8a1a 100644 --- a/listings/ch13-functional-features/listing-13-10/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-10/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "cacher" +name = "iterators" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-10/src/main.rs b/listings/ch13-functional-features/listing-13-10/src/main.rs index 4d1034db9..55a0dd37e 100644 --- a/listings/ch13-functional-features/listing-13-10/src/main.rs +++ b/listings/ch13-functional-features/listing-13-10/src/main.rs @@ -1,34 +1,7 @@ -struct Cacher -where - T: Fn(u32) -> u32, -{ - calculation: T, - value: Option, -} - -// ANCHOR: here -impl Cacher -where - T: Fn(u32) -> u32, -{ - fn new(calculation: T) -> Cacher { - Cacher { - calculation, - value: None, - } - } +fn main() { + // ANCHOR: here + let v1 = vec![1, 2, 3]; - fn value(&mut self, arg: u32) -> u32 { - match self.value { - Some(v) => v, - None => { - let v = (self.calculation)(arg); - self.value = Some(v); - v - } - } - } + let v1_iter = v1.iter(); + // ANCHOR_END: here } -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch13-functional-features/listing-13-11/Cargo.lock b/listings/ch13-functional-features/listing-13-11/Cargo.lock index 75ff09e51..e91eaa8d4 100644 --- a/listings/ch13-functional-features/listing-13-11/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-11/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "workout-app" +name = "iterators" version = "0.1.0" diff --git a/listings/ch13-functional-features/listing-13-11/Cargo.toml b/listings/ch13-functional-features/listing-13-11/Cargo.toml index 8e64540e7..2652a8a1a 100644 --- a/listings/ch13-functional-features/listing-13-11/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-11/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "workout-app" +name = "iterators" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-11/src/main.rs b/listings/ch13-functional-features/listing-13-11/src/main.rs index 9f378b793..712aff408 100644 --- a/listings/ch13-functional-features/listing-13-11/src/main.rs +++ b/listings/ch13-functional-features/listing-13-11/src/main.rs @@ -1,64 +1,11 @@ -use std::thread; -use std::time::Duration; - -struct Cacher -where - T: Fn(u32) -> u32, -{ - calculation: T, - value: Option, -} - -impl Cacher -where - T: Fn(u32) -> u32, -{ - fn new(calculation: T) -> Cacher { - Cacher { - calculation, - value: None, - } - } - - fn value(&mut self, arg: u32) -> u32 { - match self.value { - Some(v) => v, - None => { - let v = (self.calculation)(arg); - self.value = Some(v); - v - } - } - } -} +fn main() { + // ANCHOR: here + let v1 = vec![1, 2, 3]; -// ANCHOR: here -fn generate_workout(intensity: u32, random_number: u32) { - let mut expensive_result = Cacher::new(|num| { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - num - }); + let v1_iter = v1.iter(); - if intensity < 25 { - println!("Today, do {} pushups!", expensive_result.value(intensity)); - println!("Next, do {} situps!", expensive_result.value(intensity)); - } else { - if random_number == 3 { - println!("Take a break today! Remember to stay hydrated!"); - } else { - println!( - "Today, run for {} minutes!", - expensive_result.value(intensity) - ); - } + for val in v1_iter { + println!("Got: {}", val); } -} -// ANCHOR_END: here - -fn main() { - let simulated_user_specified_value = 10; - let simulated_random_number = 7; - - generate_workout(simulated_user_specified_value, simulated_random_number); + // ANCHOR_END: here } diff --git a/listings/ch13-functional-features/listing-13-12/Cargo.lock b/listings/ch13-functional-features/listing-13-12/Cargo.lock index a96532add..e91eaa8d4 100644 --- a/listings/ch13-functional-features/listing-13-12/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-12/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "equal-to-x" +name = "iterators" version = "0.1.0" diff --git a/listings/ch13-functional-features/listing-13-12/Cargo.toml b/listings/ch13-functional-features/listing-13-12/Cargo.toml index 4fd5d8523..2652a8a1a 100644 --- a/listings/ch13-functional-features/listing-13-12/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-12/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "equal-to-x" +name = "iterators" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-15/src/lib.rs b/listings/ch13-functional-features/listing-13-12/src/lib.rs similarity index 96% rename from listings/ch13-functional-features/listing-13-15/src/lib.rs rename to listings/ch13-functional-features/listing-13-12/src/lib.rs index afea80d22..758284044 100644 --- a/listings/ch13-functional-features/listing-13-15/src/lib.rs +++ b/listings/ch13-functional-features/listing-13-12/src/lib.rs @@ -14,5 +14,3 @@ mod tests { } // ANCHOR_END: here } - -fn main() {} diff --git a/listings/ch13-functional-features/listing-13-12/src/main.rs b/listings/ch13-functional-features/listing-13-12/src/main.rs deleted file mode 100644 index 7352b80b2..000000000 --- a/listings/ch13-functional-features/listing-13-12/src/main.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - let x = 4; - - let equal_to_x = |z| z == x; - - let y = 4; - - assert!(equal_to_x(y)); -} diff --git a/listings/ch13-functional-features/listing-13-13/Cargo.toml b/listings/ch13-functional-features/listing-13-13/Cargo.toml index 015f9512f..2652a8a1a 100644 --- a/listings/ch13-functional-features/listing-13-13/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "iterators" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-13/src/lib.rs b/listings/ch13-functional-features/listing-13-13/src/lib.rs new file mode 100644 index 000000000..d1cb54d0a --- /dev/null +++ b/listings/ch13-functional-features/listing-13-13/src/lib.rs @@ -0,0 +1,15 @@ +#[cfg(test)] +mod tests { + // ANCHOR: here + #[test] + fn iterator_sum() { + let v1 = vec![1, 2, 3]; + + let v1_iter = v1.iter(); + + let total: i32 = v1_iter.sum(); + + assert_eq!(total, 6); + } + // ANCHOR_END: here +} diff --git a/listings/ch13-functional-features/listing-13-13/src/main.rs b/listings/ch13-functional-features/listing-13-13/src/main.rs deleted file mode 100644 index 55a0dd37e..000000000 --- a/listings/ch13-functional-features/listing-13-13/src/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - // ANCHOR: here - let v1 = vec![1, 2, 3]; - - let v1_iter = v1.iter(); - // ANCHOR_END: here -} diff --git a/listings/ch13-functional-features/listing-13-14/Cargo.toml b/listings/ch13-functional-features/listing-13-14/Cargo.toml index 015f9512f..2652a8a1a 100644 --- a/listings/ch13-functional-features/listing-13-14/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-14/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "iterators" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-14/output.txt b/listings/ch13-functional-features/listing-13-14/output.txt new file mode 100644 index 000000000..003182224 --- /dev/null +++ b/listings/ch13-functional-features/listing-13-14/output.txt @@ -0,0 +1,20 @@ +$ cargo run + Compiling iterators v0.1.0 (file:///projects/iterators) +warning: unused `Map` that must be used +(警告: 使用されねばならない`Map`が未使用です) + --> src/main.rs:4:5 + | +4 | v1.iter().map(|x| x + 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: iterators are lazy and do nothing unless consumed + (メモ: イテレータは怠惰で、消費されるまで何もしません) + = note: `#[warn(unused_must_use)]` on by default +help: use `let _ = ...` to ignore the resulting value + | +4 | let _ = v1.iter().map(|x| x + 1); + | +++++++ + +warning: `iterators` (bin "iterators") generated 1 warning + Finished dev [unoptimized + debuginfo] target(s) in 0.47s + Running `target/debug/iterators` diff --git a/listings/ch13-functional-features/listing-13-14/src/main.rs b/listings/ch13-functional-features/listing-13-14/src/main.rs index 712aff408..62a68be9b 100644 --- a/listings/ch13-functional-features/listing-13-14/src/main.rs +++ b/listings/ch13-functional-features/listing-13-14/src/main.rs @@ -1,11 +1,7 @@ fn main() { // ANCHOR: here - let v1 = vec![1, 2, 3]; + let v1: Vec = vec![1, 2, 3]; - let v1_iter = v1.iter(); - - for val in v1_iter { - println!("Got: {}", val); - } + v1.iter().map(|x| x + 1); // ANCHOR_END: here } diff --git a/listings/ch13-functional-features/listing-13-15/Cargo.toml b/listings/ch13-functional-features/listing-13-15/Cargo.toml index 015f9512f..2652a8a1a 100644 --- a/listings/ch13-functional-features/listing-13-15/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "iterators" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-17/src/main.rs b/listings/ch13-functional-features/listing-13-15/src/main.rs similarity index 51% rename from listings/ch13-functional-features/listing-13-17/src/main.rs rename to listings/ch13-functional-features/listing-13-15/src/main.rs index 62a68be9b..db9025d6f 100644 --- a/listings/ch13-functional-features/listing-13-17/src/main.rs +++ b/listings/ch13-functional-features/listing-13-15/src/main.rs @@ -2,6 +2,8 @@ fn main() { // ANCHOR: here let v1: Vec = vec![1, 2, 3]; - v1.iter().map(|x| x + 1); + let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); + + assert_eq!(v2, vec![2, 3, 4]); // ANCHOR_END: here } diff --git a/listings/ch13-functional-features/listing-13-16/Cargo.lock b/listings/ch13-functional-features/listing-13-16/Cargo.lock index e91eaa8d4..0b15e2157 100644 --- a/listings/ch13-functional-features/listing-13-16/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-16/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "iterators" +name = "shoe_size" version = "0.1.0" diff --git a/listings/ch13-functional-features/listing-13-16/Cargo.toml b/listings/ch13-functional-features/listing-13-16/Cargo.toml index 015f9512f..cc803776b 100644 --- a/listings/ch13-functional-features/listing-13-16/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-16/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "iterators" +name = "shoe_size" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-16/src/lib.rs b/listings/ch13-functional-features/listing-13-16/src/lib.rs index 198b3c834..281c3c9e4 100644 --- a/listings/ch13-functional-features/listing-13-16/src/lib.rs +++ b/listings/ch13-functional-features/listing-13-16/src/lib.rs @@ -1,17 +1,48 @@ +#[derive(PartialEq, Debug)] +struct Shoe { + size: u32, + style: String, +} + +fn shoes_in_size(shoes: Vec, shoe_size: u32) -> Vec { + shoes.into_iter().filter(|s| s.size == shoe_size).collect() +} + #[cfg(test)] mod tests { - // ANCHOR: here - #[test] - fn iterator_sum() { - let v1 = vec![1, 2, 3]; + use super::*; - let v1_iter = v1.iter(); + #[test] + fn filters_by_size() { + let shoes = vec![ + Shoe { + size: 10, + style: String::from("sneaker"), + }, + Shoe { + size: 13, + style: String::from("sandal"), + }, + Shoe { + size: 10, + style: String::from("boot"), + }, + ]; - let total: i32 = v1_iter.sum(); + let in_my_size = shoes_in_size(shoes, 10); - assert_eq!(total, 6); + assert_eq!( + in_my_size, + vec![ + Shoe { + size: 10, + style: String::from("sneaker") + }, + Shoe { + size: 10, + style: String::from("boot") + }, + ] + ); } - // ANCHOR_END: here } - -fn main() {} diff --git a/listings/ch13-functional-features/listing-13-17/Cargo.lock b/listings/ch13-functional-features/listing-13-17/Cargo.lock deleted file mode 100644 index e91eaa8d4..000000000 --- a/listings/ch13-functional-features/listing-13-17/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "iterators" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-17/Cargo.toml b/listings/ch13-functional-features/listing-13-17/Cargo.toml deleted file mode 100644 index 015f9512f..000000000 --- a/listings/ch13-functional-features/listing-13-17/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "iterators" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/listing-13-17/output.txt b/listings/ch13-functional-features/listing-13-17/output.txt deleted file mode 100644 index ff02254be..000000000 --- a/listings/ch13-functional-features/listing-13-17/output.txt +++ /dev/null @@ -1,13 +0,0 @@ -$ cargo run - Compiling iterators v0.1.0 (file:///projects/iterators) -warning: unused `std::iter::Map` that must be used - --> src/main.rs:4:5 - | -4 | v1.iter().map(|x| x + 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unused_must_use)]` on by default - = note: iterators are lazy and do nothing unless consumed - - Finished dev [unoptimized + debuginfo] target(s) in 0.47s - Running `target/debug/iterators` diff --git a/listings/ch13-functional-features/listing-13-18/Cargo.lock b/listings/ch13-functional-features/listing-13-18/Cargo.lock index e91eaa8d4..88bf82d16 100644 --- a/listings/ch13-functional-features/listing-13-18/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-18/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "iterators" +name = "minigrep" version = "0.1.0" diff --git a/listings/ch13-functional-features/listing-13-18/Cargo.toml b/listings/ch13-functional-features/listing-13-18/Cargo.toml index 015f9512f..64c2a3f52 100644 --- a/listings/ch13-functional-features/listing-13-18/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-18/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "iterators" +name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-25/poem.txt b/listings/ch13-functional-features/listing-13-18/poem.txt similarity index 100% rename from listings/ch13-functional-features/listing-13-25/poem.txt rename to listings/ch13-functional-features/listing-13-18/poem.txt diff --git a/listings/ch13-functional-features/listing-13-25/src/lib.rs b/listings/ch13-functional-features/listing-13-18/src/lib.rs similarity index 79% rename from listings/ch13-functional-features/listing-13-25/src/lib.rs rename to listings/ch13-functional-features/listing-13-18/src/lib.rs index fe1dccf4e..292b09789 100644 --- a/listings/ch13-functional-features/listing-13-25/src/lib.rs +++ b/listings/ch13-functional-features/listing-13-18/src/lib.rs @@ -4,40 +4,40 @@ use std::fs; pub struct Config { pub query: String, - pub filename: String, - pub case_sensitive: bool, + pub file_path: String, + pub ignore_case: bool, } impl Config { - pub fn new(args: &[String]) -> Result { + pub fn build(args: &[String]) -> Result { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); - let filename = args[2].clone(); + let file_path = args[2].clone(); - let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); + let ignore_case = env::var("IGNORE_CASE").is_ok(); Ok(Config { query, - filename, - case_sensitive, + file_path, + ignore_case, }) } } pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; + let contents = fs::read_to_string(config.file_path)?; - let results = if config.case_sensitive { - search(&config.query, &contents) - } else { + let results = if config.ignore_case { search_case_insensitive(&config.query, &contents) + } else { + search(&config.query, &contents) }; for line in results { - println!("{}", line); + println!("{line}"); } Ok(()) diff --git a/listings/ch13-functional-features/listing-13-18/src/main.rs b/listings/ch13-functional-features/listing-13-18/src/main.rs index db9025d6f..40109ef63 100644 --- a/listings/ch13-functional-features/listing-13-18/src/main.rs +++ b/listings/ch13-functional-features/listing-13-18/src/main.rs @@ -1,9 +1,22 @@ -fn main() { - // ANCHOR: here - let v1: Vec = vec![1, 2, 3]; +use std::env; +use std::process; + +use minigrep::Config; - let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); +// ANCHOR: here +fn main() { + let config = Config::build(env::args()).unwrap_or_else(|err| { + eprintln!("Problem parsing arguments: {err}"); + process::exit(1); + }); - assert_eq!(v2, vec![2, 3, 4]); + // --snip-- // ANCHOR_END: here + + if let Err(e) = minigrep::run(config) { + eprintln!("Application error: {e}"); + process::exit(1); + } + // ANCHOR: here } +// ANCHOR_END: here diff --git a/listings/ch13-functional-features/listing-13-19/Cargo.lock b/listings/ch13-functional-features/listing-13-19/Cargo.lock index 0b15e2157..88bf82d16 100644 --- a/listings/ch13-functional-features/listing-13-19/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-19/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "shoe_size" +name = "minigrep" version = "0.1.0" diff --git a/listings/ch13-functional-features/listing-13-19/Cargo.toml b/listings/ch13-functional-features/listing-13-19/Cargo.toml index d0ecdac67..64c2a3f52 100644 --- a/listings/ch13-functional-features/listing-13-19/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-19/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "shoe_size" +name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-26/poem.txt b/listings/ch13-functional-features/listing-13-19/poem.txt similarity index 100% rename from listings/ch13-functional-features/listing-13-26/poem.txt rename to listings/ch13-functional-features/listing-13-19/poem.txt diff --git a/listings/ch13-functional-features/listing-13-19/src/lib.rs b/listings/ch13-functional-features/listing-13-19/src/lib.rs index c7ca364c2..79ae2b8f6 100644 --- a/listings/ch13-functional-features/listing-13-19/src/lib.rs +++ b/listings/ch13-functional-features/listing-13-19/src/lib.rs @@ -1,11 +1,79 @@ -#[derive(PartialEq, Debug)] -struct Shoe { - size: u32, - style: String, +use std::env; +use std::error::Error; +use std::fs; + +pub struct Config { + pub query: String, + pub file_path: String, + pub ignore_case: bool, +} + +// ANCHOR: here +impl Config { + pub fn build( + mut args: impl Iterator, + ) -> Result { + // --snip-- + // ANCHOR_END: here + if args.len() < 3 { + return Err("not enough arguments"); + } + + let query = args[1].clone(); + let file_path = args[2].clone(); + + let ignore_case = env::var("IGNORE_CASE").is_ok(); + + Ok(Config { + query, + file_path, + ignore_case, + }) + } +} + +pub fn run(config: Config) -> Result<(), Box> { + let contents = fs::read_to_string(config.file_path)?; + + let results = if config.ignore_case { + search_case_insensitive(&config.query, &contents) + } else { + search(&config.query, &contents) + }; + + for line in results { + println!("{line}"); + } + + Ok(()) } -fn shoes_in_my_size(shoes: Vec, shoe_size: u32) -> Vec { - shoes.into_iter().filter(|s| s.size == shoe_size).collect() +pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { + let mut results = Vec::new(); + + for line in contents.lines() { + if line.contains(query) { + results.push(line); + } + } + + results +} + +pub fn search_case_insensitive<'a>( + query: &str, + contents: &'a str, +) -> Vec<&'a str> { + let query = query.to_lowercase(); + let mut results = Vec::new(); + + for line in contents.lines() { + if line.to_lowercase().contains(&query) { + results.push(line); + } + } + + results } #[cfg(test)] @@ -13,38 +81,29 @@ mod tests { use super::*; #[test] - fn filters_by_size() { - let shoes = vec![ - Shoe { - size: 10, - style: String::from("sneaker"), - }, - Shoe { - size: 13, - style: String::from("sandal"), - }, - Shoe { - size: 10, - style: String::from("boot"), - }, - ]; - - let in_my_size = shoes_in_my_size(shoes, 10); + fn case_sensitive() { + let query = "duct"; + let contents = "\ +Rust: +safe, fast, productive. +Pick three. +Duct tape."; + + assert_eq!(vec!["safe, fast, productive."], search(query, contents)); + } + + #[test] + fn case_insensitive() { + let query = "rUsT"; + let contents = "\ +Rust: +safe, fast, productive. +Pick three. +Trust me."; assert_eq!( - in_my_size, - vec![ - Shoe { - size: 10, - style: String::from("sneaker") - }, - Shoe { - size: 10, - style: String::from("boot") - }, - ] + vec!["Rust:", "Trust me."], + search_case_insensitive(query, contents) ); } } - -fn main() {} diff --git a/listings/ch13-functional-features/listing-13-27/src/main.rs b/listings/ch13-functional-features/listing-13-19/src/main.rs similarity index 51% rename from listings/ch13-functional-features/listing-13-27/src/main.rs rename to listings/ch13-functional-features/listing-13-19/src/main.rs index 06aac30e7..9ac022545 100644 --- a/listings/ch13-functional-features/listing-13-27/src/main.rs +++ b/listings/ch13-functional-features/listing-13-19/src/main.rs @@ -4,14 +4,13 @@ use std::process; use minigrep::Config; fn main() { - let config = Config::new(env::args()).unwrap_or_else(|err| { - eprintln!("Problem parsing arguments: {}", err); + let config = Config::build(env::args()).unwrap_or_else(|err| { + eprintln!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - eprintln!("Application error: {}", e); - + eprintln!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch13-functional-features/listing-13-20/Cargo.lock b/listings/ch13-functional-features/listing-13-20/Cargo.lock index 58b70c5b7..88bf82d16 100644 --- a/listings/ch13-functional-features/listing-13-20/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-20/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "counter" +name = "minigrep" version = "0.1.0" diff --git a/listings/ch13-functional-features/listing-13-20/Cargo.toml b/listings/ch13-functional-features/listing-13-20/Cargo.toml index 4eb29e80c..64c2a3f52 100644 --- a/listings/ch13-functional-features/listing-13-20/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-20/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "counter" +name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-27/poem.txt b/listings/ch13-functional-features/listing-13-20/poem.txt similarity index 100% rename from listings/ch13-functional-features/listing-13-27/poem.txt rename to listings/ch13-functional-features/listing-13-20/poem.txt diff --git a/listings/ch13-functional-features/listing-13-20/src/lib.rs b/listings/ch13-functional-features/listing-13-20/src/lib.rs index 897804c42..34b7d8f8a 100644 --- a/listings/ch13-functional-features/listing-13-20/src/lib.rs +++ b/listings/ch13-functional-features/listing-13-20/src/lib.rs @@ -1,11 +1,115 @@ -struct Counter { - count: u32, +use std::env; +use std::error::Error; +use std::fs; + +pub struct Config { + pub query: String, + pub file_path: String, + pub ignore_case: bool, +} + +// ANCHOR: here +impl Config { + pub fn build( + mut args: impl Iterator, + ) -> Result { + args.next(); + + let query = match args.next() { + Some(arg) => arg, + // クエリ文字列を取得できませんでした + None => return Err("Didn't get a query string"), + }; + + let file_path = match args.next() { + Some(arg) => arg, + // ファイル名を取得できませんでした + None => return Err("Didn't get a file path"), + }; + + let ignore_case = env::var("IGNORE_CASE").is_ok(); + + Ok(Config { + query, + file_path, + ignore_case, + }) + } +} +// ANCHOR_END: here + +pub fn run(config: Config) -> Result<(), Box> { + let contents = fs::read_to_string(config.file_path)?; + + let results = if config.ignore_case { + search_case_insensitive(&config.query, &contents) + } else { + search(&config.query, &contents) + }; + + for line in results { + println!("{line}"); + } + + Ok(()) } -impl Counter { - fn new() -> Counter { - Counter { count: 0 } +pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { + let mut results = Vec::new(); + + for line in contents.lines() { + if line.contains(query) { + results.push(line); + } } + + results +} + +pub fn search_case_insensitive<'a>( + query: &str, + contents: &'a str, +) -> Vec<&'a str> { + let query = query.to_lowercase(); + let mut results = Vec::new(); + + for line in contents.lines() { + if line.to_lowercase().contains(&query) { + results.push(line); + } + } + + results } -fn main() {} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn case_sensitive() { + let query = "duct"; + let contents = "\ +Rust: +safe, fast, productive. +Pick three. +Duct tape."; + + assert_eq!(vec!["safe, fast, productive."], search(query, contents)); + } + + #[test] + fn case_insensitive() { + let query = "rUsT"; + let contents = "\ +Rust: +safe, fast, productive. +Pick three. +Trust me."; + + assert_eq!( + vec!["Rust:", "Trust me."], + search_case_insensitive(query, contents) + ); + } +} diff --git a/listings/ch13-functional-features/listing-13-29/src/main.rs b/listings/ch13-functional-features/listing-13-20/src/main.rs similarity index 51% rename from listings/ch13-functional-features/listing-13-29/src/main.rs rename to listings/ch13-functional-features/listing-13-20/src/main.rs index 06aac30e7..9ac022545 100644 --- a/listings/ch13-functional-features/listing-13-29/src/main.rs +++ b/listings/ch13-functional-features/listing-13-20/src/main.rs @@ -4,14 +4,13 @@ use std::process; use minigrep::Config; fn main() { - let config = Config::new(env::args()).unwrap_or_else(|err| { - eprintln!("Problem parsing arguments: {}", err); + let config = Config::build(env::args()).unwrap_or_else(|err| { + eprintln!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - eprintln!("Application error: {}", e); - + eprintln!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch13-functional-features/listing-13-21/Cargo.lock b/listings/ch13-functional-features/listing-13-21/Cargo.lock deleted file mode 100644 index 58b70c5b7..000000000 --- a/listings/ch13-functional-features/listing-13-21/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "counter" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-21/Cargo.toml b/listings/ch13-functional-features/listing-13-21/Cargo.toml deleted file mode 100644 index 4eb29e80c..000000000 --- a/listings/ch13-functional-features/listing-13-21/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "counter" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/listing-13-21/src/lib.rs b/listings/ch13-functional-features/listing-13-21/src/lib.rs deleted file mode 100644 index 97806be48..000000000 --- a/listings/ch13-functional-features/listing-13-21/src/lib.rs +++ /dev/null @@ -1,26 +0,0 @@ -struct Counter { - count: u32, -} - -impl Counter { - fn new() -> Counter { - Counter { count: 0 } - } -} - -// ANCHOR: here -impl Iterator for Counter { - type Item = u32; - - fn next(&mut self) -> Option { - if self.count < 5 { - self.count += 1; - Some(self.count) - } else { - None - } - } -} -// ANCHOR_END: here - -fn main() {} diff --git a/listings/ch13-functional-features/listing-13-22/Cargo.lock b/listings/ch13-functional-features/listing-13-22/Cargo.lock index 58b70c5b7..88bf82d16 100644 --- a/listings/ch13-functional-features/listing-13-22/Cargo.lock +++ b/listings/ch13-functional-features/listing-13-22/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "counter" +name = "minigrep" version = "0.1.0" diff --git a/listings/ch13-functional-features/listing-13-22/Cargo.toml b/listings/ch13-functional-features/listing-13-22/Cargo.toml index 4eb29e80c..64c2a3f52 100644 --- a/listings/ch13-functional-features/listing-13-22/Cargo.toml +++ b/listings/ch13-functional-features/listing-13-22/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "counter" +name = "minigrep" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch13-functional-features/listing-13-29/poem.txt b/listings/ch13-functional-features/listing-13-22/poem.txt similarity index 100% rename from listings/ch13-functional-features/listing-13-29/poem.txt rename to listings/ch13-functional-features/listing-13-22/poem.txt diff --git a/listings/ch13-functional-features/listing-13-22/src/lib.rs b/listings/ch13-functional-features/listing-13-22/src/lib.rs index f8faaca07..d694669b4 100644 --- a/listings/ch13-functional-features/listing-13-22/src/lib.rs +++ b/listings/ch13-functional-features/listing-13-22/src/lib.rs @@ -1,43 +1,108 @@ -struct Counter { - count: u32, +use std::env; +use std::error::Error; +use std::fs; + +pub struct Config { + pub query: String, + pub file_path: String, + pub ignore_case: bool, +} + +impl Config { + pub fn build( + mut args: impl Iterator, + ) -> Result { + args.next(); + + let query = match args.next() { + Some(arg) => arg, + None => return Err("Didn't get a query string"), + }; + + let file_path = match args.next() { + Some(arg) => arg, + None => return Err("Didn't get a file path"), + }; + + let ignore_case = env::var("IGNORE_CASE").is_ok(); + + Ok(Config { + query, + file_path, + ignore_case, + }) + } } -impl Counter { - fn new() -> Counter { - Counter { count: 0 } +pub fn run(config: Config) -> Result<(), Box> { + let contents = fs::read_to_string(config.file_path)?; + + let results = if config.ignore_case { + search_case_insensitive(&config.query, &contents) + } else { + search(&config.query, &contents) + }; + + for line in results { + println!("{line}"); } + + Ok(()) +} + +// ANCHOR: here +pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { + contents + .lines() + .filter(|line| line.contains(query)) + .collect() } +// ANCHOR_END: here -impl Iterator for Counter { - type Item = u32; +pub fn search_case_insensitive<'a>( + query: &str, + contents: &'a str, +) -> Vec<&'a str> { + let query = query.to_lowercase(); + let mut results = Vec::new(); - fn next(&mut self) -> Option { - if self.count < 5 { - self.count += 1; - Some(self.count) - } else { - None + for line in contents.lines() { + if line.to_lowercase().contains(&query) { + results.push(line); } } + + results } #[cfg(test)] mod tests { use super::*; - // ANCHOR: here #[test] - fn calling_next_directly() { - let mut counter = Counter::new(); - - assert_eq!(counter.next(), Some(1)); - assert_eq!(counter.next(), Some(2)); - assert_eq!(counter.next(), Some(3)); - assert_eq!(counter.next(), Some(4)); - assert_eq!(counter.next(), Some(5)); - assert_eq!(counter.next(), None); + fn case_sensitive() { + let query = "duct"; + let contents = "\ +Rust: +safe, fast, productive. +Pick three. +Duct tape."; + + assert_eq!(vec!["safe, fast, productive."], search(query, contents)); + } + + #[test] + fn case_insensitive() { + let query = "rUsT"; + let contents = "\ +Rust: +safe, fast, productive. +Pick three. +Trust me."; + + assert_eq!( + vec!["Rust:", "Trust me."], + search_case_insensitive(query, contents) + ); } - // ANCHOR_END: here } - -fn main() {} diff --git a/listings/ch13-functional-features/listing-13-26/src/main.rs b/listings/ch13-functional-features/listing-13-22/src/main.rs similarity index 51% rename from listings/ch13-functional-features/listing-13-26/src/main.rs rename to listings/ch13-functional-features/listing-13-22/src/main.rs index 06aac30e7..9ac022545 100644 --- a/listings/ch13-functional-features/listing-13-26/src/main.rs +++ b/listings/ch13-functional-features/listing-13-22/src/main.rs @@ -4,14 +4,13 @@ use std::process; use minigrep::Config; fn main() { - let config = Config::new(env::args()).unwrap_or_else(|err| { - eprintln!("Problem parsing arguments: {}", err); + let config = Config::build(env::args()).unwrap_or_else(|err| { + eprintln!("Problem parsing arguments: {err}"); process::exit(1); }); if let Err(e) = minigrep::run(config) { - eprintln!("Application error: {}", e); - + eprintln!("Application error: {e}"); process::exit(1); } } diff --git a/listings/ch13-functional-features/listing-13-23/Cargo.lock b/listings/ch13-functional-features/listing-13-23/Cargo.lock deleted file mode 100644 index 58b70c5b7..000000000 --- a/listings/ch13-functional-features/listing-13-23/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "counter" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-23/Cargo.toml b/listings/ch13-functional-features/listing-13-23/Cargo.toml deleted file mode 100644 index 4eb29e80c..000000000 --- a/listings/ch13-functional-features/listing-13-23/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "counter" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/listing-13-23/src/lib.rs b/listings/ch13-functional-features/listing-13-23/src/lib.rs deleted file mode 100644 index 351321ff9..000000000 --- a/listings/ch13-functional-features/listing-13-23/src/lib.rs +++ /dev/null @@ -1,53 +0,0 @@ -struct Counter { - count: u32, -} - -impl Counter { - fn new() -> Counter { - Counter { count: 0 } - } -} - -impl Iterator for Counter { - type Item = u32; - - fn next(&mut self) -> Option { - if self.count < 5 { - self.count += 1; - Some(self.count) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn calling_next_directly() { - let mut counter = Counter::new(); - - assert_eq!(counter.next(), Some(1)); - assert_eq!(counter.next(), Some(2)); - assert_eq!(counter.next(), Some(3)); - assert_eq!(counter.next(), Some(4)); - assert_eq!(counter.next(), Some(5)); - assert_eq!(counter.next(), None); - } - - // ANCHOR: here - #[test] - fn using_other_iterator_trait_methods() { - let sum: u32 = Counter::new() - .zip(Counter::new().skip(1)) - .map(|(a, b)| a * b) - .filter(|x| x % 3 == 0) - .sum(); - assert_eq!(18, sum); - } - // ANCHOR_END: here -} - -fn main() {} diff --git a/listings/ch13-functional-features/listing-13-25/Cargo.lock b/listings/ch13-functional-features/listing-13-25/Cargo.lock deleted file mode 100644 index 88bf82d16..000000000 --- a/listings/ch13-functional-features/listing-13-25/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "minigrep" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-25/Cargo.toml b/listings/ch13-functional-features/listing-13-25/Cargo.toml deleted file mode 100644 index 82606426f..000000000 --- a/listings/ch13-functional-features/listing-13-25/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "minigrep" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/listing-13-25/src/main.rs b/listings/ch13-functional-features/listing-13-25/src/main.rs deleted file mode 100644 index d09966e41..000000000 --- a/listings/ch13-functional-features/listing-13-25/src/main.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::env; -use std::process; - -use minigrep::Config; - -// ANCHOR: here -fn main() { - let config = Config::new(env::args()).unwrap_or_else(|err| { - eprintln!("Problem parsing arguments: {}", err); - process::exit(1); - }); - - // --snip-- - // ANCHOR_END: here - - if let Err(e) = minigrep::run(config) { - eprintln!("Application error: {}", e); - - process::exit(1); - } - // ANCHOR: here -} -// ANCHOR_END: here diff --git a/listings/ch13-functional-features/listing-13-26/Cargo.lock b/listings/ch13-functional-features/listing-13-26/Cargo.lock deleted file mode 100644 index 88bf82d16..000000000 --- a/listings/ch13-functional-features/listing-13-26/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "minigrep" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-26/Cargo.toml b/listings/ch13-functional-features/listing-13-26/Cargo.toml deleted file mode 100644 index 82606426f..000000000 --- a/listings/ch13-functional-features/listing-13-26/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "minigrep" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/listing-13-26/src/lib.rs b/listings/ch13-functional-features/listing-13-26/src/lib.rs deleted file mode 100644 index 2cb0bea7d..000000000 --- a/listings/ch13-functional-features/listing-13-26/src/lib.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::env; -use std::error::Error; -use std::fs; - -pub struct Config { - pub query: String, - pub filename: String, - pub case_sensitive: bool, -} - -// ANCHOR: here -impl Config { - pub fn new(mut args: env::Args) -> Result { - // --snip-- - // ANCHOR_END: here - if args.len() < 3 { - return Err("not enough arguments"); - } - - let query = args[1].clone(); - let filename = args[2].clone(); - - let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); - - Ok(Config { - query, - filename, - case_sensitive, - }) - } -} - -pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; - - let results = if config.case_sensitive { - search(&config.query, &contents) - } else { - search_case_insensitive(&config.query, &contents) - }; - - for line in results { - println!("{}", line); - } - - Ok(()) -} - -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { - let mut results = Vec::new(); - - for line in contents.lines() { - if line.contains(query) { - results.push(line); - } - } - - results -} - -pub fn search_case_insensitive<'a>( - query: &str, - contents: &'a str, -) -> Vec<&'a str> { - let query = query.to_lowercase(); - let mut results = Vec::new(); - - for line in contents.lines() { - if line.to_lowercase().contains(&query) { - results.push(line); - } - } - - results -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn case_sensitive() { - let query = "duct"; - let contents = "\ -Rust: -safe, fast, productive. -Pick three. -Duct tape."; - - assert_eq!(vec!["safe, fast, productive."], search(query, contents)); - } - - #[test] - fn case_insensitive() { - let query = "rUsT"; - let contents = "\ -Rust: -safe, fast, productive. -Pick three. -Trust me."; - - assert_eq!( - vec!["Rust:", "Trust me."], - search_case_insensitive(query, contents) - ); - } -} diff --git a/listings/ch13-functional-features/listing-13-27/Cargo.lock b/listings/ch13-functional-features/listing-13-27/Cargo.lock deleted file mode 100644 index 88bf82d16..000000000 --- a/listings/ch13-functional-features/listing-13-27/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "minigrep" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-27/Cargo.toml b/listings/ch13-functional-features/listing-13-27/Cargo.toml deleted file mode 100644 index 82606426f..000000000 --- a/listings/ch13-functional-features/listing-13-27/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "minigrep" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/listing-13-27/src/lib.rs b/listings/ch13-functional-features/listing-13-27/src/lib.rs deleted file mode 100644 index 61d828aab..000000000 --- a/listings/ch13-functional-features/listing-13-27/src/lib.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::env; -use std::error::Error; -use std::fs; - -pub struct Config { - pub query: String, - pub filename: String, - pub case_sensitive: bool, -} - -// ANCHOR: here -impl Config { - pub fn new(mut args: env::Args) -> Result { - args.next(); - - let query = match args.next() { - Some(arg) => arg, - None => return Err("Didn't get a query string"), - }; - - let filename = match args.next() { - Some(arg) => arg, - None => return Err("Didn't get a file name"), - }; - - let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); - - Ok(Config { - query, - filename, - case_sensitive, - }) - } -} -// ANCHOR_END: here - -pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; - - let results = if config.case_sensitive { - search(&config.query, &contents) - } else { - search_case_insensitive(&config.query, &contents) - }; - - for line in results { - println!("{}", line); - } - - Ok(()) -} - -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { - let mut results = Vec::new(); - - for line in contents.lines() { - if line.contains(query) { - results.push(line); - } - } - - results -} - -pub fn search_case_insensitive<'a>( - query: &str, - contents: &'a str, -) -> Vec<&'a str> { - let query = query.to_lowercase(); - let mut results = Vec::new(); - - for line in contents.lines() { - if line.to_lowercase().contains(&query) { - results.push(line); - } - } - - results -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn case_sensitive() { - let query = "duct"; - let contents = "\ -Rust: -safe, fast, productive. -Pick three. -Duct tape."; - - assert_eq!(vec!["safe, fast, productive."], search(query, contents)); - } - - #[test] - fn case_insensitive() { - let query = "rUsT"; - let contents = "\ -Rust: -safe, fast, productive. -Pick three. -Trust me."; - - assert_eq!( - vec!["Rust:", "Trust me."], - search_case_insensitive(query, contents) - ); - } -} - -fn main() {} diff --git a/listings/ch13-functional-features/listing-13-29/Cargo.lock b/listings/ch13-functional-features/listing-13-29/Cargo.lock deleted file mode 100644 index 88bf82d16..000000000 --- a/listings/ch13-functional-features/listing-13-29/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "minigrep" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/listing-13-29/Cargo.toml b/listings/ch13-functional-features/listing-13-29/Cargo.toml deleted file mode 100644 index 82606426f..000000000 --- a/listings/ch13-functional-features/listing-13-29/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "minigrep" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/listing-13-29/src/lib.rs b/listings/ch13-functional-features/listing-13-29/src/lib.rs deleted file mode 100644 index bc8a77ef6..000000000 --- a/listings/ch13-functional-features/listing-13-29/src/lib.rs +++ /dev/null @@ -1,106 +0,0 @@ -use std::env; -use std::error::Error; -use std::fs; - -pub struct Config { - pub query: String, - pub filename: String, - pub case_sensitive: bool, -} - -impl Config { - pub fn new(mut args: std::env::Args) -> Result { - args.next(); - - let query = match args.next() { - Some(arg) => arg, - None => return Err("Didn't get a query string"), - }; - - let filename = match args.next() { - Some(arg) => arg, - None => return Err("Didn't get a file name"), - }; - - let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); - - Ok(Config { - query, - filename, - case_sensitive, - }) - } -} - -pub fn run(config: Config) -> Result<(), Box> { - let contents = fs::read_to_string(config.filename)?; - - let results = if config.case_sensitive { - search(&config.query, &contents) - } else { - search_case_insensitive(&config.query, &contents) - }; - - for line in results { - println!("{}", line); - } - - Ok(()) -} - -// ANCHOR: here -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { - contents - .lines() - .filter(|line| line.contains(query)) - .collect() -} -// ANCHOR_END: here - -pub fn search_case_insensitive<'a>( - query: &str, - contents: &'a str, -) -> Vec<&'a str> { - let query = query.to_lowercase(); - let mut results = Vec::new(); - - for line in contents.lines() { - if line.to_lowercase().contains(&query) { - results.push(line); - } - } - - results -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn case_sensitive() { - let query = "duct"; - let contents = "\ -Rust: -safe, fast, productive. -Pick three. -Duct tape."; - - assert_eq!(vec!["safe, fast, productive."], search(query, contents)); - } - - #[test] - fn case_insensitive() { - let query = "rUsT"; - let contents = "\ -Rust: -safe, fast, productive. -Pick three. -Trust me."; - - assert_eq!( - vec!["Rust:", "Trust me."], - search_case_insensitive(query, contents) - ); - } -} diff --git a/listings/ch13-functional-features/no-listing-01-failing-cacher-test/Cargo.lock b/listings/ch13-functional-features/no-listing-01-failing-cacher-test/Cargo.lock deleted file mode 100644 index e090432bc..000000000 --- a/listings/ch13-functional-features/no-listing-01-failing-cacher-test/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cacher" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/no-listing-01-failing-cacher-test/Cargo.toml b/listings/ch13-functional-features/no-listing-01-failing-cacher-test/Cargo.toml deleted file mode 100644 index 54ab6f217..000000000 --- a/listings/ch13-functional-features/no-listing-01-failing-cacher-test/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "cacher" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/no-listing-01-failing-cacher-test/output.txt b/listings/ch13-functional-features/no-listing-01-failing-cacher-test/output.txt deleted file mode 100644 index 378a614d4..000000000 --- a/listings/ch13-functional-features/no-listing-01-failing-cacher-test/output.txt +++ /dev/null @@ -1,23 +0,0 @@ -$ cargo test - Compiling cacher v0.1.0 (file:///projects/cacher) - Finished test [unoptimized + debuginfo] target(s) in 0.72s - Running target/debug/deps/cacher-4116485fb32b3fff - -running 1 test -test tests::call_with_different_values ... FAILED - -failures: - ----- tests::call_with_different_values stdout ---- -thread 'main' panicked at 'assertion failed: `(left == right)` - left: `1`, - right: `2`', src/lib.rs:43:9 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. - - -failures: - tests::call_with_different_values - -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out - -error: test failed, to rerun pass '--lib' diff --git a/listings/ch13-functional-features/no-listing-01-failing-cacher-test/src/lib.rs b/listings/ch13-functional-features/no-listing-01-failing-cacher-test/src/lib.rs deleted file mode 100644 index e7d677d0e..000000000 --- a/listings/ch13-functional-features/no-listing-01-failing-cacher-test/src/lib.rs +++ /dev/null @@ -1,47 +0,0 @@ -struct Cacher -where - T: Fn(u32) -> u32, -{ - calculation: T, - value: Option, -} - -impl Cacher -where - T: Fn(u32) -> u32, -{ - fn new(calculation: T) -> Cacher { - Cacher { - calculation, - value: None, - } - } - - fn value(&mut self, arg: u32) -> u32 { - match self.value { - Some(v) => v, - None => { - let v = (self.calculation)(arg); - self.value = Some(v); - v - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // ANCHOR: here - #[test] - fn call_with_different_values() { - let mut c = Cacher::new(|a| a); - - let v1 = c.value(1); - let v2 = c.value(2); - - assert_eq!(v2, 2); - } - // ANCHOR_END: here -} diff --git a/listings/ch13-functional-features/no-listing-02-functions-cant-capture/Cargo.lock b/listings/ch13-functional-features/no-listing-02-functions-cant-capture/Cargo.lock deleted file mode 100644 index a96532add..000000000 --- a/listings/ch13-functional-features/no-listing-02-functions-cant-capture/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "equal-to-x" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/no-listing-02-functions-cant-capture/Cargo.toml b/listings/ch13-functional-features/no-listing-02-functions-cant-capture/Cargo.toml deleted file mode 100644 index 4fd5d8523..000000000 --- a/listings/ch13-functional-features/no-listing-02-functions-cant-capture/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "equal-to-x" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt b/listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt deleted file mode 100644 index a8d9e16d3..000000000 --- a/listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt +++ /dev/null @@ -1,16 +0,0 @@ -$ cargo run - Compiling equal-to-x v0.1.0 (file:///projects/equal-to-x) -error[E0434]: can't capture dynamic environment in a fn item - --> src/main.rs:5:14 - | -5 | z == x - | ^ - | - = help: use the `|| { ... }` closure form instead - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0434`. -error: could not compile `equal-to-x`. - -To learn more, run the command again with --verbose. diff --git a/listings/ch13-functional-features/no-listing-02-functions-cant-capture/src/main.rs b/listings/ch13-functional-features/no-listing-02-functions-cant-capture/src/main.rs deleted file mode 100644 index 1b5d2b930..000000000 --- a/listings/ch13-functional-features/no-listing-02-functions-cant-capture/src/main.rs +++ /dev/null @@ -1,11 +0,0 @@ -fn main() { - let x = 4; - - fn equal_to_x(z: i32) -> bool { - z == x - } - - let y = 4; - - assert!(equal_to_x(y)); -} diff --git a/listings/ch13-functional-features/no-listing-03-move-closures/Cargo.lock b/listings/ch13-functional-features/no-listing-03-move-closures/Cargo.lock deleted file mode 100644 index a96532add..000000000 --- a/listings/ch13-functional-features/no-listing-03-move-closures/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "equal-to-x" -version = "0.1.0" - diff --git a/listings/ch13-functional-features/no-listing-03-move-closures/Cargo.toml b/listings/ch13-functional-features/no-listing-03-move-closures/Cargo.toml deleted file mode 100644 index 4fd5d8523..000000000 --- a/listings/ch13-functional-features/no-listing-03-move-closures/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "equal-to-x" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch13-functional-features/no-listing-03-move-closures/output.txt b/listings/ch13-functional-features/no-listing-03-move-closures/output.txt deleted file mode 100644 index 43490332e..000000000 --- a/listings/ch13-functional-features/no-listing-03-move-closures/output.txt +++ /dev/null @@ -1,22 +0,0 @@ -$ cargo run - Compiling equal-to-x v0.1.0 (file:///projects/equal-to-x) -error[E0382]: borrow of moved value: `x` - --> src/main.rs:6:40 - | -2 | let x = vec![1, 2, 3]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -3 | -4 | let equal_to_x = move |z| z == x; - | -------- - variable moved due to use in closure - | | - | value moved into closure here -5 | -6 | println!("can't use x here: {:?}", x); - | ^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. -error: could not compile `equal-to-x`. - -To learn more, run the command again with --verbose. diff --git a/listings/ch13-functional-features/no-listing-03-move-closures/src/main.rs b/listings/ch13-functional-features/no-listing-03-move-closures/src/main.rs deleted file mode 100644 index 19d477608..000000000 --- a/listings/ch13-functional-features/no-listing-03-move-closures/src/main.rs +++ /dev/null @@ -1,11 +0,0 @@ -fn main() { - let x = vec![1, 2, 3]; - - let equal_to_x = move |z| z == x; - - println!("can't use x here: {:?}", x); - - let y = vec![1, 2, 3]; - - assert!(equal_to_x(y)); -} diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 24d253292..f01793001 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -169,13 +169,13 @@ - [関数型言語の機能:イテレータとクロージャ](ch13-00-functional-features.md) - - [クロージャ:環境をキャプチャできる匿名関数](ch13-01-closures.md) + - [クロージャ:環境をキャプチャする匿名関数](ch13-01-closures.md) - [一連の要素をイテレータで処理する](ch13-02-iterators.md) - [入出力プロジェクトを改善する](ch13-03-improving-our-io-project.md) - [パフォーマンス比較:ループVSイテレータ](ch13-04-performance.md) diff --git a/src/ch13-00-functional-features.md b/src/ch13-00-functional-features.md index 88e8f8e77..df2f8db2c 100644 --- a/src/ch13-00-functional-features.md +++ b/src/ch13-00-functional-features.md @@ -34,23 +34,23 @@ More specifically, we’ll cover: * *クロージャ*、変数に保存できる関数に似た文法要素 * *イテレータ*、一連の要素を処理する方法 -* これら2つの機能を使用して第12章の入出力プロジェクトを改善する方法 -* これら2つの機能のパフォーマンス(ネタバレ: 思ったよりも速いです) +* クロージャとイテレータを使用して第12章の入出力プロジェクトを改善する方法 +* クロージャとイテレータのパフォーマンス(ネタバレ: 思ったよりも速いです) -パターンマッチングやenumなど、他のRustの機能も関数型に影響されていますが、他の章で講義してきました。 +パターンマッチングやenumなども関数型スタイルに影響を受けた他のRustの機能ですが、これらについてはすでに他の章で講義してきました。 クロージャとイテレータをマスターすることは、慣用的で速いRustコードを書くことの重要な部分なので、 この章を丸ごと捧げます。 diff --git a/src/ch13-01-closures.md b/src/ch13-01-closures.md index 6439e7e6f..1732d9e4d 100644 --- a/src/ch13-01-closures.md +++ b/src/ch13-01-closures.md @@ -1,305 +1,77 @@ + -## クロージャ: 環境をキャプチャできる匿名関数 + + +## クロージャ: 環境をキャプチャする匿名関数 Rustのクロージャは、変数に保存したり、引数として他の関数に渡すことのできる匿名関数です。 -ある場所でクロージャを生成し、それから別の文脈でクロージャを呼び出して評価することができます。 -関数と異なり、呼び出されたスコープの値をクロージャは、キャプチャすることができます。 -これらのクロージャの機能がコードの再利用や、動作のカスタマイズを行わせてくれる方法を模擬しましょう。 - - - -### クロージャで動作の抽象化を行う - - - -クロージャを保存して後々使用できるようにするのが有用な場面の例に取り掛かりましょう。その過程で、 -クロージャの記法、型推論、トレイトについて語ります。 - - - -以下のような架空の場面を考えてください: カスタマイズされたエクササイズのトレーニングプランを生成するアプリを作るスタートアップで働くことになりました。 -バックエンドはRustで記述され、トレーニングプランを生成するアルゴリズムは、アプリユーザの年齢や、 -BMI、運動の好み、最近のトレーニング、指定された強弱値などの多くの要因を考慮します。 -実際に使用されるアルゴリズムは、この例では重要ではありません; 重要なのは、この計算が数秒要することです。 -必要なときだけこのアルゴリズムを呼び出し、1回だけ呼び出したいので、必要以上にユーザを待たせないことになります。 - - - -リスト13-1に示した`simulated_expensive_calculation`関数でこの仮定のアルゴリズムを呼び出すことをシミュレートし、 -この関数は`calculating slowly`と出力し、2秒待ってから、渡した数値をなんでも返します。 - - - -ファイル名: src/main.rs - -```rust -use std::thread; -use std::time::Duration; - -fn simulated_expensive_calculation(intensity: u32) -> u32 { - // ゆっくり計算します - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - intensity -} -``` - - - -リスト13-1: 実行に約2秒かかる架空の計算の代役を務める関数 - - - -次は、この例で重要なトレーニングアプリの部分を含む`main`関数です。この関数は、 -ユーザがトレーニングプランを要求した時にアプリが呼び出すコードを表します。 -アプリのフロントエンドと相互作用する部分は、クロージャの使用と関係ないので、プログラムへの入力を表す値をハードコードし、 -その出力を表示します。 - - - -必要な入力は以下の通りです: - - - -* ユーザの強弱値、これはユーザがトレーニングを要求して、低強度のトレーニングか、 -高強度のトレーニングがしたいかを示したときに指定されます。 -* 乱数、これはトレーニングプランにバリエーションを起こします。 - - - -出力は、推奨されるトレーニングプランになります。リスト13-2は使用する`main`関数を示しています。 - - - -ファイル名: src/main.rs - -```rust -fn main() { - let simulated_user_specified_value = 10; - let simulated_random_number = 7; - - generate_workout( - simulated_user_specified_value, - simulated_random_number - ); -} -# fn generate_workout(intensity: u32, random_number: u32) {} -``` - - - -リスト13-2: ユーザ入力や乱数生成をシミュレートするハードコードされた値がある`main`関数 - - - -簡潔性のために、変数`simulated_user_specified_value`は10、変数`simulated_random_number`は7とハードコードしました; -実際のプログラムにおいては、強弱値はアプリのフロントエンドから取得し、乱数の生成には、第2章の数当てゲームの例のように、`rand`クレートを使用するでしょう。 -`main`関数は、シミュレートされた入力値とともに`generate_workout`関数を呼び出します。 - - - -今や文脈ができたので、アルゴリズムに取り掛かりましょう。リスト13-3の`generate_workout`関数は、 -この例で最も気にかかるアプリのビジネスロジックを含んでいます。この例での残りの変更は、 -この関数に対して行われるでしょう: - - - -ファイル名: src/main.rs - -```rust -# use std::thread; -# use std::time::Duration; -# -# fn simulated_expensive_calculation(num: u32) -> u32 { -# println!("calculating slowly..."); -# thread::sleep(Duration::from_secs(2)); -# num -# } -# -fn generate_workout(intensity: u32, random_number: u32) { - if intensity < 25 { - - println!( - // 今日は{}回腕立て伏せをしてください! - "Today, do {} pushups!", - simulated_expensive_calculation(intensity) - ); - - println!( - // 次に、{}回腹筋をしてください! - "Next, do {} situps!", - simulated_expensive_calculation(intensity) - ); - } else { - if random_number == 3 { - // 今日は休憩してください!水分補給を忘れずに! - println!("Take a break today! Remember to stay hydrated!"); - } else { - println!( - // 今日は、{}分間走ってください! - "Today, run for {} minutes!", - simulated_expensive_calculation(intensity) - ); - } - } -} -``` +ある場所でクロージャを生成した後、他の場所でクロージャを呼び出して、別の文脈で評価することができます。 +クロージャは関数と異なり、定義されたスコープから値をキャプチャすることができます。 +これらのクロージャの特性を使用して、どのようにコードの再利用や振る舞いのカスタマイズができるか、実際に試してみましょう。 + -リスト13-3: 入力に基づいてトレーニングプランを出力するビジネスロジックと、 -`simulated_expensive_calculation`関数の呼び出し - - -リスト13-3のコードには、遅い計算を行う関数への呼び出しが複数あります。最初の`if`ブロックが、 -`simulated_expensive_calculation`を2回呼び出し、外側の`else`内の`if`は全く呼び出さず、 -2番目の`else`ケースの内側にあるコードは1回呼び出しています。 - - - - - -`generate_workout`関数の期待される振る舞いは、まずユーザが低強度のトレーニング(25より小さい数値で表される)か、 -高強度のトレーニング(25以上の数値)を欲しているか確認することです。 - - - -低強度のトレーニングプランは、シミュレーションしている複雑なアルゴリズムに基づいて、 -多くの腕立て伏せや腹筋運動を推奨してきます。 - - - -ユーザが高強度のトレーニングを欲していれば、追加のロジックがあります: アプリが生成した乱数がたまたま3なら、 -アプリは休憩と水分補給を勧めます。そうでなければ、ユーザは複雑なアルゴリズムに基づいて数分間のランニングをします。 - - -このコードは現在、ビジネスのほしいままに動くでしょうが、データサイエンスチームが、 -`simulated_expensive_calculation`関数を呼び出す方法に何らかの変更を加える必要があると決定したとしましょう。 -そのような変更が起きた時に更新を簡略化するため、`simulated_expensive_calculation`関数を1回だけ呼び出すように、 -このコードをリファクタリングしたいです。また、その過程でその関数への呼び出しを増やすことなく無駄に2回、 -この関数を現時点で呼んでいるところを切り捨てたくもあります。要するに、結果が必要なければ関数を呼び出したくなく、 -それでも1回だけ呼び出したいのです。 +### クロージャで環境をキャプチャする -#### 関数でリファクタリング +まず、クロージャから定義された環境から後で使用するために値をキャプチャするために、 +どのようにクロージャを使用することができるのか、確かめてみましょう。 +このようなシナリオを考えます: 私たちのTシャツ会社は時折プロモーションとして、 +メーリングリスト上の誰かに、その人専用の限定版のシャツを配ります。 +メーリングリスト上の人たちは、自身のプロファイルにお気に入りの色を任意で追加することができます。 +シャツ無料対象に選ばれた人がお気に入りの色を設定している場合は、その色のシャツをもらえます。 +その人がお気に入りの色を指定していない場合は、会社が現在最も多く持っている色をもらえます。 -多くの方法でトレーニングプログラムを再構築することもできます。 -1番目に`simulated_expensive_calculation`関数への重複した呼び出しを変数に抽出しようとしましょう。リスト13-4に示したように。 +これを実装する方法はたくさんあります。この例では、`Red`と`Blue`の列挙子を持つ、 +`ShirtColor`というenumを使用します(簡潔さのために入手可能な色の数は制限しています)。 +会社の棚卸資産は、`Vec`を含み現在在庫にあるシャツの色を表現する`shirts`というフィールドを持つ、 +`Inventory`構造体で表現します。`Inventory`上に定義された`giveaway`メソッドは、 +シャツ無料対象者の任意選択のシャツの色の好みを取得し、その人がもらえるシャツの色を返します。 +この構築をリスト13-1に示します: -リスト13-4: 複数の`simulated_expensive_calculation`の呼び出しを1箇所に抽出し、 -結果を`expensive_result`変数に保存する +リスト13-1: シャツ会社の無料プレゼントのシチュエーション -この変更により`simulated_expensive_calculation`の呼び出しが単一化され、 -最初の`if`ブロックが無駄に関数を2回呼んでいた問題を解決します。不幸なことに、これでは、 -あらゆる場合にこの関数を呼び出し、その結果を待つことになり、結果値を全く使用しない内側の`if`ブロックでもそうしてしまいます。 +`main`で定義されている`store`には、この限定版プロモーションのために残された、 +青いシャツが2着と赤いシャツが1着あります。赤いシャツが好みのユーザと、好みがないユーザを対象として、 +`giveaway`メソッドを呼び出しています。 -プログラムの1箇所でコードを定義したいですが、結果が本当に必要なところでだけコードを*実行*します。 -これは、クロージャのユースケースです! +繰り返しになりますが、このコードは多くの方法で実装することができます。 +ここではクロージャに着目するために、すでに学習した概念に固執しています。 +ただし、`giveaway`メソッドの本体はクロージャを使用していて、例外です。 +`giveaway`メソッドでは、ユーザの好みを`Option`型の引数として取り、 +`user_preference`に対して`unwrap_or_else`メソッドを呼び出します。 +[`Option`に対する`unwrap_or_else`メソッド][unwrap-or-else]は標準ライブラリで定義されています。 +このメソッドは引数を1つ取ります: 値`T`(`Option`の`Some`列挙子内に保存されているのと同じ型、 +この場合は`ShirtColor`)を返す、引数のないクロージャです。 +もし`Option`が`Some`列挙子の場合、`unwrap_or_else`は`Some`の内側の値を返します。 +もし`Option`が`None`列挙子の場合、`unwrap_or_else`はクロージャを呼び出し、 +そのクロージャによって返された値を返します。 -#### クロージャでリファクタリングして、コードを保存する +`unwrap_or_else`への引数としてクロージャ式`|| self.most_stocked()`を指定しています。 +これは引数を取らないクロージャです(クロージャが引数を持つ場合、それらは2本の縦線の間に現れます)。 +クロージャの本体は`self.most_stocked()`を呼び出します。 +クロージャはここで定義され、`unwrap_or_else`の実装詳細がクロージャの結果を必要とするなら、 +このクロージャを呼び出すでしょう。 -`if`ブロックの前にいつも`simulated_expensive_calculation`関数を呼び出す代わりに、 -クロージャを定義し、関数呼び出しの結果を保存するのではなく、その*クロージャ*を変数に保存できます。リスト13-5のようにですね。 -`simulated_expensive_calculation`の本体全体を実際に、ここで導入しているクロージャ内に移すことができます。 - - +このコードを実行すると、以下が出力されます: -ファイル名: src/main.rs - -```rust -# use std::thread; -# use std::time::Duration; -# -let expensive_closure = |num| { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - num -}; -# expensive_closure(5); +```console +{{#include ../listings/ch13-functional-features/listing-13-01/output.txt}} ``` - -リスト13-5: クロージャを定義し、`expensive_closure`変数に保存する - - - -クロージャ定義が`=`に続き、変数`expensive_closure`に代入されています。クロージャを定義するには、 -1組の縦棒から始め、その内部にクロージャの仮引数を指定します; この記法は、SmalltalkやRubyのクロージャ定義と類似していることから、 -選択されました。このクロージャには、`num`という引数が1つあります: 2つ以上引数があるなら、 -`|param1, param2|`のように、カンマで区切ります。 - - -引数の後に、クロージャの本体を保持する波括弧を配置します(これはクロージャ本体が式一つなら省略可能です)。 -波括弧の後、クロージャのお尻には、セミコロンが必要で、`let`文を完成させます。クロージャ本体の最後の行から返る値(`num`)が、 -呼び出された時にクロージャから返る値になります。その行がセミコロンで終わっていないからです; -ちょうど関数の本体みたいですね。 - - - -この`let`文は、`expensive_closure`が、匿名関数を呼び出した*結果の値*ではなく、 -匿名関数の*定義*を含むことを意味することに注意してください。コードを定義して、 -1箇所で呼び出し、そのコードを保存し、後々、それを呼び出したいがためにクロージャを使用していることを思い出してください; -呼び出したいコードは、現在、`expensive_closure`に保存されています。 - - - - - -クロージャが定義されたので、`if`ブロックのコードを変更して、そのコードを実行するクロージャを呼び出し、結果値を得ることができます。 -クロージャは、関数のように呼び出せます: クロージャ定義を含む変数名を指定し、使用したい引数値を含むかっこを続けます。 -リスト13-6に示したようにですね。 - - - -ファイル名: src/main.rs - -```rust -# use std::thread; -# use std::time::Duration; -# -fn generate_workout(intensity: u32, random_number: u32) { - let expensive_closure = |num| { - println!("calculating slowly..."); - thread::sleep(Duration::from_secs(2)); - num - }; - - if intensity < 25 { - println!( - "Today, do {} pushups!", - expensive_closure(intensity) - ); - println!( - "Next, do {} situps!", - expensive_closure(intensity) - ); - } else { - if random_number == 3 { - println!("Take a break today! Remember to stay hydrated!"); - } else { - println!( - "Today, run for {} minutes!", - expensive_closure(intensity) - ); - } - } -} -``` - - - -リスト13-6: 定義した`expensive_closure`を呼び出す - - - - - -今では、重い計算はたった1箇所でのみ呼び出され、その結果が必要なコードを実行するだけになりました。 - - - -ところが、リスト13-3の問題の一つを再浮上させてしまいました: それでも、最初の`if`ブロックでクロージャを2回呼んでいて、 -そうすると、重いコードを2回呼び出し、必要な分の2倍ユーザを待たせてしまいます。その`if`ブロックのみに属する変数を生成して、 -クロージャの呼び出し結果を保持するその`if`ブロックに固有の変数を生成することでこの問題を解消することもできますが、 -クロージャは他の解決法も用意してくれます。その解決策については、もう少し先で語りましょう。でもまずは、 -クロージャ定義に型注釈がない理由とクロージャに関わるトレイトについて話しましょう。 +ここで興味深い側面は、現在の`Inventory`インスタンスに対して`self.most_stocked()`を呼び出すクロージャを渡していることです。 +標準ライブラリは、プログラマが定義した`Inventory`や`ShirtColor`型や、 +このシナリオで使用したいロジックについては何も知りません。 +クロージャは`self` `Inventory`インスタンスへの不変参照をキャプチャし、 +この不変参照をプログラマが指定したコードとともに`unwrap_or_else`メソッドに渡します。 +一方で関数は、このように環境をキャプチャすることができません。 -クロージャでは、`fn`関数のように引数の型や戻り値の型を注釈する必要はありません。関数では、 -型注釈は必要です。ユーザに露出する明示的なインターフェイスの一部だからです。このインターフェイスを堅実に定義することは、 -関数が使用したり、返したりする値の型についてみんなが合意していることを保証するために重要なのです。 -しかし、クロージャはこのような露出するインターフェイスには使用されません: 変数に保存され、 +関数とクロージャの違いは他にもあります。 +クロージャでは通常、`fn`関数のように引数の型や戻り値の型を注釈する必要はありません。 +関数では、型注釈は必要です。型はユーザに露出する明示的なインターフェイスの一部だからです。 +このインターフェイスを堅実に定義することは、関数が使用したり、 +返したりする値の型についてみんなが合意していることを保証するために重要なのです。 +一方で、クロージャはこのような露出するインターフェイスには使用されません: 変数に保存され、 名前付けしたり、ライブラリの使用者に晒されることなく、使用されます。 -クロージャは通常短く、あらゆる任意の筋書きではなく、狭い文脈でのみ関係します。 +クロージャは典型的には短く、あらゆる任意の筋書きではなく、狭い文脈でのみ関係します。 このような限定された文脈内では、コンパイラは、多くの変数の型を推論できるのと似たように、 -引数や戻り値の型を頼もしく推論することができます。 - - - -このような小さく匿名の関数で型をプログラマに注釈させることは煩わしいし、コンパイラがすでに利用可能な情報と大きく被っています。 +引数や戻り値の型を推論することができます (コンパイラがクロージャ型注釈を要求するレアケースもあります)。 -本当に必要な以上に冗長になることと引き換えに、明示性と明瞭性を向上させたいなら、変数に型注釈を加えることもできます; -リスト13-5で定義したクロージャに型を注釈するなら、リスト13-7に示した定義のようになるでしょう。 +本当に必要な以上に冗長になることと引き換えに、明示性と明瞭性を向上させたいなら、 +変数に型注釈を加えることもできます; +クロージャに対する型注釈は、リスト13-2に示した定義のようになるでしょう。 +この例では、リスト13-1でやったようにクロージャを定義したその場で引数として渡すのではなく、 +クロージャを定義して変数に保存しています。 -リスト13-7: クロージャの引数と戻り値の省略可能な型注釈を追加する +リスト13-2: クロージャの引数と戻り値の省略可能な型注釈を追加する -型注釈を付け加えると、クロージャの記法は、関数の記法により酷似して見えます。以下が、引数に1を加える関数の定義と、 -同じ振る舞いをするクロージャの定義の記法を縦に比べたものです。 +型注釈を付け加えると、クロージャの記法は関数の記法とより似た見た目になっていきます。 +以下は比較のために、引数に1を加える関数と、同じ振る舞いをするクロージャを定義しています。 空白を追加して、関連のある部分を並べています。これにより、縦棒の使用と省略可能な記法の量を除いて、 クロージャ記法が関数記法に似ているところを説明しています。 @@ -644,32 +260,43 @@ let add_one_v4 = |x| x + 1 ; 1行目が関数定義を示し、2行目がフルに注釈したクロージャ定義を示しています。 -3行目は、クロージャ定義から型注釈を取り除き、4行目は、かっこを取り除いていて、 -かっこはクロージャの本体がただ1つの式からなるので、省略可能です。これらは全て、 -呼び出された時に同じ振る舞いになる合法な定義です。 - - -クロージャ定義には、引数それぞれと戻り値に対して推論される具体的な型が一つあります。例えば、 -リスト13-8に引数として受け取った値を返すだけの短いクロージャの定義を示しました。 -このクロージャは、この例での目的以外には有用ではありません。この定義には、 -何も型注釈を加えていないことに注意してください: それから1回目に`String`を引数に、 -2回目に`u32`を引数に使用してこのクロージャを2回呼び出そうとしたら、エラーになります。 +クロージャ定義では、コンパイラは引数それぞれと戻り値に対して、一つの具体的な型を推論します。 +例えば、リスト13-3に引数として受け取った値を返すだけの短いクロージャの定義を示しました。 +このクロージャは、この例での目的以外には有用ではありません。 +この定義には、何も型注釈を加えていないことに注意してください。 +型注釈が無いので、任意の型に対してこのクロージャを呼び出すことができ、 +ここでは最初は`String`に対して呼び出しています。 +その後整数に対して`example_closure`を呼び出そうとすると、エラーになります。 -リスト13-8: 2つの異なる型で型が推論されるクロージャの呼び出しを試みる +リスト13-3: 2つの異なる型で型が推論されるクロージャの呼び出しを試みる src/main.rs - | - | let n = example_closure(5); - | ^ expected struct `std::string::String`, found - integral variable - | - = note: expected type `std::string::String` - found type `{integer}` +```console +{{#include ../listings/ch13-functional-features/listing-13-03/output.txt}} ``` -`String`値で`example_closure`を呼び出した最初の時点で、コンパイラは`x`とクロージャの戻り値の型を`String`と推論します。 -そして、その型が`example_closure`のクロージャに閉じ込められ、同じクロージャを異なる型で使用しようとすると、 -型エラーが出るのです。 +`String`値で`example_closure`を呼び出した最初の時点で、 +コンパイラは`x`とクロージャの戻り値の型を`String`と推論します。 +そして、その型が`example_closure`のクロージャに閉じ込められ、 +次に同じクロージャを異なる型で使用しようとすると、型エラーが出るのです。 -### ジェネリック引数と`Fn`トレイトを使用してクロージャを保存する +### 参照をキャプチャするか、所有権を移動するか - -トレーニング生成アプリに戻りましょう。リスト13-6において、まだコードは必要以上の回数、重い計算のクロージャを呼んでいました。 -この問題を解決する一つの選択肢は、重いクロージャの結果を再利用できるように変数に保存し、クロージャを再度呼ぶ代わりに、 -結果が必要になる箇所それぞれでその変数を使用することです。しかしながら、この方法は同じコードを大量に繰り返す可能性があります。 - - - -運のいいことに、別の解決策もあります。クロージャやクロージャの呼び出し結果の値を保持する構造体を作れるのです。 -結果の値が必要な場合のみにその構造体はクロージャを実行し、その結果の値をキャッシュするので、残りのコードは、 -結果を保存し、再利用する責任を負わなくて済むのです。このパターンは、*メモ化*(memoization)または、 -*遅延評価*(lazy evaluation)として知っているかもしれません。 - - - - - -クロージャを保持する構造体を作成するために、クロージャの型を指定する必要があります。 -構造体定義は、各フィールドの型を把握しておく必要がありますからね。各クロージャインスタンスには、 -独自の匿名の型があります: つまり、たとえ2つのクロージャが全く同じシグニチャでも、その型はそれでも違うものと考えられるということです。 -クロージャを使用する構造体、enum、関数引数を定義するには、第10章で議論したように、 -ジェネリクスとトレイト境界を使用します。 - - - -`Fn`トレイトは、標準ライブラリで用意されています。全てのクロージャは、以下のいずれかのトレイトを実装しています: -`Fn`、`FnMut`または、`FnOnce`です。「クロージャで環境をキャプチャする」節で、これらのトレイト間の差異を議論します; -この例では、`Fn`トレイトを使えます。 - - -`Fn`トレイト境界にいくつかの型を追加することで、このトレイト境界に合致するクロージャが持つべき引数と戻り値の型を示します。 -今回のクロージャは`u32`型の引数を一つ取り、`u32`を返すので、指定するトレイト境界は`Fn(u32) -> u32`になります。 +クロージャは、3つの方法で環境から値をキャプチャでき、この方法は関数が引数を取れる3つの方法に直に対応します: +不変で借用する、可変で借用する、所有権を奪うです。クロージャは、 +関数本体がキャプチャされた値を使って何をするかに基づいて、これらのうちどれを使用するかを決定します。 -リスト13-9は、クロージャとオプションの結果値を保持する`Cacher`構造体の定義を示しています。 +リスト13-4では、`list`というベクタへの不変参照をキャプチャするクロージャが定義されます。 +値を出力するためには不変参照しか必要としないからです: -リスト13-9: クロージャを`calculation`に、オプションの結果値を`value`に保持する`Cacher`構造体を定義する +リスト13-4: 不変参照をキャプチャするクロージャを定義し、呼び出す -`Cacher`構造体は、ジェネリックな型`T`の`calculation`フィールドを持ちます。`T`のトレイト境界は、 -`Fn`トレイトを使うことでクロージャであると指定しています。`calculation`フィールドに保存したいクロージャは全て、 -1つの`u32`引数(`Fn`の後の括弧内で指定されている)を取り、`u32`(`->`の後に指定されている)を返さなければなりません。 +この例は、変数をクロージャ定義に束縛することができ、 +その変数名が関数名であるかのように変数名と丸かっこを使用することで、 +後でそのクロージャを呼び出すことができることも示しています。 -> 注釈: 関数も3つの`Fn`トレイト全部を実装します。もし環境から値をキャプチャする必要がなければ、 -> `Fn`トレイトを実装する何かが必要になるクロージャではなく、関数を使用できます。 - - +`list`への不変参照は複数同時に存在することができるので、`list`には、 +クロージャ定義より前のコードからでも、クロージャ定義からクロージャ呼び出しまでの間のコードからでも、 +クロージャ呼び出し後のコードからでも、アクセスすることができます。 +このコードはコンパイルでき、実行でき、以下を出力します: -`value`フィールドの型は、`Option`です。クロージャを実行する前に、`value`は`None`になるでしょう。 -`Cacher`を使用するコードがクロージャの*結果*を求めてきたら、その時点で`Cacher`はクロージャを実行し、 -その結果を`value`フィールドの`Some`列挙子に保存します。それから、コードが再度クロージャの結果を求めたら、 -クロージャを再実行するのではなく、`Cacher`は`Some`列挙子に保持された結果を返すでしょう。 +```console +{{#include ../listings/ch13-functional-features/listing-13-04/output.txt}} +``` -たった今解説した`value`フィールド周りのロジックは、リスト13-10で定義されています。 +次にリスト13-5では、`list`ベクタへ要素を追加するようにクロージャ本体を変更します。 +クロージャは可変参照をキャプチャするようになります: -リスト13-10: `Cacher`のキャッシュ機構 +リスト13-5: 可変参照をキャプチャするクロージャを定義し、呼び出す -呼び出し元のコードにこれらのフィールドの値を直接変えてもらうのではなく、`Cacher`に構造体のフィールドの値を管理してほしいので、 -これらのフィールドは非公開になっています。 - - +このコードはコンパイルでき、実行でき、以下を出力します: -`Cacher::new`関数はジェネリックな引数の`T`を取り、`Cacher`構造体と同じトレイト境界を持つよう定義しました。 -それから`calculation`フィールドに指定されたクロージャと、 -`value`フィールドに`None`値を保持する`Cacher`インスタンスを`Cacher::new`は返します。 -まだクロージャを実行していないからですね。 +```console +{{#include ../listings/ch13-functional-features/listing-13-05/output.txt}} +``` -呼び出し元のコードがクロージャの評価結果を必要としたら、クロージャを直接呼ぶ代わりに、`value`メソッドを呼びます。 -このメソッドは、結果の値が`self.value`の`Some`に既にあるかどうか確認します; そうなら、 -クロージャを再度実行することなく`Some`内の値を返します。 +`borrows_mutably`クロージャの定義と呼び出しの間の`println!`を消したことに注意してください: +`borrows_mutably`が定義されるときに、`list`への可変参照がキャプチャされます。 +クロージャを呼び出した後は、クロージャを再度使用していないので、可変借用は終了します。 +可変借用が存在するときに他の借用は許可されないので、 +クロージャ定義とクロージャ呼び出しの間に、出力するための不変借用は許可されません。 +`println!`を追加してみて、どんなエラーメッセージが得られるか確認してみてください! -`self.value`が`None`なら、コードは`self.calculation`に保存されたクロージャを呼び出し、 -結果を将来使えるように`self.value`に保存し、その値を返しもします。 +クロージャの本体が厳密には所有権を必要としない場合であっても、 +クロージャにそれが使用する値の所有権を環境から奪うように強制したい場合は、 +引数リストの前で`move`キーワードを使用することができます。 -リスト13-11は、リスト13-6の関数`generate_workout`でこの`Cacher`構造体を使用する方法を示しています。 +この手法は主に、新しいスレッドにクロージャを渡すときに、 +データが新しいスレッドに所有されるようにムーブするために有用です。 +スレッドについて、そしてなぜスレッドを使用するのかについては、 +第16章で並行性について語るときに詳しく議論しますが、今のところは、 +`move`キーワードが必要なクロージャを使って新しいスレッドを生成することについて簡単に探検してみましょう。 +リスト13-6に、メインスレッド内ではなく新しいスレッド内でベクタを出力するようにリスト13-4を変更したものを示します: -リスト13-11: `generate_workout`関数内で`Cacher`を使用し、キャッシュ機構を抽象化する +リスト13-6: `move`を使用して、スレッドのためのクロージャに`list`の所有権を奪わせる -クロージャを変数に直接保存する代わりに、クロージャを保持する`Cacher`の新規インスタンスを保存しています。 -そして、結果が必要な場所それぞれで、その`Cacher`インスタンスに対して`value`メソッドを呼び出しています。 -必要なだけ`value`メソッドを呼び出したり、全く呼び出さないこともでき、重い計算は最大でも1回しか走りません。 +実行するクロージャを引数としてスレッドに与えて、新しいスレッドを生成します。 +クロージャ本体はリストを表示します。 +リスト13-4では、クロージャは不変参照を使って`list`をキャプチャしているだけでした。 +それが`list`を出力するために必要な最小のアクセスだからです。 +この例では、クロージャ本体はやはり不変参照のみを要求しますが、 +クロージャ定義の先頭に`move`キーワードを置くことで、 +`list`をクロージャ内にムーブすべきだと指定する必要があります。 +新しいスレッドはメインスレッドの残りの部分が終了するより前に終了するかもしれませんし、 +メインスレッドが先に終了するかもしれません。 +もしメインスレッドが`list`の所有権を持ち続け、新しいスレッドが終了する前に終了して`list`をドロップしてしまうと、 +スレッド内の不変参照は無効になるでしょう。そのためコンパイラは、参照が有効になるように、 +新しいスレッドに渡されるクロージャに`list`がムーブされることを要求します。 +`move`キーワードを削除したり、メインスレッド内でクロージャが定義された後に`list`を使用したりしてみて、 +どんなコンパイルエラーが得られるか確認してみてください! + -リスト13-2の`main`関数とともにこのプログラムを走らせてみてください。 -`simulated_user_specified_value`と`simulated_random_number`変数の値を変えて、 -いろんな`if`や`else`ブロックの場合全てで、`calculating slowly`は1回だけ、必要な時にのみ出現することを実証してください。 -必要以上に重い計算を呼び出さないことを保証するのに必要なロジックの面倒を`Cacher`は見るので、 -`generate_workout`はビジネスロジックに集中できるのです。 - -### `Cacher`実装の限界 +### キャプチャされた値のクロージャからのムーブと、`Fn`系トレイト -値をキャッシュすることは、コードの他の部分でも異なるクロージャで行いたくなる可能性のある一般的に有用な振る舞いです。 -しかし、現在の`Cacher`の実装には、他の文脈で再利用することを困難にしてしまう問題が2つあります。 +クロージャが参照をキャプチャしたり、クロージャが定義されている環境から値の所有権をキャプチャする +(つまりクロージャの*中に*何をムーブするかに影響を与えます)と、クロージャの本体内のコードは、 +後でクロージャが評価されたときにその参照または値に何が起こるかを定義します +(つまりクロージャの*外に*何をムーブするかに影響を与えます)。 +クロージャ本体は以下のいずれかを行うことができます: キャプチャされた値をクロージャの外にムーブしたり、 +キャプチャされた値を変更したり、値をムーブも変更もしないでいたり、そもそも環境から何もキャプチャしないかです。 -1番目の問題は、`Cacher`インスタンスが、常に`value`メソッドの引数`arg`に対して同じ値になると想定していることです。 -言い換えると、`Cacher`のこのテストは、失敗するでしょう: - -```rust,ignore -#[test] -fn call_with_different_values() { - let mut c = Cacher::new(|a| a); - - let v1 = c.value(1); - let v2 = c.value(2); - - assert_eq!(v2, 2); -} -``` +クロージャがどのように環境から値をキャプチャして使用するかは、クロージャがどのトレイトを実装するかに影響を及ぼします。 +トレイトは、関数や構造体がどんな種類のクロージャを使用できるかを指定するための方法として使用されます。 +クロージャは、その本体はどのように値を使用するかに応じて、以下の`Fn`系トレイトのうち1つ、2つ、または3つすべてを、付加的に自動的に実装します: -このテストは、渡された値を返すクロージャを伴う`Cacher`インスタンスを新しく生成しています。 -この`Cacher`インスタンスに対して1という`arg`値で呼び出し、それから2という`arg`値で呼び出し、 -2という`arg`値の`value`呼び出しは2を返すべきと期待しています。 +1. `FnOnce`は、一度呼び出すことができるクロージャに適用されます。 + すべてのクロージャは、呼び出すことができるので、最低でもこのトレイトを実装します。 + キャプチャされた値を本体の外にムーブするクロージャは、一度しか呼び出すことができないので、 + `FnOnce`のみを実装し、他の`Fn`系トレイト群を実装しないことになるでしょう。 +2. `FnMut`は、キャプチャされた値を本体の外にムーブしないが、キャプチャされた値を変更するかもしれないクロージャに適用されます。 + これらのクロージャは複数回呼び出すことができます。 +3. `Fn`は、キャプチャされた値を本体の外にムーブせず、キャプチャされた値を変更しないクロージャと、 + 環境から何もキャプチャしないクロージャに適用されます。これらのクロージャは環境を変更することなく複数回呼び出すことができ、 + クロージャを並行して複数回呼び出す場合などに重要です。 + -このテストをリスト13-9とリスト13-10の`Cacher`実装で動かすと、`assert_eq`からこんなメッセージが出て、 -テストは失敗します: +リスト13-1で使用した、`Option`に対する`unwrap_or_else`メソッドの定義を見てみましょう: -```text -thread 'call_with_different_values' panicked at 'assertion failed: `(left == right)` - left: `1`, - right: `2`', src/main.rs +```rust,ignore +impl Option { + pub fn unwrap_or_else(self, f: F) -> T + where + F: FnOnce() -> T + { + match self { + Some(x) => x, + None => f(), + } + } +} ``` - -問題は、初めて`c.value`を1で呼び出した時に、`Cacher`インスタンスは`self.value`に`Some(1)`を保存したことです。 -その後`value`メソッドに何を渡しても、常に1を返すわけです。 - - -単独の値ではなく、ハッシュマップを保持するように`Cacher`を改変してみてください。ハッシュマップのキーは、 -渡される`arg`値になり、ハッシュマップの値は、そのキーでクロージャを呼び出した結果になるでしょう。 -`self.value`が直接`Some`か`None`値であることを調べる代わりに、`value`関数はハッシュマップの`arg`を調べ、 -存在するならその値を返します。存在しないなら、`Cacher`はクロージャを呼び出し、 -`arg`値に紐づけてハッシュマップに結果の値を保存します。 +`T`は`Option`の`Some`列挙子内の値の型を表現するジェネリック型であることを思い出してください。 +型`T`は`unwrap_or_else`関数の戻り値型でもあります: 例えば`Option`に対して`unwrap_or_else`を呼び出すコードは、`String`を得るでしょう。 -現在の`Cacher`実装の2番目の問題は、引数の型に`u32`を一つ取り、`u32`を返すクロージャしか受け付けないことです。 -例えば、文字列スライスを取り、`usize`を返すクロージャの結果をキャッシュしたくなるかもしれません。 -この問題を修正するには、`Cacher`機能の柔軟性を向上させるためによりジェネリックな引数を導入してみてください。 +次に、`unwrap_or_else`関数は追加のジェネリック型引数`F`を持つことに注目してください。 +型`F`は引数`f`の型で、`f`は`unwrap_or_else`を呼び出すときにこちらから提供するクロージャです。 -### クロージャで環境をキャプチャする +`FnOnce() -> T`はジェネリック型`F`に対して指定されているトレイト境界で、これは、 +`F`は一度呼び出すことができ、引数を取らず、`T`を返すことを意味します。 +トレイト境界で`FnOnce`を使用することは、`unwrap_or_else`は`f`を多くとも1回しか呼び出さないという制約を表現します。 +`unwrap_or_else`の本体の中では、`Option`が`Some`の場合は`f`は呼ばれないことがわかるでしょう。 +`Option`が`None`の場合は、`f`は一度呼び出されるでしょう。すべてのクロージャは`FnOnce`を実装するので、 +`unwrap_or_else`は最も多くの種類のクロージャを受け入れ、最も柔軟です。 -トレーニング生成の例においては、クロージャをインラインの匿名関数として使っただけでした。しかし、 -クロージャには、関数にはない追加の能力があります: 環境をキャプチャし、 -自分が定義されたスコープの変数にアクセスできるのです。 +> 注釈: 関数も3つの`Fn`系トレイト全部を実装することができます。もし環境から値をキャプチャする必要がなければ、 +> `Fn`系トレイトのいずれかを実装する何かが必要になるクロージャではなく、関数の名前を使用できます。 +> 例えば、`Option>`値に対して、その値が`None`である場合には新しい空のベクタを得るためには、 +> `unwrap_or_else(Vec::new)`と呼び出すことができます。 -リスト13-12は、`equal_to_x`変数に保持されたクロージャを囲む環境から`x`変数を使用するクロージャの例です。 +それでは、スライスに対して定義されている標準ライブラリメソッド`sort_by_key`を見てみて、 +`unwrap_or_else`とどう違うのか、`sort_by_key`はなぜトレイト境界に`FnOnce`ではなく`FnMut`を使用するのか、 +確認してみましょう。このクロージャは、処理対象のスライス内の現在の要素への参照という形で1つの引数を取り、 +順序付けることができる`K`型の値を返します。この関数は、 +スライスを各要素の特定の属性によってソートしたいときに便利です。 +リスト13-7では、`Rectangle`インスタンスからなるリストがあり、 +`width`属性によってその各要素を昇順に並び替えるために、`sort_by_key`を使用しています: -リスト13-12: 内包するスコープの変数を参照するクロージャの例 +リスト13-7: `sort_by_key`を使用して、幅で長方形を順序付ける - -ここで、`x`は`equal_to_x`の引数でもないのに、 -`equal_to_x`が定義されているのと同じスコープで定義されている`x`変数を`equal_to_x`クロージャは使用できています。 - - - -同じことを関数では行うことができません; 以下の例で試したら、コードはコンパイルできません: - - -ファイル名: src/main.rs - -```rust,ignore -fn main() { - let x = 4; - - fn equal_to_x(z: i32) -> bool { z == x } - - let y = 4; +このコードは以下を出力します: - assert!(equal_to_x(y)); -} +```console +{{#include ../listings/ch13-functional-features/listing-13-07/output.txt}} ``` -エラーが出ます: - -```text -error[E0434]: can't capture dynamic environment in a fn item; use the || { ... -} closure form instead -(エラー: fn要素では動的な環境をキャプチャできません; 代わりに|| { ... }のクロージャ形式を -使用してください) - --> src/main.rs - | -4 | fn equal_to_x(z: i32) -> bool { z == x } - | ^ -``` +`sort_by_key`が`FnMut`クロージャを取るように定義されている理由は、クロージャを複数回呼び出すからです: +スライス内の各要素ごとに一度呼び出されます。クロージャ`|r| r.width` は、環境から何もキャプチャ、 +変更、ムーブしないので、トレイト境界の要求を満たしています。 -コンパイラは、この形式はクロージャでのみ動作することさえも思い出させてくれています! +対照的にリスト13-8では、環境から値をムーブすることから、 +`FnOnce`トレイトだけを実装するクロージャの例を示しています。 +コンパイラは、`sort_by_key`でこのクロージャを使わせてくれないでしょう: -クロージャが環境から値をキャプチャすると、メモリを使用してクロージャ本体で使用できるようにその値を保存します。 -このメモリ使用は、環境をキャプチャしないコードを実行するようなもっと一般的な場合には払いたくないオーバーヘッドです。 -関数は、絶対に環境をキャプチャすることが許可されていないので、関数を定義して使えば、このオーバーヘッドを招くことは絶対にありません。 - - +ファイル名: src/main.rs -クロージャは、3つの方法で環境から値をキャプチャでき、この方法は関数が引数を取れる3つの方法に直に対応します: -所有権を奪う、可変で借用する、不変で借用するです。これらは、以下のように3つの`Fn`トレイトでコード化されています: +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch13-functional-features/listing-13-08/src/main.rs}} +``` -* `FnOnce`は、クロージャの*環境*として知られている内包されたスコープからキャプチャした変数を消費します。 -キャプチャした変数を消費するために、定義された際にクロージャはこれらの変数の所有権を奪い、 -自身にムーブするのです。名前のうち、`Once`の部分は、 -このクロージャは同じ変数の所有権を2回以上奪うことができないという事実を表しているので、1回しか呼ぶことができないのです。 -* `FnMut`は、可変で値を借用するので、環境を変更することができます。 -* `Fn`は、環境から値を不変で借用します。 +リスト13-8: `sort_by_key`で`FnOnce`クロージャを使用しようとする -クロージャを生成する時、クロージャが環境を使用する方法に基づいて、コンパイラはどのトレイトを使用するか推論します。 -少なくとも1回は呼び出されるので、全てのクロージャは`FnOnce`を実装しています。キャプチャした変数をムーブしないクロージャは、 -`FnMut`も実装し、キャプチャした変数に可変でアクセスする必要のないクロージャは、`Fn`も実装しています。 -リスト13-12では、`equal_to_x`クロージャは`x`を不変で借用しています(ゆえに`equal_to_x`は`Fn`トレイトです)。 -クロージャの本体は、`x`を読む必要しかないからです。 - - +これは、`list`をソートするときに`sort_by_key`が呼ばれる回数を数えようとする、 +人為的で複雑な(しかも動かない)方法です。このコードは、 +`sort_operations`ベクタに`value`—クロージャの環境からの`String`—をプッシュすることで、 +このカウントを行おうとします。このクロージャは`value`をキャプチャし、 +`value`の所有権を`sort_operations`ベクタに移転することで、`value`をクロージャの外にムーブします。 +このクロージャは一度呼び出すことができます; 2回目の呼び出しをしようとしても、 +`sort_operations`にもう一度プッシュするための`value`はもう環境にないので、うまくいかないでしょう! +そのため、このクロージャは`FnOnce`のみを実装します。 +このコードをコンパイルしようとすると、クロージャが`FnMut`を実装していなくてはならないので、 +`value`はクロージャの外にムーブすることができない、というエラーが得られます: -環境でクロージャが使用している値の所有権を奪うことをクロージャに強制したいなら、引数リストの前に`move`キーワードを使用できます。 -このテクニックは、新しいスレッドにデータが所有されるように、クロージャを新しいスレッドに渡して、 -データをムーブする際に大概は有用です。 +```console +{{#include ../listings/ch13-functional-features/listing-13-08/output.txt}} +``` -並行性について語る第16章で、`move`クロージャの例はもっと多く出てきます。とりあえず、 -こちらが`move`キーワードがクロージャ定義に追加され、整数の代わりにベクタを使用するリスト13-12からのコードです。 -整数はムーブではなく、コピーされてしまいますからね; このコードはまだコンパイルできないことに注意してください。 +エラーは、クロージャ本体内で、`value`を環境からムーブする行を指しています。 +これを修正するためには、値を環境からムーブしないようにクロージャ本体を変更する必要があります。 +`sort_by_key`が呼ばれる回数を数えるためには、環境内でカウンタを保持し、 +クロージャ本体の中でその値をインクリメントするのが、より自然な方法です。 +リスト13-9のクロージャは、`num_sort_operations`カウンタへの可変参照をキャプチャするだけで、 +そのため複数回呼び出すことができるので、`sort_by_key`で使うことができます: - -以下のようなエラーを受けます: - -```text -error[E0382]: use of moved value: `x` -(エラー: ムーブされた値の使用: `x`) - --> src/main.rs:6:40 - | -4 | let equal_to_x = move |z| z == x; - | -------- value moved (into closure) here - (値はここで(クロージャに)ムーブされた) -5 | -6 | println!("can't use x here: {:?}", x); - | ^ value used here after move - (ムーブ後、値はここで使用された) - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not - implement the `Copy` trait - (注釈: `x`が`std::vec::Vec`という`Copy`トレイトを実装しない型のため、ムーブが起きました) +```rust +{{#rustdoc_include ../listings/ch13-functional-features/listing-13-09/src/main.rs}} ``` -クロージャが定義された際に、クロージャに`x`の値はムーブされています。`move`キーワードを追加したからです。 -そして、クロージャは`x`の所有権を持ち、`main`が`println!`で`x`を使うことはもう叶わないのです。 -`println!`を取り除けば、この例は修正されます。 +リスト13-9: `sort_by_key`で`FnMut`クロージャを使用することは許可される -`Fn`トレイトのどれかを指定するほとんどの場合、`Fn`から始めると、コンパイラがクロージャ本体内で起こっていることにより、 -`FnMut`や`FnOnce`が必要な場合、教えてくれるでしょう。 +クロージャを使用する関数や型を定義または使用するときに、`Fn`系トレイトは重要です。 +次の節では、イテレータについて議論します。多くのイテレータメソッドはクロージャ引数を取るので、 +続けるにあたって、これらのクロージャの詳細のことを覚えておいてください! -環境をキャプチャできるクロージャが関数の引数として有用な場面を説明するために、次のトピックに移りましょう: イテレータです。 +[unwrap-or-else]: https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap_or_else diff --git a/src/ch13-02-iterators.md b/src/ch13-02-iterators.md index 37d630c6a..e0e6d66b0 100644 --- a/src/ch13-02-iterators.md +++ b/src/ch13-02-iterators.md @@ -18,72 +18,63 @@ have to reimplement that logic yourself. Rustにおいて、イテレータは*怠惰*です。つまり、イテレータを使い込んで消費するメソッドを呼ぶまで何の効果もないということです。 -例えば、リスト13-13のコードは、`Vec`に定義された`iter`メソッドを呼ぶことで`v1`ベクタの要素に対するイテレータを生成しています。 +例えば、リスト13-10のコードは、`Vec`に定義された`iter`メソッドを呼ぶことで`v1`ベクタの要素に対するイテレータを生成しています。 このコード単独では、何も有用なことはしません。 ```rust -let v1 = vec![1, 2, 3]; - -let v1_iter = v1.iter(); +{{#rustdoc_include ../listings/ch13-functional-features/listing-13-10/src/main.rs:here}} ``` -リスト13-13: イテレータを生成する +リスト13-10: イテレータを生成する -一旦イテレータを生成したら、いろんな手段で使用することができます。第3章のリスト3-5では、 -ここまで`iter`の呼び出しが何をするかごまかしてきましたが、`for`ループでイテレータを使い、 -各要素に何かコードを実行しています。 +イテレータは`v1_iter`変数に保存されます。一旦イテレータを生成したら、いろんな手段で使用することができます。 +第3章のリスト3-5では、`for`ループを使用して配列を走査し、各要素に対して何らかのコードを実行しました。 +今までそれが正確にはどう機能するのかごまかしてきましたが、裏で暗黙にイテレータを作成して消費していたのです。 -リスト13-14の例は、イテレータの生成と`for`ループでイテレータを使用することを区別しています。 -イテレータは、`v1_iter`変数に保存され、その時には繰り返しは起きていません。`v1_iter`のイテレータで、 -`for`ループが呼び出された時に、イテレータの各要素がループの繰り返しで使用され、各値が出力されます。 +リスト13-11の例では、イテレータの生成と`for`ループでイテレータを使用することを区別しています。 +`v1_iter`のイテレータで`for`ループが呼び出された時に、イテレータの各要素がループの繰り返しで使用され、各値が出力されます。 ```rust -let v1 = vec![1, 2, 3]; - -let v1_iter = v1.iter(); - -for val in v1_iter { - // {}でした - println!("Got: {}", val); -} +{{#rustdoc_include ../listings/ch13-functional-features/listing-13-11/src/main.rs:here}} ``` -リスト13-14: `for`ループでイテレータを使用する +リスト13-11: `for`ループでイテレータを使用する 標準ライブラリにより提供されるイテレータが存在しない言語では、変数を添え字0から始め、 @@ -152,12 +143,12 @@ The `Iterator` trait only requires implementors to define one method: the これは1度に`Some`に包まれたイテレータの1要素を返し、繰り返しが終わったら、`None`を返します。 -イテレータに対して直接`next`メソッドを呼び出すこともできます; リスト13-15は、 +イテレータに対して直接`next`メソッドを呼び出すこともできます; リスト13-12は、 ベクタから生成されたイテレータの`next`を繰り返し呼び出した時にどんな値が返るかを模擬しています。 -リスト13-15: イテレータに対して`next`メソッドを呼び出す +リスト13-12: イテレータに対して`next`メソッドを呼び出す @@ -242,14 +223,14 @@ Methods that call `next` are called *consuming adaptors*, because calling them uses up the iterator. One example is the `sum` method, which takes ownership of the iterator and iterates through the items by repeatedly calling `next`, thus consuming the iterator. As it iterates through, it adds each item to a running -total and returns the total when iteration is complete. Listing 13-16 has a +total and returns the total when iteration is complete. Listing 13-13 has a test illustrating a use of the `sum` method: --> `next`を呼び出すメソッドは、*消費アダプタ*(consuming adaptors)と呼ばれます。呼び出しがイテレータの使い込みになるからです。 一例は、`sum`メソッドで、これはイテレータの所有権を奪い、`next`を繰り返し呼び出すことで要素を繰り返し、 故にイテレータを消費するのです。繰り返しが進むごとに、各要素を一時的な合計に追加し、 -繰り返しが完了したら、その合計を返します。リスト13-16は、`sum`の使用を説明したテストです: +繰り返しが完了したら、その合計を返します。リスト13-13は、`sum`の使用を説明したテストです: -リスト13-16: `sum`メソッドを呼び出してイテレータの全要素の合計を得る +リスト13-13: `sum`メソッドを呼び出してイテレータの全要素の合計を得る -`Iterator`トレイトに定義された他のメソッドは、*イテレータアダプタ*(iterator adaptors)として知られていますが、 -イテレータを別の種類のイテレータに変えさせてくれます。イテレータアダプタを複数回呼ぶ呼び出しを連結して、 -複雑な動作を読みやすい形で行うことができます。ですが、全てのイテレータは怠惰なので、消費アダプタメソッドのどれかを呼び出し、 -イテレータアダプタの呼び出しから結果を得なければなりません。 +*イテレータアダプタ*(iterator adaptors)は、`Iterator`トレイト上で定義されたメソッドのうち、イテレータを消費しないものです。 +これらはイテレータを消費しない代わりに、元のイテレータの一部の様相を変更することによって、別のイテレータを生成します。 -リスト13-17は、イテレータアダプタメソッドの`map`の呼び出し例を示し、各要素に対して呼び出すクロージャを取り、 -新しいイテレータを生成します。ここのクロージャは、ベクタの各要素が1インクリメントされる新しいイテレータを作成します。 -ところが、このコードは警告を発します: +リスト13-14は、イテレータアダプタメソッドの`map`の呼び出し例を示しています。 +`map`は、各要素が反復処理されるときに、その要素に対して呼び出すクロージャを取ります。 +`map`メソッドは、修正された要素を生成する新しいイテレータを返します。 +`map`新しいイテレータを生成します。ここのクロージャは、ベクタの各要素が1インクリメントされる新しいイテレータを作成します: -リスト13-17: イテレータアダプタの`map`を呼び出して新規イテレータを作成する +リスト13-14: イテレータアダプタの`map`を呼び出して新規イテレータを作成する -出る警告は以下の通りです: +ところが、このコードは警告を発します: -```text -warning: unused `std::iter::Map` which must be used: iterator adaptors are lazy -and do nothing unless consumed -(警告: 使用されねばならない`std::iter::Map`が未使用です: イテレータアダプタは怠惰で、 -消費されるまで何もしません) - --> src/main.rs:4:5 - | -4 | v1.iter().map(|x| x + 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: #[warn(unused_must_use)] on by default +```console +{{#include ../listings/ch13-functional-features/listing-13-14/output.txt}} ``` -リスト13-17のコードは何もしません; 指定したクロージャは、決して呼ばれないのです。警告が理由を思い出させてくれています: +リスト13-14のコードは何もしません; 指定したクロージャは、決して呼ばれないのです。警告が理由を思い出させてくれています: イテレータアダプタは怠惰で、ここでイテレータを消費する必要があるのです。 -これを修正し、イテレータを消費するには、`collect`メソッドを使用しますが、これは第12章のリスト12-1で`env::args`とともに使用しました。 +この警告を修正し、イテレータを消費するには、`collect`メソッドを使用しますが、これは第12章のリスト12-1で`env::args`とともに使用しました。 このメソッドはイテレータを消費し、結果の値をコレクションデータ型に集結させます。 -リスト13-18において、`map`呼び出しから返ってきたイテレータを繰り返した結果をベクタに集結させています。 +リスト13-15において、`map`呼び出しから返ってきたイテレータを繰り返した結果をベクタに集結させています。 このベクタは、最終的に元のベクタの各要素に1を足したものが含まれます。 -リスト13-18: `map`メソッドを呼び出して新規イテレータを作成し、 +リスト13-15: `map`メソッドを呼び出して新規イテレータを作成し、 それから`collect`メソッドを呼び出してその新規イテレータを消費し、ベクタを生成する @@ -413,6 +369,15 @@ provides. これは、`Iterator`トレイトが提供する繰り返し動作を再利用しつつ、 クロージャにより一部の動作をカスタマイズできる好例になっています。 + + +複雑な操作を可読性の高い方法で行うために、イテレータアダプタの呼び出しを複数チェーンすることができます。 +ですが、すべてのイテレータは怠惰なので、イテレータアダプタの呼び出しから結果を得るには、消費アダプタメソッドのうちいずれかを呼ぶ必要があります。 + @@ -420,26 +385,32 @@ provides. ### 環境をキャプチャするクロージャを使用する + +多くのイテレータアダプタは引数としてクロージャを取り、また、イテレータアダプタに引数として指定するクロージャは、 +環境をキャプチャするクロージャであることは、よくあることでしょう。 + + -イテレータが出てきたので、`filter`イテレータアダプタを使って環境をキャプチャするクロージャの一般的な使用をデモすることができます。 -イテレータの`filter`メソッドは、イテレータの各要素を取り、論理値を返すクロージャを取ります。 -このクロージャが`true`を返せば、`filter`が生成するイテレータにその値が含まれます。クロージャが`false`を返したら、 -結果のイテレータにその値は含まれません。 +この例では、クロージャを取る`filter`メソッドを使用します。クロージャは、イテレータからの要素を取り、`bool`を返すクロージャです。 +このクロージャが`true`を返せば、`filter`が生成する繰り返し処理にその値が含まれます。クロージャが`false`を返したら、 +その値は含まれません。 -リスト13-19では、環境から`shoe_size`変数をキャプチャするクロージャで`filter`を使って、 +リスト13-16では、環境から`shoe_size`変数をキャプチャするクロージャで`filter`を使って、 `Shoe`構造体インスタンスのコレクションを繰り返しています。指定したサイズの靴だけを返すわけです。 -リスト13-19: `shoe_size`をキャプチャするクロージャで`filter`メソッドを使用する +リスト13-16: `shoe_size`をキャプチャするクロージャで`filter`メソッドを使用する -`shoes_in_my_size`関数は、引数として靴のベクタとサイズの所有権を奪います。指定されたサイズの靴だけを含むベクタを返します。 +`shoes_in_size`関数は、引数として靴のベクタとサイズの所有権を奪います。指定されたサイズの靴だけを含むベクタを返します。 -`shoes_in_my_size`の本体で、`into_iter`を呼び出してベクタの所有権を奪うイテレータを作成しています。 +`shoes_in_size`の本体で、`into_iter`を呼び出してベクタの所有権を奪うイテレータを作成しています。 そして、`filter`を呼び出してそのイテレータをクロージャが`true`を返した要素だけを含む新しいイテレータに適合させます。 -`shoes_in_my_size`を呼び出した時に、指定した値と同じサイズの靴だけが得られることをテストは示しています。 - - - -### `Iterator`トレイトで独自のイテレータを作成する - - - -ベクタに対し、`iter`、`into_iter`、`iter_mut`を呼び出すことでイテレータを作成できることを示してきました。 -ハッシュマップなどの標準ライブラリの他のコレクション型からもイテレータを作成できます。 -`Iterator`トレイトを自分で実装することで、したいことを何でもするイテレータを作成することもできます。 -前述の通り、定義を提供する必要のある唯一のメソッドは、`next`メソッドなのです。一旦、そうしてしまえば、 -`Iterator`トレイトが用意しているデフォルト実装のある他の全てのメソッドを使うことができるのです! - - - -デモ用に、絶対に1から5をカウントするだけのイテレータを作成しましょう。まず、値を保持する構造体を生成し、 -`Iterator`トレイトを実装することでこの構造体をイテレータにし、その実装内の値を使用します。 - - - -リスト13-20は、`Counter`構造体と`Counter`のインスタンスを作る`new`関連関数の定義です: - - - -ファイル名: src/lib.rs - -```rust -struct Counter { - count: u32, -} - -impl Counter { - fn new() -> Counter { - Counter { count: 0 } - } -} -``` - - - -リスト13-20: `Counter`構造体と`count`に対して0という初期値で`Counter`のインスタンスを作る`new`関数を定義する - - - -`Counter`構造体には、`count`というフィールドがあります。このフィールドは、 -1から5までの繰り返しのどこにいるかを追いかける`u32`値を保持しています。`Counter`の実装にその値を管理してほしいので、 -`count`フィールドは非公開です。`count`フィールドは常に0という値から新規インスタンスを開始するという動作を`new`関数は強要します。 - - - -次に、`next`メソッドの本体をこのイテレータが使用された際に起きてほしいことを指定するように定義して、 -`Counter`型に対して`Iterator`トレイトを実装します。リスト13-21のようにですね: - - - -ファイル名: src/lib.rs - -```rust -# struct Counter { -# count: u32, -# } -# -impl Iterator for Counter { - type Item = u32; - - fn next(&mut self) -> Option { - self.count += 1; - - if self.count < 6 { - Some(self.count) - } else { - None - } - } -} -``` - - - -リスト13-21: `Counter`構造体に`Iterator`トレイトを実装する - - - -イテレータの`Item`関連型を`u32`に設定しました。つまり、イテレータは、`u32`の値を返します。 -ここでも、まだ関連型について心配しないでください。第19章で講義します。 - - - -イテレータに現在の状態に1を足してほしいので、まず1を返すように`count`を0に初期化しました。 -`count`の値が5以下なら、`next`は`Some`に包まれた現在の値を返しますが、 -`count`が6以上なら、イテレータは`None`を返します。 - - - -#### `Counter`イテレータの`next`メソッドを使用する - - - -一旦`Iterator`トレイトを実装し終わったら、イテレータの出来上がりです!リスト13-22は、 -リスト13-15のベクタから生成したイテレータと全く同様に、直接`next`メソッドを呼び出すことで、 -`Counter`構造体のイテレータ機能を使用できることをデモするテストを示しています。 - - - -ファイル名: src/lib.rs - -```rust -# struct Counter { -# count: u32, -# } -# -# impl Iterator for Counter { -# type Item = u32; -# -# fn next(&mut self) -> Option { -# self.count += 1; -# -# if self.count < 6 { -# Some(self.count) -# } else { -# None -# } -# } -# } -# -#[test] -fn calling_next_directly() { - let mut counter = Counter::new(); - - assert_eq!(counter.next(), Some(1)); - assert_eq!(counter.next(), Some(2)); - assert_eq!(counter.next(), Some(3)); - assert_eq!(counter.next(), Some(4)); - assert_eq!(counter.next(), Some(5)); - assert_eq!(counter.next(), None); -} -``` - - - -リスト13-22: `next`メソッド実装の機能をテストする - - - -このテストは、`counter`変数に新しい`Counter`インスタンスを生成し、 -それからイテレータにほしい動作が実装し終わっていることを実証しながら、`next`を繰り返し呼び出しています: -1から5の値を返すことです。 - - - -#### 他の`Iterator`トレイトメソッドを使用する - - - -`next`メソッドを定義して`Iterator`トレイトを実装したので、今では、標準ライブラリで定義されているように、 -どんな`Iterator`トレイトメソッドのデフォルト実装も使えるようになりました。全て`next`メソッドの機能を使っているからです。 - - - -例えば、何らかの理由で、`Counter`インスタンスが生成する値を取り、最初の値を飛ばしてから、 -別の`Counter`インスタンスが生成する値と一組にし、各ペアを掛け算し、3で割り切れる結果だけを残し、 -全結果の値を足し合わせたくなったら、リスト13-23のテストに示したように、そうすることができます: - - - -ファイル名: src/lib.rs - - - -```rust -# struct Counter { -# count: u32, -# } -# -# impl Counter { -# fn new() -> Counter { -# Counter { count: 0 } -# } -# } -# -# impl Iterator for Counter { -# // このイテレータはu32を生成します -# // Our iterator will produce u32s -# type Item = u32; -# -# fn next(&mut self) -> Option { -# // カウントをインクリメントする。故に0から始まる -# // increment our count. This is why we started at zero. -# self.count += 1; -# -# // カウントが終わったかどうか確認する -# // check to see if we've finished counting or not. -# if self.count < 6 { -# Some(self.count) -# } else { -# None -# } -# } -# } -# -#[test] -fn using_other_iterator_trait_methods() { - let sum: u32 = Counter::new().zip(Counter::new().skip(1)) - .map(|(a, b)| a * b) - .filter(|x| x % 3 == 0) - .sum(); - assert_eq!(18, sum); -} -``` - - - -リスト13-23: `Counter`イテレータに対していろんな`Iterator`トレイトのメソッドを使用する - - - -`zip`は4組しか生成しないことに注意してください; 理論的な5番目の組の`(5, None)`は、 -入力イテレータのどちらかが`None`を返したら、`zip`は`None`を返却するため、決して生成されることはありません。 - - - -`next`メソッドの動作方法を指定し、標準ライブラリが`next`を呼び出す他のメソッドにデフォルト実装を提供しているので、 -これらのメソッド呼び出しは全て可能です。 +`shoes_in_size`を呼び出した時に、指定した値と同じサイズの靴だけが得られることをテストは示しています。 diff --git a/src/ch13-03-improving-our-io-project.md b/src/ch13-03-improving-our-io-project.md index a722b106e..b8d95e2d1 100644 --- a/src/ch13-03-improving-our-io-project.md +++ b/src/ch13-03-improving-our-io-project.md @@ -13,11 +13,11 @@ With this new knowledge about iterators, we can improve the I/O project in Chapter 12 by using iterators to make places in the code clearer and more concise. Let’s look at how iterators can improve our implementation of the -`Config::new` function and the `search` function. +`Config::build` function and the `search` function. --> このイテレータに関する新しい知識があれば、イテレータを使用してコードのいろんな場所をより明確で簡潔にすることで、 -第12章の入出力プロジェクトを改善することができます。イテレータが`Config::new`関数と`search`関数の実装を改善する方法に目を向けましょう。 +第12章の入出力プロジェクトを改善することができます。イテレータが`Config::build`関数と`search`関数の実装を改善する方法に目を向けましょう。 リスト12-6において、スライスに添え字アクセスして値をクローンすることで、`Config`構造体に値を所有させながら、 -`String`値のスライスを取り、`Config`構造体のインスタンスを作るコードを追記しました。リスト13-24では、 -リスト12-23のような`Config::new`の実装を再現しました: +`String`値のスライスを取り、`Config`構造体のインスタンスを作るコードを追記しました。リスト13-17では、 +リスト12-23のような`Config::build`の実装を再現しました: -リスト13-24: リスト12-23から`Config::new`関数の再現 +リスト13-17: リスト12-23から`Config::build`関数の再現 引数`args`に`String`要素のスライスがあるためにここで`clone`が必要だったのですが、 -`new`関数は`args`を所有していません。`Config`インスタンスの所有権を返すためには、 -`Config`インスタンスがその値を所有できるように、`Config`の`query`と`filename`フィールドから値をクローンしなければなりませんでした。 +`build`関数は`args`を所有していません。`Config`インスタンスの所有権を返すためには、 +`Config`インスタンスがその値を所有できるように、`Config`の`query`と`file_path`フィールドから値をクローンしなければなりませんでした。 -イテレータについての新しい知識があれば、`new`関数をスライスを借用する代わりに、 +イテレータについての新しい知識があれば、`build`関数をスライスを借用する代わりに、 引数としてイテレータの所有権を奪うように変更することができます。スライスの長さを確認し、 特定の場所に添え字アクセスするコードの代わりにイテレータの機能を使います。これにより、 -イテレータは値にアクセスするので、`Config::new`関数がすることが明確化します。 +イテレータは値にアクセスするので、`Config::build`関数がすることが明確化します。 -ひとたび、`Config::new`がイテレータの所有権を奪い、借用する添え字アクセス処理をやめたら、 +ひとたび、`Config::build`がイテレータの所有権を奪い、借用する添え字アクセス処理をやめたら、 `clone`を呼び出して新しくメモリ確保するのではなく、イテレータからの`String`値を`Config`にムーブできます。 -リスト12-24のような`main`関数の冒頭をリスト13-25のコードに変更します。 -これは、`Config::new`も更新するまでコンパイルできません。 +まずはリスト12-24のような`main`関数の冒頭を、今回はイテレータを使用するリスト13-18のコードに変更します。 +これは、`Config::build`も更新するまでコンパイルできません。 -リスト13-25: `env::args`の戻り値を`Config::new`に渡す +リスト13-18: `env::args`の戻り値を`Config::build`に渡す -`env::args`関数は、イテレータを返します!イテレータの値をベクタに集結させ、それからスライスを`Config::new`に渡すのではなく、 -今では`env::args`から返ってくるイテレータの所有権を直接`Config::new`に渡しています。 - -次に、`Config::new`の定義を更新する必要があります。入出力プロジェクトの*src/lib.rs*ファイルで、 -`Config::new`のシグニチャをリスト13-26のように変えましょう。関数本体を更新する必要があるので、 +次に、`Config::build`の定義を更新する必要があります。入出力プロジェクトの*src/lib.rs*ファイルで、 +`Config::build`のシグニチャをリスト13-19のように変えましょう。関数本体を更新する必要があるので、 それでもコンパイルはできません。 -リスト13-26: `Config::new`のシグニチャをイテレータを期待するように更新する +リスト13-19: `Config::build`のシグニチャをイテレータを期待するように更新する + +`env::args`関数の標準ライブラリドキュメントは、この関数が返すイテレータの型は`std::env::Args`であること、 +そしてこの型は`String`値を返す`Iterator`トレイトを実装していることを示しています。 + + + +引数`args`の型が`&[String]`ではなく、トレイト境界`impl Iterator`を持つジェネリック型を持つように、 +`Config::build`関数のシグニチャを更新しています。第10章の[「引数としてのトレイト」][impl-trait]節で議論した`impl Trait`構文のここでの使用は、 +`args`は`Iterator`型を実装し`String`要素を返す任意の型でよいことを意味します。 + + + -`env::args`関数の標準ライブラリドキュメントは、自身が返すイテレータの型は、`std::env::Args`であると表示しています。 -`Config::new`関数のシグニチャを更新したので、引数`args`の型は、`&[String]`ではなく、 -`std::env::Args`になりました。`args`の所有権を奪い、繰り返しを行うことで`args`を可変化する予定なので、 +`args`の所有権を奪い、繰り返しを行うことで`args`を可変化する予定なので、 `args`引数の仕様に`mut`キーワードを追記でき、可変にします。 -次に、`Config::new`の本体を修正しましょう。標準ライブラリのドキュメントは、 -`std::env::Args`が`Iterator`トレイトを実装していることにも言及しているので、 -それに対して`next`メソッドを呼び出せることがわかります!リスト13-27は、 +次に、`Config::build`の本体を修正しましょう。`args`は`Iterator`トレイトを実装しているので、 +それに対して`next`メソッドを呼び出せることがわかります!リスト13-20は、 リスト12-23のコードを`next`メソッドを使用するように更新したものです: -リスト13-27: `Config::new`の本体をイテレータメソッドを使うように変更する +リスト13-20: `Config::build`の本体をイテレータメソッドを使うように変更する `env::args`の戻り値の1番目の値は、プログラム名であることを思い出してください。それは無視し、 次の値を取得したいので、まず`next`を呼び出し、戻り値に対して何もしません。2番目に、 `next`を呼び出して`Config`の`query`フィールドに置きたい値を得ます。`next`が`Some`を返したら、 `match`を使用してその値を抜き出します。`None`を返したら、十分な引数が与えられなかったということなので、 -`Err`値で早期リターンします。`filename`値に対しても同じことをします。 +`Err`値で早期リターンします。`file_path`値に対しても同じことをします。 入出力プロジェクトの`search`関数でも、イテレータを活用することができます。その関数はリスト12-19に示していますが、以下のリスト13-28に再掲します。 @@ -334,25 +287,15 @@ project, which is reproduced here in Listing 13-28 as it was in Listing 12-19: ファイル名: src/lib.rs ```rust,ignore -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { - let mut results = Vec::new(); - - for line in contents.lines() { - if line.contains(query) { - results.push(line); - } - } - - results -} +{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-19/src/lib.rs:ch13}} ``` -リスト13-28: リスト12-19の`search`関数の実装 +リスト13-21: リスト12-19の`search`関数の実装 イテレータアダプタメソッドを使用して、このコードをもっと簡潔に書くことができます。そうすれば、 可変な中間の`results`ベクタをなくすこともできます。関数型プログラミングスタイルは、可変な状態の量を最小化することを好み、 コードを明瞭化します。可変な状態を除去すると、検索を同時並行に行うという将来的な改善をするのが、 可能になる可能性があります。なぜなら、`results`ベクタへの同時アクセスを管理する必要がなくなるからです。 -リスト13-29は、この変更を示しています: +リスト13-22は、この変更を示しています: -リスト13-29: `search`関数の実装でイテレータアダプタのメソッドを使用する +リスト13-22: `search`関数の実装でイテレータアダプタのメソッドを使用する `search`関数の目的は、`query`を含む`contents`の行全てを返すことであることを思い出してください。 -リスト13-19の`filter`例に酷似して、このコードは`filter`アダプタを使用して`line.contains(query)`が真を返す行だけを残すことができます。 +リスト13-16の`filter`例に酷似して、このコードは`filter`アダプタを使用して`line.contains(query)`が`true`を返す行だけを残すことができます。 それから、合致した行を別のベクタに`collect`で集結させます。ずっと単純です!ご自由に、 同じ変更を行い、`search_case_insensitive`関数でもイテレータメソッドを使うようにしてください。 + + +### ループかイテレータかの選択 + -次の論理的な疑問は、自身のコードでどちらのスタイルを選ぶかと理由です: リスト13-28の元の実装とリスト13-29のイテレータを使用するバージョンです。 +次の論理的な疑問は、自身のコードでどちらのスタイルを選ぶかと理由です: リスト13-21の元の実装とリスト13-22のイテレータを使用するバージョンです。 多くのRustプログラマは、イテレータスタイルを好みます。とっかかりが少し困難ですが、 いろんなイテレータアダプタとそれがすることの感覚を一度掴めれば、イテレータの方が理解しやすいこともあります。 いろんなループを少しずつもてあそんだり、新しいベクタを構築する代わりに、コードは、ループの高難度の目的に集中できるのです。 @@ -433,3 +378,9 @@ performance. ですが、本当に2つの実装は等価なのでしょうか?直観的な仮説は、より低レベルのループの方がより高速ということかもしれません。 パフォーマンスに触れましょう。 + + + +[impl-trait]: ch10-02-traits.html#引数としてのトレイト diff --git a/src/ch13-04-performance.md b/src/ch13-04-performance.md index 45ea29cf0..418a02a6a 100644 --- a/src/ch13-04-performance.md +++ b/src/ch13-04-performance.md @@ -5,13 +5,13 @@ ## パフォーマンス比較: ループVSイテレータ -ループを使うべきかイテレータを使うべきか決定するために、`search`関数のうち、どちらのバージョンが速いか知る必要があります: -明示的な`for`ループがあるバージョンと、イテレータのバージョンです。 +ループを使うべきかイテレータを使うべきか決定するために、どちらの実装が速いか知る必要があります: +明示的な`for`ループを使うバージョンの`search`関数と、イテレータを使うバージョンです。 -より包括的なベンチマークとするためには、いろんなサイズの様々なテキストを`contents`として、異なる単語、異なる長さの単語を`query`として、 +より包括的なベンチマークとするためには、いろんなサイズの様々なテキストを`contents`として使用して、異なる単語、異なる長さの単語を`query`として、 他のあらゆる種類のバリエーションを確認するべきです。重要なのは: イテレータは、 高度な抽象化にも関わらず、低レベルのコードを自身で書いているかのように、ほぼ同じコードにコンパイルされることです。 イテレータは、Rustの*ゼロコスト抽象化*の一つであり、これは、抽象化を使うことが追加の実行時オーバーヘッドを生まないことを意味しています。 @@ -78,7 +78,7 @@ code uses an iterator chain to do some math on three variables in scope: a to shift data in `qlp_shift`. We’ve declared the variables within this example but not given them any values; although this code doesn’t have much meaning outside of its context, it’s still a concise, real-world example of how Rust -translates high-level ideas to low-level code: +translates high-level ideas to low-level code. --> 別の例として、以下のコードは、オーディオデコーダから取ってきました。デコードアルゴリズムは、 @@ -86,7 +86,7 @@ translates high-level ideas to low-level code: イテレータ連結をしてスコープにある3つの変数に計算を行っています: `buffer`というデータのスライス、 12の`coefficients`(係数)の配列、`qlp_shift`でデータをシフトする量です。この例の中で変数を宣言しましたが、 値は与えていません; このコードは、文脈の外では大して意味を持ちませんが、 -それでもRustが高レベルな考えを低レベルなコードに翻訳する簡潔で現実的な例になっています: +それでもRustが高レベルな考えを低レベルなコードに翻訳する簡潔で現実的な例になっています。 ```rust,ignore let buffer: &mut [i32]; From 2296c28ec5945a6a52380ad3050480c93da188b8 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:06 +0900 Subject: [PATCH 15/22] =?UTF-8?q?ch14=20Cargo=E3=81=A8Crates.io=E3=81=AB?= =?UTF-8?q?=E3=81=A4=E3=81=84=E3=81=A6=E3=82=88=E3=82=8A=E8=A9=B3=E3=81=97?= =?UTF-8?q?=E3=81=8F=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0?= =?UTF-8?q?=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-14-01/Cargo.toml | 3 +- .../listing-14-01/src/lib.rs | 1 + .../listing-14-02/Cargo.toml | 3 +- .../listing-14-02/src/lib.rs | 5 +- .../listing-14-03/Cargo.toml | 3 +- .../listing-14-03/src/lib.rs | 11 +- .../listing-14-04/Cargo.toml | 3 +- .../listing-14-05/Cargo.toml | 3 +- .../listing-14-06/Cargo.toml | 3 +- .../listing-14-07/add/Cargo.lock | 4 +- .../listing-14-07/add/Cargo.toml | 2 +- .../listing-14-07/add/add-one/Cargo.toml | 7 - .../listing-14-07/add/add_one/Cargo.toml | 6 + .../add/{add-one => add_one}/src/lib.rs | 0 .../listing-14-07/add/adder/Cargo.toml | 5 +- .../listing-14-07/add/adder/src/main.rs | 7 +- .../add/adder/Cargo.toml | 3 +- .../add/Cargo.lock | 4 +- .../add/Cargo.toml | 2 +- .../add/add-one/Cargo.toml | 7 - .../add/add_one/Cargo.toml | 6 + .../add/{add-one => add_one}/src/lib.rs | 0 .../add/adder/Cargo.toml | 6 +- .../add/Cargo.lock | 84 ++- .../add/Cargo.toml | 2 +- .../add/add-one/Cargo.toml | 8 - .../add/add_one/Cargo.toml | 7 + .../add/{add-one => add_one}/src/lib.rs | 0 .../add/adder/Cargo.toml | 5 +- .../add/adder/src/main.rs | 1 + .../add/Cargo.lock | 4 +- .../add/Cargo.toml | 2 +- .../add/add-one/Cargo.toml | 7 - .../add/add_one/Cargo.toml | 6 + .../add/{add-one => add_one}/src/lib.rs | 0 .../add/adder/Cargo.toml | 5 +- .../output-only-01-adder-crate/add/Cargo.lock | 5 + .../output-only-02-add-one/add/.gitignore | 1 - .../output-only-02-add-one/add/Cargo.lock | 4 +- .../output-only-02-add-one/add/Cargo.toml | 2 +- .../add/add-one/src/lib.rs | 7 - .../add/{add-one => add_one}/Cargo.toml | 5 +- .../add/add_one/src/lib.rs | 14 + .../add/adder/Cargo.toml | 5 +- .../output-only-03-use-rand/add/Cargo.lock | 84 ++- .../output-only-03-use-rand/add/Cargo.toml | 2 +- .../add/add-one/Cargo.toml | 8 - .../add/add_one/Cargo.toml | 7 + .../add/{add-one => add_one}/src/lib.rs | 0 .../add/adder/Cargo.toml | 5 +- src/ch14-00-more-about-cargo.md | 14 +- src/ch14-01-release-profiles.md | 64 +-- src/ch14-02-publishing-to-crates-io.md | 477 ++++++++---------- src/ch14-03-cargo-workspaces.md | 464 +++++++++-------- src/ch14-04-installing-binaries.md | 56 +- src/ch14-05-extending-cargo.md | 10 +- 56 files changed, 713 insertions(+), 746 deletions(-) delete mode 100644 listings/ch14-more-about-cargo/listing-14-07/add/add-one/Cargo.toml create mode 100644 listings/ch14-more-about-cargo/listing-14-07/add/add_one/Cargo.toml rename listings/ch14-more-about-cargo/listing-14-07/add/{add-one => add_one}/src/lib.rs (100%) delete mode 100644 listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add-one/Cargo.toml create mode 100644 listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add_one/Cargo.toml rename listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/{add-one => add_one}/src/lib.rs (100%) delete mode 100644 listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add-one/Cargo.toml create mode 100644 listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add_one/Cargo.toml rename listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/{add-one => add_one}/src/lib.rs (100%) delete mode 100644 listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add-one/Cargo.toml create mode 100644 listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add_one/Cargo.toml rename listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/{add-one => add_one}/src/lib.rs (100%) create mode 100644 listings/ch14-more-about-cargo/output-only-01-adder-crate/add/Cargo.lock delete mode 100644 listings/ch14-more-about-cargo/output-only-02-add-one/add/.gitignore delete mode 100644 listings/ch14-more-about-cargo/output-only-02-add-one/add/add-one/src/lib.rs rename listings/ch14-more-about-cargo/output-only-02-add-one/add/{add-one => add_one}/Cargo.toml (65%) create mode 100644 listings/ch14-more-about-cargo/output-only-02-add-one/add/add_one/src/lib.rs delete mode 100644 listings/ch14-more-about-cargo/output-only-03-use-rand/add/add-one/Cargo.toml create mode 100644 listings/ch14-more-about-cargo/output-only-03-use-rand/add/add_one/Cargo.toml rename listings/ch14-more-about-cargo/output-only-03-use-rand/add/{add-one => add_one}/src/lib.rs (100%) diff --git a/listings/ch14-more-about-cargo/listing-14-01/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-01/Cargo.toml index 716953ae1..c52da0412 100644 --- a/listings/ch14-more-about-cargo/listing-14-01/Cargo.toml +++ b/listings/ch14-more-about-cargo/listing-14-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "my_crate" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch14-more-about-cargo/listing-14-01/src/lib.rs b/listings/ch14-more-about-cargo/listing-14-01/src/lib.rs index ed7abb727..5ed7e8e64 100644 --- a/listings/ch14-more-about-cargo/listing-14-01/src/lib.rs +++ b/listings/ch14-more-about-cargo/listing-14-01/src/lib.rs @@ -1,4 +1,5 @@ /// Adds one to the number given. +/// 与えられた数値に1を足す。 /// /// # Examples /// diff --git a/listings/ch14-more-about-cargo/listing-14-02/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-02/Cargo.toml index 716953ae1..c52da0412 100644 --- a/listings/ch14-more-about-cargo/listing-14-02/Cargo.toml +++ b/listings/ch14-more-about-cargo/listing-14-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "my_crate" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch14-more-about-cargo/listing-14-02/src/lib.rs b/listings/ch14-more-about-cargo/listing-14-02/src/lib.rs index 64c9c439c..66da390f1 100644 --- a/listings/ch14-more-about-cargo/listing-14-02/src/lib.rs +++ b/listings/ch14-more-about-cargo/listing-14-02/src/lib.rs @@ -3,7 +3,10 @@ //! //! `my_crate` is a collection of utilities to make performing certain //! calculations more convenient. - +//! +//! # 自分のクレート +//! +//! `my_crate`は、ユーティリティの集まりであり、特定の計算をより便利に行うことができます。 /// Adds one to the number given. // --snip-- // ANCHOR_END: here diff --git a/listings/ch14-more-about-cargo/listing-14-03/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-03/Cargo.toml index a2e9e369b..66ef4b532 100644 --- a/listings/ch14-more-about-cargo/listing-14-03/Cargo.toml +++ b/listings/ch14-more-about-cargo/listing-14-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "art" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch14-more-about-cargo/listing-14-03/src/lib.rs b/listings/ch14-more-about-cargo/listing-14-03/src/lib.rs index 00a81c508..893ba8037 100644 --- a/listings/ch14-more-about-cargo/listing-14-03/src/lib.rs +++ b/listings/ch14-more-about-cargo/listing-14-03/src/lib.rs @@ -2,9 +2,14 @@ //! # Art //! //! A library for modeling artistic concepts. +//! +//! # 芸術 +//! +//! 芸術的な概念をモデル化するライブラリ。 pub mod kinds { /// The primary colors according to the RYB color model. + /// RYBカラーモデルによる主色。 pub enum PrimaryColor { Red, Yellow, @@ -12,6 +17,7 @@ pub mod kinds { } /// The secondary colors according to the RYB color model. + /// RYBカラーモデルによる副色。 pub enum SecondaryColor { Orange, Green, @@ -24,13 +30,12 @@ pub mod utils { /// Combines two primary colors in equal amounts to create /// a secondary color. + /// 2つの主色を同じ割合で混合し、副色にする。 pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor { // --snip-- // ANCHOR_END: here - SecondaryColor::Orange + unimplemented!(); // ANCHOR: here } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch14-more-about-cargo/listing-14-04/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-04/Cargo.toml index a2e9e369b..66ef4b532 100644 --- a/listings/ch14-more-about-cargo/listing-14-04/Cargo.toml +++ b/listings/ch14-more-about-cargo/listing-14-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "art" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch14-more-about-cargo/listing-14-05/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-05/Cargo.toml index a2e9e369b..66ef4b532 100644 --- a/listings/ch14-more-about-cargo/listing-14-05/Cargo.toml +++ b/listings/ch14-more-about-cargo/listing-14-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "art" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch14-more-about-cargo/listing-14-06/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-06/Cargo.toml index a2e9e369b..66ef4b532 100644 --- a/listings/ch14-more-about-cargo/listing-14-06/Cargo.toml +++ b/listings/ch14-more-about-cargo/listing-14-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "art" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch14-more-about-cargo/listing-14-07/add/Cargo.lock b/listings/ch14-more-about-cargo/listing-14-07/add/Cargo.lock index 77292f614..a456055c9 100644 --- a/listings/ch14-more-about-cargo/listing-14-07/add/Cargo.lock +++ b/listings/ch14-more-about-cargo/listing-14-07/add/Cargo.lock @@ -1,13 +1,13 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "add-one" +name = "add_one" version = "0.1.0" [[package]] name = "adder" version = "0.1.0" dependencies = [ - "add-one 0.1.0", + "add_one 0.1.0", ] diff --git a/listings/ch14-more-about-cargo/listing-14-07/add/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-07/add/Cargo.toml index d26e7cfb4..1448801d5 100644 --- a/listings/ch14-more-about-cargo/listing-14-07/add/Cargo.toml +++ b/listings/ch14-more-about-cargo/listing-14-07/add/Cargo.toml @@ -2,5 +2,5 @@ members = [ "adder", - "add-one", + "add_one", ] diff --git a/listings/ch14-more-about-cargo/listing-14-07/add/add-one/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-07/add/add-one/Cargo.toml deleted file mode 100644 index 8260fb541..000000000 --- a/listings/ch14-more-about-cargo/listing-14-07/add/add-one/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "add-one" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch14-more-about-cargo/listing-14-07/add/add_one/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-07/add/add_one/Cargo.toml new file mode 100644 index 000000000..8af4ab816 --- /dev/null +++ b/listings/ch14-more-about-cargo/listing-14-07/add/add_one/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "add_one" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch14-more-about-cargo/listing-14-07/add/add-one/src/lib.rs b/listings/ch14-more-about-cargo/listing-14-07/add/add_one/src/lib.rs similarity index 100% rename from listings/ch14-more-about-cargo/listing-14-07/add/add-one/src/lib.rs rename to listings/ch14-more-about-cargo/listing-14-07/add/add_one/src/lib.rs diff --git a/listings/ch14-more-about-cargo/listing-14-07/add/adder/Cargo.toml b/listings/ch14-more-about-cargo/listing-14-07/add/adder/Cargo.toml index e73f1beca..feb3d956e 100644 --- a/listings/ch14-more-about-cargo/listing-14-07/add/adder/Cargo.toml +++ b/listings/ch14-more-about-cargo/listing-14-07/add/adder/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] -add-one = { path = "../add-one" } +add_one = { path = "../add_one" } diff --git a/listings/ch14-more-about-cargo/listing-14-07/add/adder/src/main.rs b/listings/ch14-more-about-cargo/listing-14-07/add/adder/src/main.rs index 7deb7962f..ef96c72d0 100644 --- a/listings/ch14-more-about-cargo/listing-14-07/add/adder/src/main.rs +++ b/listings/ch14-more-about-cargo/listing-14-07/add/adder/src/main.rs @@ -2,9 +2,6 @@ use add_one; fn main() { let num = 10; - println!( - "Hello, world! {} plus one is {}!", - num, - add_one::add_one(num) - ); + // "こんにちは世界!{num}+1は{}!" + println!("Hello, world! {num} plus one is {}!", add_one::add_one(num)); } diff --git a/listings/ch14-more-about-cargo/no-listing-01-workspace-with-adder-crate/add/adder/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-01-workspace-with-adder-crate/add/adder/Cargo.toml index 0e3940cf1..e61cb12e3 100644 --- a/listings/ch14-more-about-cargo/no-listing-01-workspace-with-adder-crate/add/adder/Cargo.toml +++ b/listings/ch14-more-about-cargo/no-listing-01-workspace-with-adder-crate/add/adder/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/Cargo.lock b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/Cargo.lock index 77292f614..a456055c9 100644 --- a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/Cargo.lock +++ b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/Cargo.lock @@ -1,13 +1,13 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "add-one" +name = "add_one" version = "0.1.0" [[package]] name = "adder" version = "0.1.0" dependencies = [ - "add-one 0.1.0", + "add_one 0.1.0", ] diff --git a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/Cargo.toml index d26e7cfb4..1448801d5 100644 --- a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/Cargo.toml +++ b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/Cargo.toml @@ -2,5 +2,5 @@ members = [ "adder", - "add-one", + "add_one", ] diff --git a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add-one/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add-one/Cargo.toml deleted file mode 100644 index 8260fb541..000000000 --- a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add-one/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "add-one" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add_one/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add_one/Cargo.toml new file mode 100644 index 000000000..8af4ab816 --- /dev/null +++ b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add_one/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "add_one" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add-one/src/lib.rs b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add_one/src/lib.rs similarity index 100% rename from listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add-one/src/lib.rs rename to listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add_one/src/lib.rs diff --git a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/adder/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/adder/Cargo.toml index e73f1beca..55c02036c 100644 --- a/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/adder/Cargo.toml +++ b/listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/adder/Cargo.toml @@ -1,9 +1,7 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] - -add-one = { path = "../add-one" } +add_one = { path = "../add_one" } diff --git a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/Cargo.lock b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/Cargo.lock index f17f35e86..bf6974b58 100644 --- a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/Cargo.lock +++ b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/Cargo.lock @@ -1,94 +1,82 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "add-one" +name = "add_one" version = "0.1.0" dependencies = [ - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand", ] [[package]] name = "adder" version = "0.1.0" dependencies = [ - "add-one 0.1.0", + "add_one", ] [[package]] -name = "bitflags" -version = "1.2.1" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cloudabi" -version = "0.0.3" +name = "getrandom" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] [[package]] -name = "fuchsia-cprng" -version = "0.1.1" +name = "libc" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" [[package]] -name = "libc" -version = "0.2.54" +name = "ppv-lite86" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.5.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_chacha", + "rand_core", ] [[package]] -name = "rand_core" -version = "0.3.1" +name = "rand_chacha" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/Cargo.toml index d26e7cfb4..1448801d5 100644 --- a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/Cargo.toml +++ b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/Cargo.toml @@ -2,5 +2,5 @@ members = [ "adder", - "add-one", + "add_one", ] diff --git a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add-one/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add-one/Cargo.toml deleted file mode 100644 index 5b52051a6..000000000 --- a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add-one/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "add-one" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] -rand = "0.5.5" diff --git a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add_one/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add_one/Cargo.toml new file mode 100644 index 000000000..bc758bd88 --- /dev/null +++ b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add_one/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "add_one" +version = "0.1.0" +edition = "2021" + +[dependencies] +rand = "0.8.5" diff --git a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add-one/src/lib.rs b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add_one/src/lib.rs similarity index 100% rename from listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add-one/src/lib.rs rename to listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add_one/src/lib.rs diff --git a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/adder/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/adder/Cargo.toml index e73f1beca..feb3d956e 100644 --- a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/adder/Cargo.toml +++ b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/adder/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] -add-one = { path = "../add-one" } +add_one = { path = "../add_one" } diff --git a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/adder/src/main.rs b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/adder/src/main.rs index 7deb7962f..457795c3b 100644 --- a/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/adder/src/main.rs +++ b/listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/adder/src/main.rs @@ -3,6 +3,7 @@ use add_one; fn main() { let num = 10; println!( + // こんにちは世界!{}+1は{}! "Hello, world! {} plus one is {}!", num, add_one::add_one(num) diff --git a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/Cargo.lock b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/Cargo.lock index 77292f614..a456055c9 100644 --- a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/Cargo.lock +++ b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/Cargo.lock @@ -1,13 +1,13 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "add-one" +name = "add_one" version = "0.1.0" [[package]] name = "adder" version = "0.1.0" dependencies = [ - "add-one 0.1.0", + "add_one 0.1.0", ] diff --git a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/Cargo.toml index d26e7cfb4..1448801d5 100644 --- a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/Cargo.toml +++ b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/Cargo.toml @@ -2,5 +2,5 @@ members = [ "adder", - "add-one", + "add_one", ] diff --git a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add-one/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add-one/Cargo.toml deleted file mode 100644 index 8260fb541..000000000 --- a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add-one/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "add-one" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add_one/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add_one/Cargo.toml new file mode 100644 index 000000000..8af4ab816 --- /dev/null +++ b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add_one/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "add_one" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add-one/src/lib.rs b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add_one/src/lib.rs similarity index 100% rename from listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add-one/src/lib.rs rename to listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add_one/src/lib.rs diff --git a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/adder/Cargo.toml b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/adder/Cargo.toml index e73f1beca..feb3d956e 100644 --- a/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/adder/Cargo.toml +++ b/listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/adder/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] -add-one = { path = "../add-one" } +add_one = { path = "../add_one" } diff --git a/listings/ch14-more-about-cargo/output-only-01-adder-crate/add/Cargo.lock b/listings/ch14-more-about-cargo/output-only-01-adder-crate/add/Cargo.lock new file mode 100644 index 000000000..d98623d6e --- /dev/null +++ b/listings/ch14-more-about-cargo/output-only-01-adder-crate/add/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "adder" +version = "0.1.0" diff --git a/listings/ch14-more-about-cargo/output-only-02-add-one/add/.gitignore b/listings/ch14-more-about-cargo/output-only-02-add-one/add/.gitignore deleted file mode 100644 index 64904e06d..000000000 --- a/listings/ch14-more-about-cargo/output-only-02-add-one/add/.gitignore +++ /dev/null @@ -1 +0,0 @@ -add-one diff --git a/listings/ch14-more-about-cargo/output-only-02-add-one/add/Cargo.lock b/listings/ch14-more-about-cargo/output-only-02-add-one/add/Cargo.lock index 77292f614..a456055c9 100644 --- a/listings/ch14-more-about-cargo/output-only-02-add-one/add/Cargo.lock +++ b/listings/ch14-more-about-cargo/output-only-02-add-one/add/Cargo.lock @@ -1,13 +1,13 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "add-one" +name = "add_one" version = "0.1.0" [[package]] name = "adder" version = "0.1.0" dependencies = [ - "add-one 0.1.0", + "add_one 0.1.0", ] diff --git a/listings/ch14-more-about-cargo/output-only-02-add-one/add/Cargo.toml b/listings/ch14-more-about-cargo/output-only-02-add-one/add/Cargo.toml index d26e7cfb4..1448801d5 100644 --- a/listings/ch14-more-about-cargo/output-only-02-add-one/add/Cargo.toml +++ b/listings/ch14-more-about-cargo/output-only-02-add-one/add/Cargo.toml @@ -2,5 +2,5 @@ members = [ "adder", - "add-one", + "add_one", ] diff --git a/listings/ch14-more-about-cargo/output-only-02-add-one/add/add-one/src/lib.rs b/listings/ch14-more-about-cargo/output-only-02-add-one/add/add-one/src/lib.rs deleted file mode 100644 index 31e1bb209..000000000 --- a/listings/ch14-more-about-cargo/output-only-02-add-one/add/add-one/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/listings/ch14-more-about-cargo/output-only-02-add-one/add/add-one/Cargo.toml b/listings/ch14-more-about-cargo/output-only-02-add-one/add/add_one/Cargo.toml similarity index 65% rename from listings/ch14-more-about-cargo/output-only-02-add-one/add/add-one/Cargo.toml rename to listings/ch14-more-about-cargo/output-only-02-add-one/add/add_one/Cargo.toml index 602f686d3..900018470 100644 --- a/listings/ch14-more-about-cargo/output-only-02-add-one/add/add-one/Cargo.toml +++ b/listings/ch14-more-about-cargo/output-only-02-add-one/add/add_one/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "add-one" +name = "add_one" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/listings/ch14-more-about-cargo/output-only-02-add-one/add/add_one/src/lib.rs b/listings/ch14-more-about-cargo/output-only-02-add-one/add/add_one/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/listings/ch14-more-about-cargo/output-only-02-add-one/add/add_one/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/listings/ch14-more-about-cargo/output-only-02-add-one/add/adder/Cargo.toml b/listings/ch14-more-about-cargo/output-only-02-add-one/add/adder/Cargo.toml index e73f1beca..feb3d956e 100644 --- a/listings/ch14-more-about-cargo/output-only-02-add-one/add/adder/Cargo.toml +++ b/listings/ch14-more-about-cargo/output-only-02-add-one/add/adder/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] -add-one = { path = "../add-one" } +add_one = { path = "../add_one" } diff --git a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/Cargo.lock b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/Cargo.lock index f17f35e86..bf6974b58 100644 --- a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/Cargo.lock +++ b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/Cargo.lock @@ -1,94 +1,82 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "add-one" +name = "add_one" version = "0.1.0" dependencies = [ - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand", ] [[package]] name = "adder" version = "0.1.0" dependencies = [ - "add-one 0.1.0", + "add_one", ] [[package]] -name = "bitflags" -version = "1.2.1" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cloudabi" -version = "0.0.3" +name = "getrandom" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] [[package]] -name = "fuchsia-cprng" -version = "0.1.1" +name = "libc" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" [[package]] -name = "libc" -version = "0.2.54" +name = "ppv-lite86" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" -version = "0.5.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_chacha", + "rand_core", ] [[package]] -name = "rand_core" -version = "0.3.1" +name = "rand_chacha" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/Cargo.toml b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/Cargo.toml index d26e7cfb4..1448801d5 100644 --- a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/Cargo.toml +++ b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/Cargo.toml @@ -2,5 +2,5 @@ members = [ "adder", - "add-one", + "add_one", ] diff --git a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/add-one/Cargo.toml b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/add-one/Cargo.toml deleted file mode 100644 index 5b52051a6..000000000 --- a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/add-one/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "add-one" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] -rand = "0.5.5" diff --git a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/add_one/Cargo.toml b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/add_one/Cargo.toml new file mode 100644 index 000000000..bc758bd88 --- /dev/null +++ b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/add_one/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "add_one" +version = "0.1.0" +edition = "2021" + +[dependencies] +rand = "0.8.5" diff --git a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/add-one/src/lib.rs b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/add_one/src/lib.rs similarity index 100% rename from listings/ch14-more-about-cargo/output-only-03-use-rand/add/add-one/src/lib.rs rename to listings/ch14-more-about-cargo/output-only-03-use-rand/add/add_one/src/lib.rs diff --git a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/adder/Cargo.toml b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/adder/Cargo.toml index e73f1beca..feb3d956e 100644 --- a/listings/ch14-more-about-cargo/output-only-03-use-rand/add/adder/Cargo.toml +++ b/listings/ch14-more-about-cargo/output-only-03-use-rand/add/adder/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "adder" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] -add-one = { path = "../add-one" } +add_one = { path = "../add_one" } diff --git a/src/ch14-00-more-about-cargo.md b/src/ch14-00-more-about-cargo.md index 733f8bf9e..d75003305 100644 --- a/src/ch14-00-more-about-cargo.md +++ b/src/ch14-00-more-about-cargo.md @@ -16,23 +16,23 @@ other, more advanced features to show you how to do the following: * リリースプロファイルでビルドをカスタマイズする -* [crates.io](https://crates.io)でライブラリを公開する +* [crates.io](https://crates.io/)でライブラリを公開する * ワークスペースで巨大なプロジェクトを体系化する -* [crates.io](https://crates.io)からバイナリをインストールする +* [crates.io](https://crates.io/)からバイナリをインストールする * 独自のコマンドを使用してCargoを拡張する -また、Cargoはこの章で講義する以上のこともできるので、機能の全解説を見るには、 +また、Cargoはこの章で講義する機能以上のこともできるので、機能の全解説を見るには、 [ドキュメンテーション](https://doc.rust-lang.org/cargo/)を参照されたし。 diff --git a/src/ch14-01-release-profiles.md b/src/ch14-01-release-profiles.md index 29866e4df..b8e2b8dad 100644 --- a/src/ch14-01-release-profiles.md +++ b/src/ch14-01-release-profiles.md @@ -32,31 +32,37 @@ These profile names might be familiar from the output of your builds: これらのプロファイル名は、ビルドの出力で馴染みのある可能性があります: -```text + + +```console $ cargo build - Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs + Finished dev [unoptimized + debuginfo] target(s) in 0.0s $ cargo build --release - Finished release [optimized] target(s) in 0.0 secs + Finished release [optimized] target(s) in 0.0s ``` -このビルド出力で表示されている`dev`と`release`は、コンパイラが異なるプロファイルを使用していることを示しています。 +`dev`と`release`が、コンパイラによって使用される異なるプロファイルです。 -プロジェクトの*Cargo.toml*ファイルに`[profile.*]`セクションが存在しない際に適用される各プロファイル用のデフォルト設定が、 -Cargoには存在します。カスタマイズしたいプロファイル用の`[profile.*]`セクションを追加することで、 -デフォルト設定の一部を上書きすることができます。例えば、こちらが`dev`と`release`プロファイルの`opt-level`設定のデフォルト値です: +Cargoには、プロジェクトの*Cargo.toml*ファイルに`[profile.*]`セクションが明示的に追加されていない際に適用される、 +各プロファイル用のデフォルト設定が存在します。カスタマイズしたいプロファイル用の`[profile.*]`セクションを追加することで、 +デフォルト設定の一部が上書きされます。例えば、こちらが`dev`と`release`プロファイルの`opt-level`設定のデフォルト値です: - `opt-level`設定は、0から3の範囲でコンパイラがコードに適用する最適化の度合いを制御します。 -最適化を多くかけると、コンパイル時間が延びるので、開発中に頻繁にコードをコンパイルするのなら、 -たとえ出力結果のコードの動作速度が遅くなっても早くコンパイルが済んでほしいですよね。 -これが、`dev`の`opt-level`のデフォルト設定が`0`になっている唯一の理由です。 +最適化を多くかけるとコンパイル時間が延びるので、開発中に頻繁にコードをコンパイルするのなら、 +たとえ出力結果のコードの動作速度が遅くなっても早くコンパイルできるように、より少ない最適化で済ませてほしいですよね。 +そのため、`dev`の`opt-level`のデフォルト設定は`0`になっています。 コードのリリース準備ができたら、より長い時間をコンパイルにかけるのが最善の策です。 リリースモードでコンパイルするのはたった1回ですが、コンパイル結果のプログラムは何度も実行するので、 リリースモードでは、長いコンパイル時間と引き換えに、生成したコードが速く動作します。 そのため、`release`の`opt-level`のデフォルト設定が`3`になっているのです。 -設定の選択肢と各プロファイルのデフォルト設定の一覧は、[Cargoのドキュメンテーション](https://doc.rust-lang.org/cargo/)を参照されたし。 +設定の選択肢と各プロファイルのデフォルト設定の一覧は、[Cargoのドキュメンテーション](https://doc.rust-lang.org/cargo/reference/profiles.html)を参照されたし。 diff --git a/src/ch14-02-publishing-to-crates-io.md b/src/ch14-02-publishing-to-crates-io.md index fce6f105b..731c67e25 100644 --- a/src/ch14-02-publishing-to-crates-io.md +++ b/src/ch14-02-publishing-to-crates-io.md @@ -5,25 +5,25 @@ ## Crates.ioにクレートを公開する -プロジェクトの依存として[crates.io](https://crates.io)のパッケージを使用しましたが、 +プロジェクトの依存として[crates.io](https://crates.io/)のパッケージを使用しましたが、 自分のパッケージを公開することで他の人とコードを共有することもできます。 -[crates.io](https://crates.io)のクレート登録所は、自分のパッケージのソースコードを配布するので、 +[crates.io](https://crates.io/)のクレートレジストリは、自分のパッケージのソースコードを配布するので、 主にオープンソースのコードをホストします。 -RustとCargoは、公開したパッケージを人が使用し、そもそも見つけやすくしてくれる機能を有しています。 +RustとCargoは、公開されたパッケージを人々が見つけやすく、使いやすくしてくれる機能を有しています。 これらの機能の一部を次に語り、そして、パッケージの公開方法を説明します。 ドキュメンテーションコメントは、2つではなく、3連スラッシュ、`///`を使用し、テキストを整形するMarkdown記法もサポートしています。 ドキュメント対象の要素の直前にドキュメンテーションコメントを配置してください。 -リスト14-1は、`my_crate`という名のクレートの`add_one`関数用のドキュメンテーションコメントを示しています: +リスト14-1は、`my_crate`という名のクレートの`add_one`関数用のドキュメンテーションコメントを示しています。 -* **Panics**: ドキュメント対象の関数が`panic!`する可能性のある筋書きです。プログラムをパニックさせたくない関数の使用者は、 +* **Panics**: ドキュメント対象の関数がパニックする可能性のある筋書きです。プログラムをパニックさせたくない関数の使用者は、 これらの状況で関数が呼ばれないことを確かめる必要があります。 * **Errors**: 関数が`Result`を返すなら、起きうるエラーの種類とどんな条件がそれらのエラーを引き起こす可能性があるのか解説すると、 呼び出し側の役に立つので、エラーの種類によって処理するコードを変えて書くことができます。 @@ -165,12 +153,12 @@ and covering the invariants that the function expects callers to uphold. 多くのドキュメンテーションコメントでは、これら全てのセクションが必要になることはありませんが、 -これは自分のコードを呼び出している人が知りたいと思うコードの方向性を思い出させてくれるいいチェックリストになります。 +これはコードの利用者が知りたいと思うコードの方向性を思い出させてくれるいいチェックリストになります。 + ```text Doc-tests my_crate running 1 test test src/lib.rs - add_one (line 5) ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s ``` さて、例の`assert_eq!`がパニックするように、関数か例を変更し、再度`cargo test`を実行したら、 @@ -223,26 +217,25 @@ docテストが、例とコードがお互いに同期されていないこと #### 含まれている要素にコメントする -docコメントの別スタイル、`//!`は、コメントに続く要素にドキュメンテーションを付け加えるのではなく、 -コメントを含む要素にドキュメンテーションを付け加えます。典型的には、クレートのルートファイル(慣例的には、*src/lib.rs*)内部や、 +`//!`スタイルのdocコメントは、コメントに続く要素にではなく、コメントを含む要素にドキュメンテーションを付け加えます。 +典型的には、クレートのルートファイル(慣例的には、*src/lib.rs*)内部や、 モジュールの内部で使用して、クレートやモジュール全体にドキュメントをつけます。 -例えば、`add_one`関数を含む`my_crate`クレートの目的を解説するドキュメンテーションを追加したいのなら、 -`//!`で始まるドキュメンテーションコメントを*src/lib.rs*ファイルの先頭につけることができます。 +例えば、`add_one`関数を含む`my_crate`クレートの目的を解説するドキュメンテーションを追加するには、 +`//!`で始まるドキュメンテーションコメントを*src/lib.rs*ファイルの先頭につけます。 リスト14-2に示したようにですね: `//!`で始まる最後の行のあとにコードがないことに注目してください。`///`ではなく、`//!`でコメントを開始しているので、 このコメントに続く要素ではなく、このコメントを含む要素にドキュメントをつけているわけです。 -今回の場合、このコメントを含む要素は*src/lib.rs*ファイルであり、クレートのルートです。 +今回の場合、そのような要素は*src/lib.rs*ファイルであり、クレートのルートです。 これらのコメントは、クレート全体を解説しています。 要素内のドキュメンテーションコメントは、特にクレートやモジュールを解説するのに有用です。 -コンテナの全体の目的を説明し、クレートの使用者がクレートの体系を理解する手助けをするのに使用してください。 +コンテナの全体の目的を説明し、使用者がクレートの体系を理解する手助けをするのに使用してください。 - -第7章において、`mod`キーワードを使用してモジュールにコードを体系化する方法、`pub`キーワードで要素を公開にする方法、 -`use`キーワードで要素をスコープに導入する方法について講義しました。しかしながら、クレートの開発中に、 -自分にとって意味のある構造は、ユーザにはあまり便利ではない可能性があります。複数階層を含む階層で、 -自分の構造体を体系化したくなるかもしれませんが、それから階層の深いところで定義した型を使用したい人は、 -型が存在することを見つけ出すのに困難を伴う可能性もあります。また、そのような人は、 -`use my_crate::UsefulType`の代わりに`use my_crate::some_module::another_module::UsefulType;`と入力するのを煩わしく感じる可能性もあります。 - + +第7章において、`pub`キーワードで要素を公開にする方法、`use`キーワードで要素をスコープに導入する方法について講義しました。 +しかしながら、クレートの開発中に自分にとって意味のある構造は、ユーザにはあまり便利ではない可能性があります。 +複数階層を含む階層で自分の構造体を体系化したくなるかもしれませんが、それから階層の深いところで定義した型を使用したい人は、 +型が存在することを見つけ出すのに困難を伴う可能性もあります。また、そのような人は、 +`use my_crate::UsefulType`の代わりに`use my_crate::some_module::another_module::UsefulType;`と入力するのを煩わしく感じる可能性もあります。 + @@ -382,42 +363,8 @@ function named `mix`, as shown in Listing 14-3: ファイル名: src/lib.rs -```rust,ignore -//! # Art -//! -//! A library for modeling artistic concepts. -//! #芸術 -//! -//! 芸術的な概念をモデル化するライブラリ。 - -pub mod kinds { - /// The primary colors according to the RYB color model. - /// RYBカラーモデルによる主色 - pub enum PrimaryColor { - Red, - Yellow, - Blue, - } - - /// The secondary colors according to the RYB color model. - /// RYBカラーモデルによる副色 - pub enum SecondaryColor { - Orange, - Green, - Purple, - } -} - -pub mod utils { - use kinds::*; - - /// Combines two primary colors in equal amounts to create - /// a secondary color. - ///2つの主色を同じ割合で混合し、副色にする - pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor { - // --snip-- - } -} +```rust,noplayground,test_harness +{{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-03/src/lib.rs:here}} ``` このライブラリに依存する別のクレートは、現在定義されているモジュール構造を指定して、 -`art`の要素をインポートする`use`文が必要になるでしょう。リスト14-4は、 +`art`の要素をスコープ内に持ち込む`use`文が必要になるでしょう。リスト14-4は、 `art`クレートから`PrimaryColor`と`mix`要素を使用するクレートの例を示しています: -リスト14-4は`art`クレートを使用していますが、このコードの筆者は、`PrimaryColor`が`kinds`モジュールにあり、 +リスト14-4は`art`クレートを使用していますが、このコードの作者は、`PrimaryColor`が`kinds`モジュールにあり、 `mix`が`utils`モジュールにあることを理解しなければなりませんでした。`art`クレートのモジュール構造は、 `art`クレートの使用者よりも、`art`クレートに取り組む開発者などに関係が深いです。 -クレートの一部を`kinds`モジュールと`utils`モジュールに体系化する内部構造は、`art`クレートの使用方法を理解しようとする人には、 -何も役に立つ情報を含んでいません。代わりに、開発者がどこを見るべきか計算する必要があるので、 -`art`クレートのモジュール構造は混乱を招き、また、開発者はモジュール名を`use`文で指定しなければならないので、 -この構造は不便です。 +この内部構造は`art`クレートの使用方法を理解しようとする人とって役に立つ情報を何も含んでおらず、むしろ、 +利用者はどこを見ればよいのか探し出す必要があり、モジュール名を`use`文で指定しなければならないので、 +混乱を招くものです。 ネストされたモジュールがたくさんあるような場合、最上位階層で`pub use`により型を再エクスポートすることは、 -クレートの使用者の経験に大きな違いを生みます。 +クレートの使用者の経験に大きな違いを生みます。別のよくある`pub use`の使用法は、 +依存クレートの定義をクレートの公開APIの一部とするために、現在のクレートの中で依存クレートの定義を再エクスポートすることです。 -クレートを公開する前に、[crates.io](https://crates.io)のアカウントを作成し、 -APIトークンを取得する必要があります。そうするには、[crates.io](https://crates.io)のホームページを訪れ、 +クレートを公開する前に、[crates.io](https://crates.io/)のアカウントを作成し、 +APIトークンを取得する必要があります。そうするには、[crates.io](https://crates.io/)のホームページを訪れ、 Githubアカウントでログインしてください。(現状は、Githubアカウントがなければなりませんが、 いずれは他の方法でもアカウントを作成できるようになる可能性があります。)ログインしたら、 [https://crates.io/me/](https://crates.io/me/)で自分のアカウントの設定に行き、 APIキーを取り扱ってください。そして、`cargo login`コマンドをAPIキーとともに実行してください。 以下のようにですね: -```text +```console $ cargo login abcdefghijklmnopqrstuvwxyz012345 ``` @@ -665,12 +582,13 @@ $ cargo login abcdefghijklmnopqrstuvwxyz012345 This command will inform Cargo of your API token and store it locally in *~/.cargo/credentials*. Note that this token is a *secret*: do not share it with anyone else. If you do share it with anyone for any reason, you should -revoke it and generate a new token on [crates.io](https://crates.io) +revoke it and generate a new token on [crates.io](https://crates.io/) +. --> このコマンドは、CargoにAPIトークンを知らせ、*~/.cargo/credentials*にローカルに保存します。 このトークンは、*秘密*です: 他人とは共有しないでください。なんらかの理由で他人と実際に共有してしまったら、 -古いものを破棄して[crates.io](https://crates.io)で新しいトークンを生成するべきです。 +古いものを破棄して[crates.io](https://crates.io/)で新しいトークンを生成するべきです。 -アカウントはできたので、公開したいクレートがあるとしましょう。公開前に、 -*Cargo.toml*ファイルの`[package]`セクションに追加することでクレートにメタデータを追加する必要があるでしょう。 +公開したいクレートがあるとしましょう。公開前に、 +*Cargo.toml*ファイルの`[package]`セクションにメタデータを追加する必要があるでしょう。 -クレートには、独自の名前が必要でしょう。クレートをローカルで作成している間、 -クレートの名前はなんでもいい状態でした。ところが、[crates.io](https://crates.io)のクレート名は、 +クレートには、一意な名前が必要でしょう。クレートをローカルで作成している間、 +クレートの名前はなんでもいい状態でした。ところが、[crates.io](https://crates.io/)のクレート名は、 最初に来たもの勝ちの精神で付与されていますので、一旦クレート名が取られてしまったら、 -その名前のクレートを他の人が公開することは絶対できません。もう使われているか、 -サイトで使いたい名前を検索してください。まだなら、*Cargo.toml*ファイルの`[package]`以下の名前を編集して、 -名前を公開用に使ってください。以下のように: +その名前のクレートを他の人が公開することは絶対できません。クレートを公開しようとする前に使いたい名前を検索してください。 +すでに使用されている場合は、他の名前を探して、*Cargo.toml*ファイルの`[package]`セクション下の`name`フィールドを編集して、 +公開用に新しい名前を使う必要があるでしょう。以下のように: -たとえ、独自の名前を選択していたとしても、この時点で`cargo publish`を実行すると、警告とエラーが出ます: +たとえ、一意な名前を選択していたとしても、この時点で`cargo publish`を実行すると、警告とエラーが出ます: -```text + + +```console $ cargo publish - Updating registry `https://github.com/rust-lang/crates.io-index` -warning: manifest has no description, license, license-file, documentation, -homepage or repository. -(警告: マニフェストに説明、ライセンス、ライセンスファイル、ドキュメンテーション、ホームページ、 -リポジトリがありません) + Updating crates.io index +warning: manifest has no description, license, license-file, documentation, homepage or repository. +See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. +(警告: マニフェストに説明、ライセンス、ライセンスファイル、ドキュメンテーション、ホームページ、リポジトリがありません。 +さらなる情報については https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata を参照してください。) --snip-- -error: api errors: missing or empty metadata fields: description, license. -(エラー: APIエラー: 存在しないメタデータフィールド: description, license) +error: failed to publish to registry at https://crates.io +(エラー: https://crates.ioにあるレジストリへの公開に失敗しました) + +Caused by: + the remote server responded with an error: missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for how to upload metadata +(原因: + リモートサーバがエラーを返しました: 存在しないか空のメタデータフィールド: description, license. メタデータをアップロードする方法については https://doc.rust-lang.org/cargo/reference/manifest.html を参照してください) ``` -原因は、大事な情報を一部入れていないからです: 説明とライセンスは、 +これがエラーになるのは、大事な情報を一部入れていないからです: 説明とライセンスは、 他の人があなたのクレートは何をし、どんな条件の元で使っていいのかを知るために必要なのです。 -このエラーを解消するには、*Cargo.toml*ファイルにこの情報を入れ込む必要があります。 - - - -1文か2文程度の説明をつけてください。これは、検索結果に表示されますからね。 +*Cargo.toml*に1文か2文程度の説明をつけてください。これは、検索結果に表示されますからね。 `license`フィールドには、*ライセンス識別子*を与える必要があります。 [Linux団体のSoftware Package Data Exchange(SPDX)][spdx]に、この値に使用できる識別子が列挙されています。 例えば、自分のクレートをMITライセンスでライセンスするためには、 `MIT`識別子を追加してください: -[spdx]: http://spdx.org/licenses/ - @@ -799,12 +720,11 @@ Rust自体と同じようにプロジェクトをライセンスします。こ プロジェクトに複数のライセンスを持たせることもできることを模擬しています。 -独自の名前、バージョン、クレート作成時に`cargo new`が追加した筆者の詳細、説明、ライセンスが追加され、 +一意な名前、バージョン、説明、ライセンスが追加され、 公開準備のできたプロジェクト用の`Cargo.toml`ファイルは以下のような見た目になっていることでしょう: アカウントを作成し、APIトークンを保存し、クレートの名前を決め、必要なメタデータを指定したので、 公開する準備が整いました!クレートを公開すると、特定のバージョンが、 -[crates.io](http://crates.io)に他の人が使用できるようにアップロードされます。 +[crates.io](http://crates.io/)に他の人が使用できるようにアップロードされます。 -公開は*永久*なので、クレートの公開時には気をつけてください。バージョンは絶対に上書きできず、 -コードも削除できません。[crates.io](https://crates.io)の一つの主な目標が、 -[crates.io](https://crates.io)のクレートに依存している全てのプロジェクトのビルドが、 +公開は*永久*なので、気をつけてください。バージョンは絶対に上書きできず、 +コードも削除できません。[crates.io](https://crates.io/)の一つの主な目標が、 +[crates.io](https://crates.io/)のクレートに依存している全てのプロジェクトのビルドが、 動き続けるようにコードの永久アーカイブとして機能することなのです。バージョン削除を可能にしてしまうと、 その目標を達成するのが不可能になってしまいます。ですが、公開できるクレートバージョンの数に制限はありません。 @@ -873,15 +793,21 @@ Run the `cargo publish` command again. It should succeed now: 再度`cargo publish`コマンドを実行してください。今度は成功するはずです: -```text + + +```console $ cargo publish - Updating registry `https://github.com/rust-lang/crates.io-index` -Packaging guessing_game v0.1.0 (file:///projects/guessing_game) -Verifying guessing_game v0.1.0 (file:///projects/guessing_game) -Compiling guessing_game v0.1.0 + Updating crates.io index + Packaging guessing_game v0.1.0 (file:///projects/guessing_game) + Verifying guessing_game v0.1.0 (file:///projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game/target/package/guessing_game-0.1.0) - Finished dev [unoptimized + debuginfo] target(s) in 0.19 secs -Uploading guessing_game v0.1.0 (file:///projects/guessing_game) + Finished dev [unoptimized + debuginfo] target(s) in 0.19s + Uploading guessing_game v0.1.0 (file:///projects/guessing_game) ``` + -### `cargo yank`でCrates.ioからバージョンを削除する +### `cargo yank`でCrates.ioからバージョンを非推奨化する -バージョンを取り下げると、既存のプロジェクトは、引き続きダウンロードしたりそのバージョンに依存したりしつづけられますが、 -新規プロジェクトが新しくそのバージョンに依存しだすことは防止されます。つまるところ、取り下げは、 +バージョンを取り下げると、それに依存するすべての既存のプロジェクトは引き続き依存することができますが、 +新規プロジェクトがそのバージョンに依存することはできなくなります。つまるところ、取り下げは、 すでに*Cargo.lock*が存在するプロジェクトは壊さないが、将来的に生成された*Cargo.lock*ファイルは 取り下げられたバージョンを使わない、ということを意味します。 -あるバージョンのクレートを取り下げるには、`cargo yank`を実行し、取り下げたいバージョンを指定します: +あるバージョンのクレートを取り下げるには、以前公開したクレートのディレクトリで、取り下げたいバージョンを指定して`cargo yank`を実行してください。 +例えば、`guessing_game`という名前のクレートのバージョン1.0.1を公開したことがあり、それを取り下げたい場合は、 +`guessing_game`のプロジェクトディレクトリで以下を実行します: -```text + + +```console $ cargo yank --vers 1.0.1 + Updating crates.io index + Yank guessing_game@1.0.1 ``` -取り下げは、コードの削除は一切し*ません*。例として、取り下げ機能は、誤ってアップロードされた秘密鍵を削除するためのものではありません。 +取り下げは、コードの削除は一切*しません*。例えば、誤ってアップロードされた秘密鍵を削除することはできません。 もしそうなってしまったら、即座に秘密鍵をリセットしなければなりません。 + +[spdx]: http://spdx.org/licenses/ +[semver]: http://semver.org/ diff --git a/src/ch14-03-cargo-workspaces.md b/src/ch14-03-cargo-workspaces.md index 7c0592c7d..dc0757f07 100644 --- a/src/ch14-03-cargo-workspaces.md +++ b/src/ch14-03-cargo-workspaces.md @@ -7,15 +7,14 @@ 第12章で、バイナリクレートとライブラリクレートを含むパッケージを構築しました。プロジェクトの開発が進むにつれて、 ライブラリクレートの肥大化が続き、その上で複数のライブラリクレートにパッケージを分割したくなることでしょう。 -この場面において、Cargoは*ワークスペース*という協調して開発された関連のある複数のパッケージを管理するのに役立つ機能を提供しています。 +Cargoは*ワークスペース*という協調して開発された関連のある複数のパッケージを管理するのに役立つ機能を提供しています。 *ワークスペース*は、同じ*Cargo.lock*と出力ディレクトリを共有する一連のパッケージです。 ワークスペースを使用したプロジェクトを作成し、ワークスペースの構造に集中できるよう、瑣末なコードを使用しましょう。 -ワークスペースを構築する方法は複数ありますが、一般的な方法を提示しましょう。バイナリ1つとライブラリ2つを含むワークスペースを作ります。 +ワークスペースを構築する方法は複数あるので、よく使われる方法だけを提示しましょう。バイナリ1つとライブラリ2つを含むワークスペースを作ります。 バイナリは、主要な機能を提供しますが、2つのライブラリに依存しています。 一方のライブラリは、`add_one`関数を提供し、2番目のライブラリは、`add_two`関数を提供します。 これら3つのクレートが同じワークスペースの一部になります。ワークスペース用の新しいディレクトリを作ることから始めましょう: -```text +```console $ mkdir add $ cd add ``` 次に*add*ディレクトリにワークスペース全体を設定する*Cargo.toml*ファイルを作成します。 -このファイルには、他の*Cargo.toml*ファイルで見かけるような`[package]`セクションやメタデータはありません。 -代わりにバイナリクレートへのパスを指定することでワークスペースにメンバを追加させてくれる`[workspace]`セクションから開始します; +このファイルには`[package]`セクションはありません。 +代わりに、バイナリクレートを含むパッケージへのパスを指定することでワークスペースにメンバを追加させてくれる`[workspace]`セクションから開始します; 今回の場合、そのパスは*adder*です: + +```console +$ cargo new adder + Created binary (application) `adder` package ``` -ワークスペースには、コンパイルした生成物を置けるように最上位に*target*のディレクトリがあります; -`adder`クレートには*target*ディレクトリはありません。 +ワークスペースは、コンパイルした生成物が置かれる単一の*target*ディレクトリを最上位に持ちます; +`adder`パッケージには*target*ディレクトリはありません。 *adder*ディレクトリ内部から`cargo build`を走らせることになっていたとしても、コンパイルされる生成物は、 *add/adder/target*ではなく、*add/target*に落ち着くでしょう。ワークスペースのクレートは、 お互いに依存しあうことを意味するので、Cargoはワークスペースの*target*ディレクトリをこのように構成します。 -各クレートが*target*ディレクトリを持っていたら、各クレートがワークスペースの他のクレートを再コンパイルし、 -*target*ディレクトリに生成物がある状態にしなければならないでしょう。一つの*target*ディレクトリを共有することで、 +各クレートが*target*ディレクトリを持っていたら、各クレートは自身の*target*ディレクトリにワークスペースの他のクレートの生成物を置くために、 +ワークスペースの他のクレートを再コンパイルしなくてはならなくなるでしょう。一つの*target*ディレクトリを共有することで、 クレートは不必要な再ビルドを回避できるのです。 -### ワークスペース内に2番目のクレートを作成する +### ワークスペース内に2番目のパッケージを作成する -次に、ワークスペースに別のメンバクレートを作成し、`add-one`と呼びましょう。 -最上位の*Cargo.toml*を変更して`members`リストで*add-one*パスを指定するようにしてください: +次に、ワークスペースに別のメンバパッケージを作成し、`add_one`と呼びましょう。 +最上位の*Cargo.toml*を変更して`members`リストで*add_one*パスを指定するようにしてください: -それから、`add-one`という名前のライブラリクレートを生成してください: +それから、`add_one`という名前のライブラリクレートを生成してください: -```text -$ cargo new add-one --lib - Created library `add-one` project + + +```console +$ cargo new add_one --lib + Created library `add_one` package ``` -*add-one/src/lib.rs*ファイルに`add_one`関数を追加しましょう: +*add_one/src/lib.rs*ファイルに`add_one`関数を追加しましょう: -ファイル名: add-one/src/lib.rs +ファイル名: add_one/src/lib.rs -```rust -pub fn add_one(x: i32) -> i32 { - x + 1 -} +```rust,noplayground +{{#rustdoc_include ../listings/ch14-more-about-cargo/no-listing-02-workspace-with-two-crates/add/add_one/src/lib.rs}} ``` -ワークスペースにライブラリクレートが存在するようになったので、バイナリクレート`adder`をライブラリクレートの`add-one`に依存させられます。 -まず、`add-one`へのパス依存を*adder/Cargo.toml*に追加する必要があります: +これで、バイナリを持つパッケージ`adder`を、ライブラリを持つパッケージ`add_one`に依存させることができるようになりました。 +まず、`add_one`へのパス依存を*adder/Cargo.toml*に追加する必要があります。 Cargoはワークスペースのクレートが、お互いに依存しているとは想定していないので、 -クレート間の依存関係について明示する必要があります。 +依存関係について明示する必要があります。 -次に、`adder`クレートの`add-one`クレートから`add_one`関数を使用しましょう。*adder/src/main.rs*ファイルを開き、 -冒頭に`extern crate`行を追加して新しい`add-one`ライブラリクレートをスコープに導入してください。 -それから`main`関数を変更し、`add_one`関数を呼び出します。リスト14-7のようにですね: +次に、`adder`クレート内で(`add_one`クレートの)`add_one`関数を使用しましょう。*adder/src/main.rs*ファイルを開き、 +冒頭に`use`行を追加して新しい`add_one`ライブラリクレートをスコープに導入してください。 +それから`main`関数を変更し、`add_one`関数を呼び出します。リスト14-7のようにですね。 -リスト14-7: `adder`クレートから`add-one`ライブラリクレートを使用する +リスト14-7: `adder`クレートから`add_one`ライブラリクレートを使用する + +```console $ cargo build - Compiling add-one v0.1.0 (file:///projects/add/add-one) + Compiling add_one v0.1.0 (file:///projects/add/add_one) Compiling adder v0.1.0 (file:///projects/add/adder) - Finished dev [unoptimized + debuginfo] target(s) in 0.68 secs + Finished dev [unoptimized + debuginfo] target(s) in 0.68s ``` *add*ディレクトリからバイナリクレートを実行するには、`-p`引数とパッケージ名を`cargo run`と共に使用して、 -使用したいワークスペースのパッケージを指定する必要があります: +実行したいワークスペースのパッケージを指定することができます: -```text + + +```console $ cargo run -p adder - Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs + Finished dev [unoptimized + debuginfo] target(s) in 0.0s Running `target/debug/adder` Hello, world! 10 plus one is 11! ``` これにより、*adder/src/main.rs*のコードが実行され、これは`add_one`クレートに依存しています。 -#### ワークスペースの外部クレートに依存する +#### ワークスペースの外部パッケージに依存する ワークスペースには、各クレートのディレクトリそれぞれに*Cargo.lock*が存在するのではなく、 -ワークスペースの最上位階層にただ一つの*Cargo.lock*が存在するだけのことに注目してください。 +最上位階層にただ一つの*Cargo.lock*が存在するだけのことに注目してください。 これにより、全クレートが全依存の同じバージョンを使用していることが確認されます。 -`rand`クレートを*adder/Cargo.toml*と*add-one/Cargo.toml*ファイルに追加すると、 +`rand`パッケージを*adder/Cargo.toml*と*add_one/Cargo.toml*ファイルに追加すると、 Cargoは両者をあるバージョンの`rand`に解決し、それを一つの*Cargo.lock*に記録します。 ワークスペースの全クレートに同じ依存を使用させるということは、 -ワークスペースのクレートが相互に互換性を常に維持するということになります。 -*add-one/Cargo.toml*ファイルの`[dependencies]`セクションに`rand`クレートを追加して、 -`add-one`クレートで`rand`クレートを使用できます: +クレートが相互に互換性を常に維持するということになります。 +`add_one`クレートで`rand`クレートを使用できるように、 +*add_one/Cargo.toml*ファイルの`[dependencies]`セクションに`rand`クレートを追加しましょう: + + -ファイル名: add-one/Cargo.toml +ファイル名: add_one/Cargo.toml ```toml -[dependencies] - -rand = "0.3.14" +{{#include ../listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add/add_one/Cargo.toml:6:7}} ``` -これで、*add-one/src/lib.rs*ファイルに`extern crate rand;`を追加でき、 +これで、*add_one/src/lib.rs*ファイルに`use rand;`を追加でき、 *add*ディレクトリで`cargo build`を実行することでワークスペース全体をビルドすると、 -`rand`クレートを持ってきてコンパイルするでしょう: +`rand`クレートを持ってきてコンパイルするでしょう。 +スコープ内に持ち込んだ`rand`を参照していないので、警告が出るでしょう: -```text + + +```console $ cargo build - Updating registry `https://github.com/rust-lang/crates.io-index` - Downloading rand v0.3.14 + Updating crates.io index + Downloaded rand v0.8.5 --snip-- - Compiling rand v0.3.14 - Compiling add-one v0.1.0 (file:///projects/add/add-one) + Compiling rand v0.8.5 + Compiling add_one v0.1.0 (file:///projects/add/add_one) +warning: unused import: `rand` +(警告: 未使用のインポート: `rand`) + --> add_one/src/lib.rs:1:5 + | +1 | use rand; + | ^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +warning: `add_one` (lib) generated 1 warning Compiling adder v0.1.0 (file:///projects/add/adder) - Finished dev [unoptimized + debuginfo] target(s) in 10.18 secs + Finished dev [unoptimized + debuginfo] target(s) in 10.18s ``` -さて、最上位の*Cargo.lock*は、`rand`に対する`add-one`の依存の情報を含むようになりました。 +さて、最上位の*Cargo.lock*は、`rand`に対する`add_one`の依存の情報を含むようになりました。 ですが、`rand`はワークスペースのどこかで使用されているにも関わらず、それぞれの*Cargo.toml*ファイルにも、 `rand`を追加しない限り、ワークスペースの他のクレートでそれを使用することはできません。 -例えば、`adder`クレートの*adder/src/main.rs*ファイルに`extern crate rand;`を追加すると、 +例えば、`adder`パッケージの*adder/src/main.rs*ファイルに`use rand;`を追加すると、 エラーが出ます: -```text + + +```console $ cargo build + --snip-- Compiling adder v0.1.0 (file:///projects/add/adder) -error: use of unstable library feature 'rand': use `rand` from crates.io (see -issue #27703) -(エラー: 不安定なライブラリの機能'rand'を使用しています: crates.ioの`rand`を使用してください) - --> adder/src/main.rs:1:1 +error[E0432]: unresolved import `rand` +(エラー: 未解決のインポート`rand`) + --> adder/src/main.rs:2:5 | -1 | extern crate rand; +2 | use rand; + | ^^^^ no external crate `rand` + | (外部クレート`rand`は存在しません) ``` -これを修正するには、`adder`クレートの*Cargo.toml*ファイルを編集し、同様にそのクレートが`rand`に依存していることを示してください。 -`adder`クレートをビルドすると、`rand`を*Cargo.lock*の`adder`の依存一覧に追加しますが、 -`rand`のファイルが追加でダウンロードされることはありません。Cargoが、ワークスペースの`rand`を使用するどのクレートも、 -同じバージョンを使っていることを確かめてくれるのです。ワークスペース全体で`rand`の同じバージョンを使用することにより、 -複数のコピーが存在しないのでスペースを節約し、ワークスペースのクレートが相互に互換性を維持することを確かめます。 +これを修正するには、`adder`パッケージの*Cargo.toml*ファイルを編集し、これも`rand`に依存していることを示してください。 +`adder`パッケージをビルドすると、`rand`を*Cargo.lock*の`adder`の依存一覧に追加しますが、 +`rand`のファイルが追加でダウンロードされることはありません。Cargoが、 +ワークスペース内で`rand`パッケージを使用するすべてのパッケージ内のすべてのクレートが、 +同じバージョンを使用することを保証してくれるのです。これによりスペースを節約し、 +ワークスペースのクレートが相互に互換性があることを保証してくれます。 -ファイル名: add-one/src/lib.rs - -```rust -pub fn add_one(x: i32) -> i32 { - x + 1 -} - -#[cfg(test)] -mod tests { - use super::*; +ファイル名: add_one/src/lib.rs - #[test] - fn it_works() { - assert_eq!(3, add_one(2)); - } -} +```rust,noplayground +{{#rustdoc_include ../listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add/add_one/src/lib.rs}} ``` -では、最上位の*add*ディレクトリで`cargo test`を実行してください: +では、最上位の*add*ディレクトリで`cargo test`を実行してください。 +このような構造をしたワークスペースで`cargo test`を走らせると、ワークスペースの全クレートのテストを実行します: -```text + + +```console $ cargo test - Compiling add-one v0.1.0 (file:///projects/add/add-one) + Compiling add_one v0.1.0 (file:///projects/add/add_one) Compiling adder v0.1.0 (file:///projects/add/adder) - Finished dev [unoptimized + debuginfo] target(s) in 0.27 secs - Running target/debug/deps/add_one-f0253159197f7841 + Finished test [unoptimized + debuginfo] target(s) in 0.27s + Running unittests src/lib.rs (target/debug/deps/add_one-f0253159197f7841) running 1 test test tests::it_works ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - Running target/debug/deps/adder-f88af9d2cc175a5e + Running unittests src/main.rs (target/debug/deps/adder-49979ff40686fa8e) running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - Doc-tests add-one + Doc-tests add_one running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` -出力の最初の区域が、`add-one`クレートの`it_works`テストが通ったことを示しています。 +出力の最初の区域が、`add_one`クレートの`it_works`テストが通ったことを示しています。 次の区域には、`adder`クレートにはテストが見つからなかったことが示され、 -さらに最後の区域には、`add-one`クレートにドキュメンテーションテストは見つからなかったと表示されています。 -このような構造をしたワークスペースで`cargo test`を走らせると、ワークスペースの全クレートのテストを実行します。 +さらに最後の区域には、`add_one`クレートにドキュメンテーションテストは見つからなかったと表示されています。 + +```console +$ cargo test -p add_one + Finished test [unoptimized + debuginfo] target(s) in 0.00s + Running unittests src/lib.rs (target/debug/deps/add_one-b3235fea9a156f74) running 1 test test tests::it_works ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - Doc-tests add-one + Doc-tests add_one running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` -この出力は、`cargo test`が`add-one`クレートのテストのみを実行し、`adder`クレートのテストは実行しなかったことを示しています。 +この出力は、`cargo test`が`add_one`クレートのテストのみを実行し、`adder`クレートのテストは実行しなかったことを示しています。 -ワークスペースのクレートを *https://crates.io/* に公開したら、ワークスペースのクレートは個別に公開される必要があります。 -`cargo publish`コマンドには`--all`フラグや`-p`フラグはないので、各クレートのディレクトリに移動して、 -ワークスペースの各クレートを`cargo publish`して、公開しなければなりません。 +ワークスペースのクレートを [crates.io](https://crates.io/) に公開したら、ワークスペースのクレートは個別に公開される必要があります。 +`cargo test`のように、`-p`フラグを使用して公開したいクレートの名前を指定することで、ワークスペース内の特定のクレートを公開することができます。 -鍛錬を積むために、`add-one`クレートと同様の方法でワークスペースに`add-two`クレートを追加してください! +鍛錬を積むために、`add_one`クレートと同様の方法でワークスペースに`add_two`クレートを追加してください! プロジェクトが肥大化してきたら、ワークスペースの使用を考えてみてください: 大きな一つのコードの塊よりも、 微細で個別のコンポーネントの方が理解しやすいです。またワークスペースにクレートを保持することは、 -同時に変更されることが多いのなら、協調しやすくなることにも繋がります。 +同時に変更されることが多いのなら、クレート間の協調をしやすくなることにも繋がります。 diff --git a/src/ch14-04-installing-binaries.md b/src/ch14-04-installing-binaries.md index 7f1a140e6..4d583aa72 100644 --- a/src/ch14-04-installing-binaries.md +++ b/src/ch14-04-installing-binaries.md @@ -1,15 +1,20 @@ + -## `cargo install`でCrates.ioからバイナリをインストールする + + +## `cargo install`でバイナリをインストールする `cargo install`でインストールされるバイナリは全て、インストールのルートの*bin*フォルダに保持されます。 -Rustを`rustup`を使用し、独自の設定を何も行なっていなければ、このディレクトリは、*$HOME/.cargo/bin*になります。 +*rustup.rs*を使用しRustをインストールし、独自の設定を何も行なっていなければ、このディレクトリは、*$HOME/.cargo/bin*になります。 `cargo install`でインストールしたプログラムを実行できるようにするためには、そのディレクトリが`$PATH`に含まれていることを確かめてください。 例えば、第12章で、ファイルを検索する`ripgrep`という`grep`ツールのRust版があることに触れました。 -`ripgrep`をインストールしたかったら、以下を実行することができます: +`ripgrep`をインストールするには、以下を実行することができます: + + -```text +```console $ cargo install ripgrep -Updating registry `https://github.com/rust-lang/crates.io-index` - Downloading ripgrep v0.3.2 - --snip-- - Compiling ripgrep v0.3.2 - Finished release [optimized + debuginfo] target(s) in 97.91 secs + Updating crates.io index + Downloaded ripgrep v13.0.0 + Downloaded 1 crate (243.3 KB) in 0.88s + Installing ripgrep v13.0.0 +--snip-- + Compiling ripgrep v13.0.0 + Finished release [optimized + debuginfo] target(s) in 3m 10s Installing ~/.cargo/bin/rg + Installed package `ripgrep v13.0.0` (executable `rg`) ``` -出力の最後の行が、インストールされたバイナリの位置と名前を示していて、`ripgrep`の場合、`rg`です。 +出力の最後から2番目の行が、インストールされたバイナリの位置と名前を示していて、`ripgrep`の場合、`rg`です。 インストールディレクトリが`$PATH`に存在する限り、前述したように、`rg --help`を走らせて、 より高速でRustらしいファイル検索ツールを使用し始めることができます! diff --git a/src/ch14-05-extending-cargo.md b/src/ch14-05-extending-cargo.md index 18c30c44c..13a06ff75 100644 --- a/src/ch14-05-extending-cargo.md +++ b/src/ch14-05-extending-cargo.md @@ -26,16 +26,16 @@ Cargoのサブコマンドであるかのように実行することができま ## まとめ -Cargoで[crates.io](https://crates.io)とコードを共有することは、 +Cargoで[crates.io](https://crates.io/)とコードを共有することは、 Rustのエコシステムを多くの異なる作業に有用にするものの一部です。Rustの標準ライブラリは、 小さく安定的ですが、クレートは共有および使用しやすく、言語とは異なるタイムラインで進化します。 -積極的に[crates.io](https://crates.io)で自分にとって有用なコードを共有してください; +積極的に[crates.io](https://crates.io/)で自分にとって有用なコードを共有してください; 他の誰かにとっても、役に立つものであることでしょう! From 97d839762501a07ebe06101f7df40c9fb9c68414 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:06 +0900 Subject: [PATCH 16/22] =?UTF-8?q?ch15=20=E3=82=B9=E3=83=9E=E3=83=BC?= =?UTF-8?q?=E3=83=88=E3=83=9D=E3=82=A4=E3=83=B3=E3=82=BF=E3=81=AE=E5=92=8C?= =?UTF-8?q?=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- dot/trpl15-04.dot | 16 + .../listing-15-01/Cargo.toml | 3 +- .../listing-15-02/Cargo.toml | 3 +- .../listing-15-03/Cargo.toml | 3 +- .../listing-15-03/output.txt | 25 +- .../listing-15-05/Cargo.toml | 3 +- .../listing-15-06/Cargo.toml | 3 +- .../listing-15-07/Cargo.toml | 3 +- .../listing-15-08/Cargo.toml | 3 +- .../listing-15-09/Cargo.toml | 3 +- .../listing-15-09/output.txt | 7 +- .../listing-15-10/Cargo.toml | 3 +- .../listing-15-10/src/main.rs | 2 +- .../listing-15-11/Cargo.toml | 3 +- .../listing-15-11/src/main.rs | 2 +- .../listing-15-12/Cargo.toml | 3 +- .../listing-15-12/src/main.rs | 2 +- .../listing-15-13/Cargo.toml | 3 +- .../listing-15-13/src/main.rs | 2 +- .../listing-15-14/Cargo.toml | 3 +- .../listing-15-14/src/main.rs | 4 + .../listing-15-15/Cargo.toml | 3 +- .../listing-15-15/output.txt | 14 +- .../listing-15-15/src/main.rs | 1 + .../listing-15-16/Cargo.toml | 3 +- .../listing-15-16/src/main.rs | 1 + .../listing-15-17/Cargo.toml | 3 +- .../listing-15-17/output.txt | 6 +- .../listing-15-18/Cargo.toml | 3 +- .../listing-15-19/Cargo.toml | 3 +- .../listing-15-19/src/main.rs | 4 + .../listing-15-20/Cargo.toml | 3 +- .../listing-15-20/src/lib.rs | 5 +- .../listing-15-21/Cargo.toml | 3 +- .../listing-15-21/output.txt | 16 +- .../listing-15-21/src/lib.rs | 2 +- .../listing-15-22/Cargo.toml | 3 +- .../listing-15-22/src/lib.rs | 4 +- .../listing-15-23/Cargo.toml | 3 +- .../listing-15-23/output.txt | 13 +- .../listing-15-23/src/lib.rs | 2 +- .../listing-15-24/Cargo.toml | 3 +- .../listing-15-25/Cargo.toml | 3 +- .../listing-15-26/Cargo.toml | 3 +- .../listing-15-26/src/main.rs | 10 + .../listing-15-27/Cargo.toml | 3 +- .../listing-15-28/Cargo.toml | 3 +- .../listing-15-28/src/main.rs | 1 + .../listing-15-29/Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../output.txt | 16 +- .../Cargo.toml | 3 +- .../output.txt | 27 +- src/ch08-01-vectors.md | 2 +- src/ch15-00-smart-pointers.md | 82 ++-- src/ch15-01-box.md | 235 ++++++------ src/ch15-02-deref.md | 315 +++++++--------- src/ch15-03-drop.md | 176 ++++----- src/ch15-04-rc.md | 133 ++----- src/ch15-05-interior-mutability.md | 346 +++++------------ src/ch15-06-reference-cycles.md | 356 +++++------------- src/img/trpl15-04.svg | 129 ++++--- 62 files changed, 801 insertions(+), 1245 deletions(-) create mode 100644 dot/trpl15-04.dot diff --git a/dot/trpl15-04.dot b/dot/trpl15-04.dot new file mode 100644 index 000000000..562543cb6 --- /dev/null +++ b/dot/trpl15-04.dot @@ -0,0 +1,16 @@ +digraph { + node[shape=record]; + rankdir=LR; + + l1[label="{ 5| }"]; + l2[label="{ 10| }"]; + + {node[shape=point height=0] invisible_start invisible_end} + + a -> l1:n; + b -> l2:n; + invisible_start:n -> l1[arrowtail=none]; + invisible_start:s -> invisible_end:s[dir=none]; + l1:next:c -> l2:data; + l2:next:c -> invisible_end:n[arrowhead=none]; +} diff --git a/listings/ch15-smart-pointers/listing-15-01/Cargo.toml b/listings/ch15-smart-pointers/listing-15-01/Cargo.toml index 4a0bb9d2f..690385c7a 100644 --- a/listings/ch15-smart-pointers/listing-15-01/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "box-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-02/Cargo.toml b/listings/ch15-smart-pointers/listing-15-02/Cargo.toml index 86c8e956e..dce1515c3 100644 --- a/listings/ch15-smart-pointers/listing-15-02/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cons-list" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-03/Cargo.toml b/listings/ch15-smart-pointers/listing-15-03/Cargo.toml index 86c8e956e..dce1515c3 100644 --- a/listings/ch15-smart-pointers/listing-15-03/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cons-list" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-03/output.txt b/listings/ch15-smart-pointers/listing-15-03/output.txt index f15aaacb9..312099e84 100644 --- a/listings/ch15-smart-pointers/listing-15-03/output.txt +++ b/listings/ch15-smart-pointers/listing-15-03/output.txt @@ -1,28 +1,19 @@ $ cargo run Compiling cons-list v0.1.0 (file:///projects/cons-list) error[E0072]: recursive type `List` has infinite size +(エラー: 再帰的な型`List`は無限のサイズを持ちます) --> src/main.rs:1:1 | 1 | enum List { - | ^^^^^^^^^ recursive type has infinite size + | ^^^^^^^^^ 2 | Cons(i32, List), | ---- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable - -error[E0391]: cycle detected when processing `List` - --> src/main.rs:1:1 - | -1 | enum List { - | ^^^^^^^^^ +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle +(ヘルプ: 何らかの間接参照(例: `Box`、`Rc`、あるいは`&`)を挿入して、循環参照を断ち切ってください) | - = note: ...which again requires processing `List`, completing the cycle - = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: List } }` - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. -error: could not compile `cons-list`. +2 | Cons(i32, Box), + | ++++ + -To learn more, run the command again with --verbose. +For more information about this error, try `rustc --explain E0072`. +error: could not compile `cons-list` (bin "cons-list") due to 1 previous error diff --git a/listings/ch15-smart-pointers/listing-15-05/Cargo.toml b/listings/ch15-smart-pointers/listing-15-05/Cargo.toml index 86c8e956e..dce1515c3 100644 --- a/listings/ch15-smart-pointers/listing-15-05/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cons-list" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-06/Cargo.toml b/listings/ch15-smart-pointers/listing-15-06/Cargo.toml index 2a9630fe4..67ec198f7 100644 --- a/listings/ch15-smart-pointers/listing-15-06/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "deref-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-07/Cargo.toml b/listings/ch15-smart-pointers/listing-15-07/Cargo.toml index 2a9630fe4..67ec198f7 100644 --- a/listings/ch15-smart-pointers/listing-15-07/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "deref-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-08/Cargo.toml b/listings/ch15-smart-pointers/listing-15-08/Cargo.toml index 2a9630fe4..67ec198f7 100644 --- a/listings/ch15-smart-pointers/listing-15-08/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "deref-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-09/Cargo.toml b/listings/ch15-smart-pointers/listing-15-09/Cargo.toml index 2a9630fe4..67ec198f7 100644 --- a/listings/ch15-smart-pointers/listing-15-09/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "deref-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-09/output.txt b/listings/ch15-smart-pointers/listing-15-09/output.txt index 8fbd56124..9191ab97a 100644 --- a/listings/ch15-smart-pointers/listing-15-09/output.txt +++ b/listings/ch15-smart-pointers/listing-15-09/output.txt @@ -1,14 +1,11 @@ $ cargo run Compiling deref-example v0.1.0 (file:///projects/deref-example) error[E0614]: type `MyBox<{integer}>` cannot be dereferenced +(エラー: 型`MyBox<{integer}>`は参照外しできません) --> src/main.rs:14:19 | 14 | assert_eq!(5, *y); | ^^ -error: aborting due to previous error - For more information about this error, try `rustc --explain E0614`. -error: could not compile `deref-example`. - -To learn more, run the command again with --verbose. +error: could not compile `deref-example` (bin "deref-example") due to 1 previous error diff --git a/listings/ch15-smart-pointers/listing-15-10/Cargo.toml b/listings/ch15-smart-pointers/listing-15-10/Cargo.toml index 2a9630fe4..67ec198f7 100644 --- a/listings/ch15-smart-pointers/listing-15-10/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "deref-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-10/src/main.rs b/listings/ch15-smart-pointers/listing-15-10/src/main.rs index a97f97c9b..cce754d08 100644 --- a/listings/ch15-smart-pointers/listing-15-10/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-10/src/main.rs @@ -4,7 +4,7 @@ use std::ops::Deref; impl Deref for MyBox { type Target = T; - fn deref(&self) -> &T { + fn deref(&self) -> &Self::Target { &self.0 } } diff --git a/listings/ch15-smart-pointers/listing-15-11/Cargo.toml b/listings/ch15-smart-pointers/listing-15-11/Cargo.toml index 2a9630fe4..67ec198f7 100644 --- a/listings/ch15-smart-pointers/listing-15-11/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "deref-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-11/src/main.rs b/listings/ch15-smart-pointers/listing-15-11/src/main.rs index b73ad89c2..77a88c91f 100644 --- a/listings/ch15-smart-pointers/listing-15-11/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-11/src/main.rs @@ -1,6 +1,6 @@ // ANCHOR: here fn hello(name: &str) { - println!("Hello, {}!", name); + println!("Hello, {name}!"); } // ANCHOR_END: here diff --git a/listings/ch15-smart-pointers/listing-15-12/Cargo.toml b/listings/ch15-smart-pointers/listing-15-12/Cargo.toml index 2a9630fe4..67ec198f7 100644 --- a/listings/ch15-smart-pointers/listing-15-12/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "deref-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-12/src/main.rs b/listings/ch15-smart-pointers/listing-15-12/src/main.rs index 6a3e143cc..8cd3893cb 100644 --- a/listings/ch15-smart-pointers/listing-15-12/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-12/src/main.rs @@ -17,7 +17,7 @@ impl MyBox { } fn hello(name: &str) { - println!("Hello, {}!", name); + println!("Hello, {name}!"); } // ANCHOR: here diff --git a/listings/ch15-smart-pointers/listing-15-13/Cargo.toml b/listings/ch15-smart-pointers/listing-15-13/Cargo.toml index 2a9630fe4..67ec198f7 100644 --- a/listings/ch15-smart-pointers/listing-15-13/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "deref-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-13/src/main.rs b/listings/ch15-smart-pointers/listing-15-13/src/main.rs index ef5361c12..9debe2a31 100644 --- a/listings/ch15-smart-pointers/listing-15-13/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-13/src/main.rs @@ -17,7 +17,7 @@ impl MyBox { } fn hello(name: &str) { - println!("Hello, {}!", name); + println!("Hello, {name}!"); } // ANCHOR: here diff --git a/listings/ch15-smart-pointers/listing-15-14/Cargo.toml b/listings/ch15-smart-pointers/listing-15-14/Cargo.toml index e9ad457cf..1e4c99481 100644 --- a/listings/ch15-smart-pointers/listing-15-14/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-14/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "drop-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-14/src/main.rs b/listings/ch15-smart-pointers/listing-15-14/src/main.rs index 231612ae6..ccc3bf23c 100644 --- a/listings/ch15-smart-pointers/listing-15-14/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-14/src/main.rs @@ -4,16 +4,20 @@ struct CustomSmartPointer { impl Drop for CustomSmartPointer { fn drop(&mut self) { + // "データ`{}`を持つCustomSmartPointerをドロップ中!" println!("Dropping CustomSmartPointer with data `{}`!", self.data); } } fn main() { let c = CustomSmartPointer { + // "俺のもの" data: String::from("my stuff"), }; let d = CustomSmartPointer { + // "別のもの" data: String::from("other stuff"), }; + // "CustomSmartPointerが作成された。" println!("CustomSmartPointers created."); } diff --git a/listings/ch15-smart-pointers/listing-15-15/Cargo.toml b/listings/ch15-smart-pointers/listing-15-15/Cargo.toml index e9ad457cf..1e4c99481 100644 --- a/listings/ch15-smart-pointers/listing-15-15/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "drop-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-15/output.txt b/listings/ch15-smart-pointers/listing-15-15/output.txt index 4af05876e..ea1b0473e 100644 --- a/listings/ch15-smart-pointers/listing-15-15/output.txt +++ b/listings/ch15-smart-pointers/listing-15-15/output.txt @@ -1,14 +1,18 @@ $ cargo run Compiling drop-example v0.1.0 (file:///projects/drop-example) error[E0040]: explicit use of destructor method +(エラー: デストラクタメソッドを明示的に使用しています) --> src/main.rs:16:7 | 16 | c.drop(); | ^^^^ explicit destructor calls not allowed - -error: aborting due to previous error + | (明示的なデストラクタの呼び出しは許可されません) + | +help: consider using `drop` function +(ヘルプ: `drop`関数の使用を検討してください) + | +16 | drop(c); + | +++++ ~ For more information about this error, try `rustc --explain E0040`. -error: could not compile `drop-example`. - -To learn more, run the command again with --verbose. +error: could not compile `drop-example` (bin "drop-example") due to 1 previous error diff --git a/listings/ch15-smart-pointers/listing-15-15/src/main.rs b/listings/ch15-smart-pointers/listing-15-15/src/main.rs index ff3b391a9..fc40b5e4b 100644 --- a/listings/ch15-smart-pointers/listing-15-15/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-15/src/main.rs @@ -15,6 +15,7 @@ fn main() { }; println!("CustomSmartPointer created."); c.drop(); + // "CustomSmartPointerがmainの終端の前でドロップされた。" println!("CustomSmartPointer dropped before the end of main."); } // ANCHOR_END: here diff --git a/listings/ch15-smart-pointers/listing-15-16/Cargo.toml b/listings/ch15-smart-pointers/listing-15-16/Cargo.toml index e9ad457cf..1e4c99481 100644 --- a/listings/ch15-smart-pointers/listing-15-16/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-16/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "drop-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-16/src/main.rs b/listings/ch15-smart-pointers/listing-15-16/src/main.rs index f11715c45..bb2710df1 100644 --- a/listings/ch15-smart-pointers/listing-15-16/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-16/src/main.rs @@ -15,6 +15,7 @@ fn main() { }; println!("CustomSmartPointer created."); drop(c); + // "CustomSmartPointerがmainの終端の前でドロップされた。" println!("CustomSmartPointer dropped before the end of main."); } // ANCHOR_END: here diff --git a/listings/ch15-smart-pointers/listing-15-17/Cargo.toml b/listings/ch15-smart-pointers/listing-15-17/Cargo.toml index 86c8e956e..dce1515c3 100644 --- a/listings/ch15-smart-pointers/listing-15-17/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-17/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cons-list" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-17/output.txt b/listings/ch15-smart-pointers/listing-15-17/output.txt index 5966a71ec..757a65fb5 100644 --- a/listings/ch15-smart-pointers/listing-15-17/output.txt +++ b/listings/ch15-smart-pointers/listing-15-17/output.txt @@ -10,9 +10,5 @@ error[E0382]: use of moved value: `a` 11 | let c = Cons(4, Box::new(a)); | ^ value used here after move -error: aborting due to previous error - For more information about this error, try `rustc --explain E0382`. -error: could not compile `cons-list`. - -To learn more, run the command again with --verbose. +error: could not compile `cons-list` (bin "cons-list") due to 1 previous error diff --git a/listings/ch15-smart-pointers/listing-15-18/Cargo.toml b/listings/ch15-smart-pointers/listing-15-18/Cargo.toml index 86c8e956e..dce1515c3 100644 --- a/listings/ch15-smart-pointers/listing-15-18/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-18/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cons-list" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-19/Cargo.toml b/listings/ch15-smart-pointers/listing-15-19/Cargo.toml index 86c8e956e..dce1515c3 100644 --- a/listings/ch15-smart-pointers/listing-15-19/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-19/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cons-list" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-19/src/main.rs b/listings/ch15-smart-pointers/listing-15-19/src/main.rs index 1bd7bc533..bcf98a6a1 100644 --- a/listings/ch15-smart-pointers/listing-15-19/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-19/src/main.rs @@ -9,13 +9,17 @@ use std::rc::Rc; // ANCHOR: here fn main() { let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil))))); + // "a作成後のカウント = {}" println!("count after creating a = {}", Rc::strong_count(&a)); let b = Cons(3, Rc::clone(&a)); + // "b作成後のカウント = {}" println!("count after creating b = {}", Rc::strong_count(&a)); { let c = Cons(4, Rc::clone(&a)); + // "c作成後のカウント = {}" println!("count after creating c = {}", Rc::strong_count(&a)); } + // "cがスコープを抜けた後のカウント = {}" println!("count after c goes out of scope = {}", Rc::strong_count(&a)); } // ANCHOR_END: here diff --git a/listings/ch15-smart-pointers/listing-15-20/Cargo.toml b/listings/ch15-smart-pointers/listing-15-20/Cargo.toml index b230a2326..98c3f537c 100644 --- a/listings/ch15-smart-pointers/listing-15-20/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-20/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "limit-tracker" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-20/src/lib.rs b/listings/ch15-smart-pointers/listing-15-20/src/lib.rs index d3a900373..4fc9f72d5 100644 --- a/listings/ch15-smart-pointers/listing-15-20/src/lib.rs +++ b/listings/ch15-smart-pointers/listing-15-20/src/lib.rs @@ -12,7 +12,7 @@ impl<'a, T> LimitTracker<'a, T> where T: Messenger, { - pub fn new(messenger: &T, max: usize) -> LimitTracker { + pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> { LimitTracker { messenger, value: 0, @@ -26,11 +26,14 @@ where let percentage_of_max = self.value as f64 / self.max as f64; if percentage_of_max >= 1.0 { + // "エラー: 割り当てを超えています!" self.messenger.send("Error: You are over your quota!"); } else if percentage_of_max >= 0.9 { + // "緊急警告: 割り当ての90%以上を使用してしまいました!" self.messenger .send("Urgent warning: You've used up over 90% of your quota!"); } else if percentage_of_max >= 0.75 { + // "警告: 割り当ての75%以上を使用してしまいました!" self.messenger .send("Warning: You've used up over 75% of your quota!"); } diff --git a/listings/ch15-smart-pointers/listing-15-21/Cargo.toml b/listings/ch15-smart-pointers/listing-15-21/Cargo.toml index b230a2326..98c3f537c 100644 --- a/listings/ch15-smart-pointers/listing-15-21/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-21/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "limit-tracker" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-21/output.txt b/listings/ch15-smart-pointers/listing-15-21/output.txt index 851b5caf9..1ec0a84b9 100644 --- a/listings/ch15-smart-pointers/listing-15-21/output.txt +++ b/listings/ch15-smart-pointers/listing-15-21/output.txt @@ -1,16 +1,18 @@ $ cargo test Compiling limit-tracker v0.1.0 (file:///projects/limit-tracker) error[E0596]: cannot borrow `self.sent_messages` as mutable, as it is behind a `&` reference +(エラー: `self.sent_messages`は`&`参照の後ろにあるので、可変として借用できません) --> src/lib.rs:58:13 | -57 | fn send(&self, message: &str) { - | ----- help: consider changing this to be a mutable reference: `&mut self` 58 | self.sent_messages.push(String::from(message)); | ^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to previous error + | (`self`は`&`参照なので、それが参照するデータは可変として借用できません) + | +help: consider changing this to be a mutable reference +(ヘルプ: 可変参照に変更することを検討してください) + | +2 | fn send(&mut self, msg: &str); + | ~~~~~~~~~ For more information about this error, try `rustc --explain E0596`. -error: could not compile `limit-tracker`. - -To learn more, run the command again with --verbose. +error: could not compile `limit-tracker` (lib test) due to 1 previous error diff --git a/listings/ch15-smart-pointers/listing-15-21/src/lib.rs b/listings/ch15-smart-pointers/listing-15-21/src/lib.rs index 9e403e3ca..4572d4313 100644 --- a/listings/ch15-smart-pointers/listing-15-21/src/lib.rs +++ b/listings/ch15-smart-pointers/listing-15-21/src/lib.rs @@ -12,7 +12,7 @@ impl<'a, T> LimitTracker<'a, T> where T: Messenger, { - pub fn new(messenger: &T, max: usize) -> LimitTracker { + pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> { LimitTracker { messenger, value: 0, diff --git a/listings/ch15-smart-pointers/listing-15-22/Cargo.toml b/listings/ch15-smart-pointers/listing-15-22/Cargo.toml index b230a2326..98c3f537c 100644 --- a/listings/ch15-smart-pointers/listing-15-22/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-22/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "limit-tracker" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-22/src/lib.rs b/listings/ch15-smart-pointers/listing-15-22/src/lib.rs index dc259f7fc..a77ffa41c 100644 --- a/listings/ch15-smart-pointers/listing-15-22/src/lib.rs +++ b/listings/ch15-smart-pointers/listing-15-22/src/lib.rs @@ -12,7 +12,7 @@ impl<'a, T> LimitTracker<'a, T> where T: Messenger, { - pub fn new(messenger: &T, max: usize) -> LimitTracker { + pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> { LimitTracker { messenger, value: 0, @@ -76,5 +76,3 @@ mod tests { } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch15-smart-pointers/listing-15-23/Cargo.toml b/listings/ch15-smart-pointers/listing-15-23/Cargo.toml index b230a2326..98c3f537c 100644 --- a/listings/ch15-smart-pointers/listing-15-23/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-23/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "limit-tracker" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-23/output.txt b/listings/ch15-smart-pointers/listing-15-23/output.txt index 9d69d439c..ead441672 100644 --- a/listings/ch15-smart-pointers/listing-15-23/output.txt +++ b/listings/ch15-smart-pointers/listing-15-23/output.txt @@ -1,7 +1,7 @@ $ cargo test Compiling limit-tracker v0.1.0 (file:///projects/limit-tracker) Finished test [unoptimized + debuginfo] target(s) in 0.91s - Running target/debug/deps/limit_tracker-d1b2637139dca6ca + Running unittests src/lib.rs (target/debug/deps/limit_tracker-e599811fa246dbde) running 1 test test tests::it_sends_an_over_75_percent_warning_message ... FAILED @@ -9,13 +9,16 @@ test tests::it_sends_an_over_75_percent_warning_message ... FAILED failures: ---- tests::it_sends_an_over_75_percent_warning_message stdout ---- -thread 'main' panicked at 'already borrowed: BorrowMutError', src/libcore/result.rs:1188:5 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +thread 'tests::it_sends_an_over_75_percent_warning_message' panicked at src/lib.rs:60:53: +already borrowed: BorrowMutError +(スレッド'tests::it_sends_an_over_75_percent_warning_message'は、src/lib.rs:60:53でパニックしました: +すでに借用されています: BorrowMutError) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::it_sends_an_over_75_percent_warning_message -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s -error: test failed, to rerun pass '--lib' +error: test failed, to rerun pass `--lib` diff --git a/listings/ch15-smart-pointers/listing-15-23/src/lib.rs b/listings/ch15-smart-pointers/listing-15-23/src/lib.rs index 4e599ddc8..7d288e680 100644 --- a/listings/ch15-smart-pointers/listing-15-23/src/lib.rs +++ b/listings/ch15-smart-pointers/listing-15-23/src/lib.rs @@ -12,7 +12,7 @@ impl<'a, T> LimitTracker<'a, T> where T: Messenger, { - pub fn new(messenger: &T, max: usize) -> LimitTracker { + pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> { LimitTracker { messenger, value: 0, diff --git a/listings/ch15-smart-pointers/listing-15-24/Cargo.toml b/listings/ch15-smart-pointers/listing-15-24/Cargo.toml index 86c8e956e..dce1515c3 100644 --- a/listings/ch15-smart-pointers/listing-15-24/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-24/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cons-list" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-25/Cargo.toml b/listings/ch15-smart-pointers/listing-15-25/Cargo.toml index 86c8e956e..dce1515c3 100644 --- a/listings/ch15-smart-pointers/listing-15-25/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-25/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cons-list" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-26/Cargo.toml b/listings/ch15-smart-pointers/listing-15-26/Cargo.toml index 86c8e956e..dce1515c3 100644 --- a/listings/ch15-smart-pointers/listing-15-26/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-26/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "cons-list" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-26/src/main.rs b/listings/ch15-smart-pointers/listing-15-26/src/main.rs index 08963aaa5..5a1e2020b 100644 --- a/listings/ch15-smart-pointers/listing-15-26/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-26/src/main.rs @@ -21,24 +21,34 @@ impl List { fn main() { let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil)))); + // "aの最初の参照カウント = {}" println!("a initial rc count = {}", Rc::strong_count(&a)); + // "aの次の要素は = {:?}" println!("a next item = {:?}", a.tail()); let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a)))); + // "b作成後のaの参照カウント = {}" println!("a rc count after b creation = {}", Rc::strong_count(&a)); + // "bの最初の参照カウント = {}" println!("b initial rc count = {}", Rc::strong_count(&b)); + // "bの次の要素 = {:?}" println!("b next item = {:?}", b.tail()); if let Some(link) = a.tail() { *link.borrow_mut() = Rc::clone(&b); } + // "aを変更後のbの参照カウント = {}" println!("b rc count after changing a = {}", Rc::strong_count(&b)); + // "aを変更後のaの参照カウント = {}" println!("a rc count after changing a = {}", Rc::strong_count(&a)); // Uncomment the next line to see that we have a cycle; // it will overflow the stack + // 次の行のコメントを外して循環していると確認してください; + // スタックオーバーフローします + // // "aの次の要素 = {:?}" // println!("a next item = {:?}", a.tail()); } // ANCHOR_END: here diff --git a/listings/ch15-smart-pointers/listing-15-27/Cargo.toml b/listings/ch15-smart-pointers/listing-15-27/Cargo.toml index d6774b817..0bbf897d0 100644 --- a/listings/ch15-smart-pointers/listing-15-27/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-27/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "tree" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-28/Cargo.toml b/listings/ch15-smart-pointers/listing-15-28/Cargo.toml index d6774b817..0bbf897d0 100644 --- a/listings/ch15-smart-pointers/listing-15-28/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-28/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "tree" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/listing-15-28/src/main.rs b/listings/ch15-smart-pointers/listing-15-28/src/main.rs index fabd1cbce..1f77febd5 100644 --- a/listings/ch15-smart-pointers/listing-15-28/src/main.rs +++ b/listings/ch15-smart-pointers/listing-15-28/src/main.rs @@ -18,6 +18,7 @@ fn main() { children: RefCell::new(vec![]), }); + // "leafの親 = {:?}" println!("leaf parent = {:?}", leaf.parent.borrow().upgrade()); let branch = Rc::new(Node { diff --git a/listings/ch15-smart-pointers/listing-15-29/Cargo.toml b/listings/ch15-smart-pointers/listing-15-29/Cargo.toml index d6774b817..0bbf897d0 100644 --- a/listings/ch15-smart-pointers/listing-15-29/Cargo.toml +++ b/listings/ch15-smart-pointers/listing-15-29/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "tree" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/Cargo.toml b/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/Cargo.toml index 1558eb615..16f92447f 100644 --- a/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/Cargo.toml +++ b/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "borrowing" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt b/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt index c8e5592de..1fb8139a8 100644 --- a/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt +++ b/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt @@ -1,16 +1,18 @@ $ cargo run Compiling borrowing v0.1.0 (file:///projects/borrowing) error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable +(エラー: `x`は可変として宣言されていないので、可変として借用することはできません) --> src/main.rs:3:13 | -2 | let x = 5; - | - help: consider changing this to be mutable: `mut x` 3 | let y = &mut x; | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error + | (可変として借用できません) + | +help: consider changing this to be mutable +(ヘルプ: これを可変に変更することを考慮してください) + | +2 | let mut x = 5; + | +++ For more information about this error, try `rustc --explain E0596`. -error: could not compile `borrowing`. - -To learn more, run the command again with --verbose. +error: could not compile `borrowing` (bin "borrowing") due to 1 previous error diff --git a/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/Cargo.toml b/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/Cargo.toml index 2a9630fe4..67ec198f7 100644 --- a/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/Cargo.toml +++ b/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "deref-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt b/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt index 4368ee65f..3e89cf55a 100644 --- a/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt +++ b/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt @@ -1,17 +1,28 @@ $ cargo run Compiling deref-example v0.1.0 (file:///projects/deref-example) error[E0277]: can't compare `{integer}` with `&{integer}` +(エラー: `{integer}`を`&{integer}`と比較することはできません) --> src/main.rs:6:5 | 6 | assert_eq!(5, y); - | ^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &{integer}` + | ^^^^^^^^^^^^^^^^ no implementation for `{integer} == &{integer}` + | (`{integer} == &{integer}`のための実装はありません) | - = help: the trait `std::cmp::PartialEq<&{integer}>` is not implemented for `{integer}` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error: aborting due to previous error + = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}` + (ヘルプ: トレイト`PartialEq<&{integer}>`は`{integer}`に対して実装されていません) + = help: the following other types implement trait `PartialEq`: + (ヘルプ: 以下の型であればトレイト`PartialEq`を実装しています:) + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 + and 6 others + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + (注釈: このエラーはマクロ`assert_eq`に由来します (nightlyビルドでは、詳細を得るには-Z macro-bactraceを実行してください)) For more information about this error, try `rustc --explain E0277`. -error: could not compile `deref-example`. - -To learn more, run the command again with --verbose. +error: could not compile `deref-example` (bin "deref-example") due to 1 previous error diff --git a/src/ch08-01-vectors.md b/src/ch08-01-vectors.md index 57ee7a6c2..54b9447c3 100644 --- a/src/ch08-01-vectors.md +++ b/src/ch08-01-vectors.md @@ -500,4 +500,4 @@ Let’s move on to the next collection type: `String`! [data-types]: ch03-02-data-types.html#データ型 [nomicon]: ../nomicon/vec/vec.html [vec-api]: ../std/vec/struct.Vec.html -[deref]: ch15-02-deref.html#参照外し演算子で値までポインタを追いかける +[deref]: ch15-02-deref.html#値までポインタを追いかける diff --git a/src/ch15-00-smart-pointers.md b/src/ch15-00-smart-pointers.md index 5606899cc..ba173fe15 100644 --- a/src/ch15-00-smart-pointers.md +++ b/src/ch15-00-smart-pointers.md @@ -10,70 +10,68 @@ memory. This address refers to, or “points at,” some other data. The most common kind of pointer in Rust is a reference, which you learned about in Chapter 4. References are indicated by the `&` symbol and borrow the value they point to. They don’t have any special capabilities other than referring to -data. Also, they don’t have any overhead and are the kind of pointer we use -most often. +data, and have no overhead. --> *ポインタ*は、メモリのアドレスを含む変数の一般的な概念です。このアドレスは、何らかの他のデータを参照、または「指します」。 -Rustにおいて最もありふれた種類のポインタは参照です。参照については第4章で習いましたね。参照は`&`記号で示唆され、指している値を借用します。データを参照すること以外に特別な能力は何もありません。 -また、オーバーヘッドもなく、ポインタの中では最も頻繁に使われます。 +Rustにおいて最もありふれた種類のポインタは参照です。参照については第4章で習いましたね。参照は`&`記号で示唆され、指している値を借用します。 +データを参照すること以外に特別な能力は何もなく、オーバーヘッドもありません。 -一方、*スマートポインタ*は、ポインタのように振る舞うだけでなく、追加のメタデータと能力があるデータ構造です。 +一方、*スマートポインタ*は、ポインタのように振る舞いますが、追加のメタデータと能力があるデータ構造です。 スマートポインタという概念は、Rustに特有のものではありません。スマートポインタは、C++に端を発し、 -他の言語にも存在しています。Rustでは、標準ライブラリに定義された色々なスマートポインタが、 -参照以上の機能を提供します。この章で探究する一つの例が、*参照カウント*方式のスマートポインタ型です。 +他の言語にも存在しています。Rustには、参照以上の機能を提供する色々なスマートポインタが標準ライブラリに定義されています。 +一般的な概念を探索するために、いくつかのスマートポインタの例を見ていきますが、その一つが*参照カウント*方式のスマートポインタ型です。 このポインタのおかげでデータに複数の所有者を持たせることができます。 所有者の数を追いかけ、所有者がいなくなったらデータの片付けをしてくれるからです。 -所有権と借用の概念を使うRustにおいて、参照とスマートポインタにはもう1つ違いがあります。参照はデータを借用するだけのポインタなのです。 -対照的に多くの場合、スマートポインタは指しているデータを*所有*します。 +所有権と借用の概念を持つRustでは、参照とスマートポインタにはもう1つ違いがあります: +参照はデータを借用するだけである一方で、スマートポインタは、多くの場合、指しているデータを*所有*します。 -私達はすでに、この本の中でいくつかのスマートポインタに遭遇してきました。例えば第8章の`String`や`Vec`です。ただし、私達はそれらをスマートポインタとは呼んでいませんでした。 -これらの型がどちらもスマートポインタに数えられるのは、あるメモリを所有しそれを弄ることができるからです。 -また、メタデータ(キャパシティなど)や追加の能力、あるいは保証(`String`ならデータが常に有効なUTF-8であると保証することなど)もあります。 +そのときはそう呼ばなかったものの、私達はすでに、この本の中でいくつかのスマートポインタに遭遇してきました。 +例えば第8章の`String`や`Vec`です。これらの型はどちらも、あるメモリを所有しそれを弄ることができるので、 +スマートポインタと見なされます。また、メタデータや追加の能力、あるいは保証もあります。 +例えば`String`は、その許容量をメタデータとして保持し、データが常に有効なUTF-8であると保証する追加の能力を持ちます。 -スマートポインタは普通、構造体を使用して実装されています。スマートポインタを通常の構造体と区別する特徴は、 -スマートポインタが`Deref`と`Drop`トレイトを実装していることです。`Deref`トレイトにより、スマートポインタ構造体のインスタンスは、 -参照のように振る舞うことができるので、参照あるいはスマートポインタのどちらとも動作するコードを書くことができます。 +スマートポインタは普通、構造体を使用して実装されています。通常の構造体とは異なり、 +スマートポインタが`Deref`と`Drop`トレイトを実装します。`Deref`トレイトにより、スマートポインタ構造体のインスタンスは、 +参照のように振る舞うことができるので、参照あるいはスマートポインタのどちらとも動作するようにコードを書くことができます。 `Drop`トレイトにより、スマートポインタのインスタンスがスコープを外れた時に走るコードをカスタマイズすることができます。 この章では、どちらのトレイトについても議論し、これらのトレイトがスマートポインタにとって重要な理由を説明します。 @@ -92,7 +90,7 @@ cover the most common smart pointers in the standard library: * `Box` for allocating values on the heap * `Rc`, a reference counting type that enables multiple ownership * `Ref` and `RefMut`, accessed through `RefCell`, a type that enforces -the borrowing rules at runtime instead of compile time + the borrowing rules at runtime instead of compile time --> * ヒープに値を確保する`Box` diff --git a/src/ch15-01-box.md b/src/ch15-01-box.md index bb3ddb48a..5dec7b187 100644 --- a/src/ch15-01-box.md +++ b/src/ch15-01-box.md @@ -26,11 +26,11 @@ either. You’ll use them most often in these situations: * コンパイル時にはサイズを知ることができない型があり、正確なサイズを要求する文脈でその型の値を使用する時 @@ -43,22 +43,24 @@ implements a particular trait rather than being of a specific type --> -「ボックスで再帰的な型を可能にする」節で1つ目の場合について実際に説明します。 +[「ボックスで再帰的な型を可能にする」](#ボックスで再帰的な型を可能にする)節で1つ目の場合について実際に説明します。 2番目の場合、多くのデータの所有権を転送するには、データがスタック上でコピーされるので、長い時間がかかり得ます。 この場面でパフォーマンスを向上させるために、多くのデータをヒープ上にボックスとして格納することができます。 そして、小さなポインタのデータのみがスタック上でコピーされる一方、それが参照しているデータはヒープ上の1箇所に留まります。 -3番目のケースは*トレイトオブジェクト*として知られています。第17章の「トレイトオブジェクトで異なる型の値を許容する」の節は、 +3番目のケースは*トレイトオブジェクト*として知られています。第17章の[「トレイトオブジェクトで異なる型の値を許容する」][trait-objects]の節は、 すべてその話題に捧げられています。 従って、ここで学ぶことは第17章でもまた使うことになります! @@ -69,11 +71,11 @@ to that topic. So what you learn here you’ll apply again in Chapter 17! ### `Box`を使ってヒープにデータを格納する -`Box`のこのユースケースを議論する前に、`Box`の記法と、`Box`内に格納された値を読み書きする方法について講義しましょう。 +`Box`のヒープストレージのユースケースを議論する前に、`Box`の記法と、`Box`内に格納された値を読み書きする方法について講義しましょう。 変数`b`を定義して`Box`の値を保持します。`Box`は値`5`を指し、値`5`はヒープに確保されています。このプログラムは、`b = 5`と出力するでしょう。つまりこの場合、このデータがスタックにあるのと同じような方法でボックスのデータにアクセスできます。 所有された値と全く同じでスコープを抜けるとき、実際`b`は`main`の終わりで抜けるのですが、 -ボックスはメモリから解放されます。メモリの解放は(スタックに格納されている)ボックスと(ヒープに格納されている)指しているデータに対して起きます。 +ボックスはメモリから解放されます。メモリの解放は(スタックに格納されている)ボックスと(ヒープに格納されている)指しているデータの両方に対して起きます。 -コンパイル時にコンパイラが知っておかねばならないのは、ある型が占有する領域の大きさです。コンパイル時にサイズがわからない型の1つ -として -*再帰的な型*があります。この型の値は、値の一部として同じ型の他の値を持つ場合があります。値のこうしたネストは、理論的には無限に続く可能性があるので、コンパイラは再帰的な型の値が必要とする領域を知ることができないのです。 -しかしながら、ボックスのサイズはわかっているので、再帰的な型の定義にボックスを挟むことで再帰的な型を作ることができます。 +*再帰的な型*の値は、値の一部として同じ型の他の値を持つことができます。再帰的な型はある問題を提起します。 +コンパイラは、コンパイル時にある型が占有する領域の大きさを知っておかなくてはならないからです。 +しかし、再帰的な型の値のネストは、理論的には無限に続く可能性があるので、コンパイラはその値が必要とする領域の大きさを知ることができないのです。 +ボックスのサイズはわかっているので、再帰的な型の定義にボックスを挟むことで、再帰的な型を作ることができます。 -*コンスリスト*は関数型プログラミング言語では一般的なデータ型ですが、これを再帰的な型の例として探究しましょう。 +再帰的な型の例として、*コンスリスト*を探究しましょう。これは関数型プログラミング言語でよく見られるデータ型です。 我々が定義するコンスリストは、再帰を除けば素直です。故に、これから取り掛かる例に現れる概念は、 再帰的な型が関わるもっと複雑な場面に遭遇したときには必ず役に立つでしょう。 @@ -167,14 +166,16 @@ more complex situations involving recursive types. -コンスリストは、Lispプログラミング言語とその方言に由来するデータ構造です。Lispでは、 -`cons`関数("construct function"の省略形です)は2つの引数から新しいペアを構成します。 -この引数は通常、単独の値と別のペアからなります。これらのペアを含むペアがリストをなすのです。 +コンスリストは、Lispプログラミング言語とその方言に由来するデータ構造で、ネストされたペアによって構成される、 +Lisp版の連結リストです。その名前は、2つの引数から新しいペアを構築するLispの`cons`関数("construct function"の省略形です)に由来します。 +`cons`を、値と別のペアからなるペアに対して呼び出すことで、再帰的なペアからなるコンスリストを構築することができます。 + +例えば、リスト 1, 2, 3 を含むコンスリストを、丸かっこを各ペアする擬似コードで表現すると、次のようになります: + +```text +(1, (2, (3, Nil))) +``` + -関数型プログラミング言語ではコンスリストは頻繁に使われますが、Rustではあまり使用されないデータ構造です。 +コンスリストはRustではあまり使用されないデータ構造です。 Rustで要素のリストがあるときはほとんど、`Vec`を使用するのがよりよい選択になります。 -より複雑な他の再帰的なデータ型は様々な場面で役に立ち*ます*。しかしコンスリストから始めることで、 +より複雑な他の再帰的なデータ型は様々な場面で役に立ち*ます*。しかしこの章ではコンスリストから始めることで、 ボックスのおかげで再帰的なデータ型を定義できるわけを、あまり気を散らすことなく調べることができるのです。 > 注釈: この例のために`i32`値だけを保持するコンスリストを実装します。第10章で議論したように、 @@ -266,12 +274,8 @@ Listing 15-3: ファイル名: src/main.rs -```rust,ignore -use List::{Cons, Nil}; - -fn main() { - let list = Cons(1, Cons(2, Cons(3, Nil))); -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-03/src/main.rs:here}} ``` src/main.rs:1:1 - | -1 | enum List { - | ^^^^^^^^^ recursive type has infinite size -2 | Cons(i32, List), - | ----- recursive without indirection - | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to - make `List` representable - (助言: 間接参照(例: `Box`、`Rc`、あるいは`&`)をどこかに挿入して、`List`を表現可能にしてください) +```console +{{#include ../listings/ch15-smart-pointers/listing-15-03/output.txt}} ``` エラーは、この型は「無限のサイズである」と表示しています。理由は、再帰的な列挙子を含む`List`を定義したからです。 つまり、`List`は自身の別の値を直接保持しているのです。結果として、コンパイラは`List`値を格納するのに必要な領域が計算できません。 -このエラーが出た理由を少し噛み砕きましょう。まず、非再帰的な型の値を格納するのに必要な領域をどうコンパイラが決定しているかを見ましょう。 +このエラーが出た理由を噛み砕きましょう。まず、非再帰的な型の値を格納するのに必要な領域をどうコンパイラが決定しているかを見ましょう。 -コンパイラは、再帰的に定義された型に必要なメモリ量を計算できないので、リスト15-4ではエラーを返します。 -しかし、エラーにはこんな役立つ提案が含まれているのです。 +コンパイラは、再帰的に定義された型に必要なメモリ量を計算できないので、以下の役に立つ提案を含むエラーを返します: + + ```text - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to - make `List` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle +(ヘルプ: 何らかの間接参照(例: `Box`、`Rc`、あるいは`&`)を挿入して、循環を断ち切ってください) + | +2 | Cons(i32, Box), + | ++++ + ``` -この提案において「間接参照」は、値を直接格納するのではなく、データ構造を変更して値を間接的に格納することを意味します。これは値の代わりに値へのポインタを格納することによって可能になります。 +この提案において「間接参照」は、値を直接格納するのではなく、データ構造を変更して値を間接的に格納すべきであるという意味です。 +これは値の代わりに値へのポインタを格納することによって可能になります。 `Box`はポインタなので、コンパイラには`Box`が必要とする領域が必ずわかります。すなわち、ポインタのサイズは指しているデータの量に左右されません。つまり、別の`List`値を直接置く代わりに、 `Cons`列挙子の中に`Box`を配置することができます。`Box`は、 `Cons`列挙子の中ではなく、ヒープに置かれる次の`List`値を指します。概念的には、 -依然として我々のリストは他のリストを「保持する」リストによって作られたものです。 +依然として我々のリストは他のリストを保持するリストによって作られたものです。 しかし、今やこの実装は、要素をお互いの中に配置するというより、隣り合うように配置するような感じになります。 -`Cons`列挙子は、1つの`i32`のサイズに加えてボックスのポインタデータを格納する領域を必要とするでしょう。 +`Cons`列挙子は、1つの`i32`のサイズに加えてボックスのポインタデータを格納する領域を必要とします。 `Nil`列挙子は値を格納しないので、`Cons`列挙子よりも必要な領域は小さいです。これで、 どんな`List`値も`i32`1つのサイズに加えてボックスのポインタデータのサイズを必要とすることがわかりました。 ボックスを使うことで無限に続く再帰の連鎖を断ち切ったので、コンパイラは`List`値を格納するのに必要なサイズを計算できます。 @@ -515,7 +496,7 @@ because `Cons` holds a `Box` `Box`型がスマートポインタなのは、`Deref`トレイトを実装しているからです。 このトレイトにより`Box`の値を参照のように扱うことができます。 `Box`値がスコープを抜けると、ボックスが参照しているヒープデータも片付けられます。これは`Drop`トレイト実装のおかげです。 -これら2つのトレイトをより詳しく探究しましょう。これら2つのトレイトは、他のスマートポインタ型が提供する機能にとってさらに重要なものです。それらついてはこの章の残りで議論します。 +これら2つのトレイトは、他のスマートポインタ型が提供する機能にとってさらに重要なものです。それらついてはこの章の残りで議論します。 +これら2つのトレイトをより詳しく探究しましょう。 + + + +[trait-objects]: ch17-02-trait-objects.html#トレイトオブジェクトで異なる型の値を許容する + diff --git a/src/ch15-02-deref.md b/src/ch15-02-deref.md index b508d99b5..f0a5cfeb5 100644 --- a/src/ch15-02-deref.md +++ b/src/ch15-02-deref.md @@ -6,22 +6,22 @@ -`Deref`トレイトを実装することで、*参照外し演算子*の`*`(掛け算やグロブ演算子とは違います)の振る舞いをカスタマイズできます。 +`Deref`トレイトを実装することで、*参照外し演算子*の`*`(掛け算やグロブ演算子と混同しないてください)の振る舞いをカスタマイズできます。 `Deref`を実装してスマートポインタを普通の参照みたいに扱えるようにすれば、 参照に対して処理を行うコードを書いて、そのコードをスマートポインタに対しても使うことができるのです。 @@ -32,20 +32,37 @@ or smart pointers. そして、Rustには*参照外し型強制*という機能があり、その機能のおかげで参照やスマートポインタをうまく使うことができるので、それに目を向けてみましょう。 -### 参照外し演算子で値までポインタを追いかける +> 注釈: 私たちが構築しようとしている`MyBox`型と本物の`Box`との間には、1つ大きな違いがあります: +> 私たちのバージョンはヒープ上にデータを保存しません。 +> 私たちは`Deref`の例として注目しているので、データが実際にどこに保存されるかは、 +> ポインタのように振る舞うかどうかに比べて、重要ではありません。 + + + + + + +### 値までポインタを追いかける 普通の参照は1種のポインタであり、ポインタはどこか他の場所に格納された値への矢印と見なすことができます。 -リスト15-6では、`i32`値への参照を生成してから参照外し演算子を使ってデータまで参照を辿ります。 +リスト15-6では、`i32`値への参照を生成してから参照外し演算子を使って値まで参照を辿ります。 変数`x`は`i32`値の`5`を保持しています。`y`は`x`への参照として設定します。`x`は`5`に等しいとアサートできます。 -しかしながら、`y`の値に関するアサートを行いたい場合、`*y`を使用して参照が指している値まで追いかけなければなりません(そのため*参照外し*です)。 +しかしながら、`y`の値に関するアサートを行いたい場合、コンパイラが実際の値と比較できるように、 +`*y`を使用して参照が指している値まで追いかけなければなりません(そのため*参照外し*です)。 一旦`y`の参照を外せば、`y`が指している整数値にアクセスできます。これは`5`と比較可能です。 src/main.rs:6:5 - | -6 | assert_eq!(5, y); - | ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `&{integer}` - | - = help: the trait `std::cmp::PartialEq<&{integer}>` is not implemented for - `{integer}` - (助言: トレイト`std::cmp::PartialEq<&{integer}>`は`{integer}`に対して実装されていません) +```console +{{#include ../listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt}} ``` 数値と数値への参照の比較は許されていません。これらは異なる型だからです。参照外し演算子を使用して、 @@ -121,11 +123,14 @@ to the value it's pointing to. リスト15-6のコードを、参照の代わりに`Box`を使うように書き直すことができます。 -参照外し演算子は、リスト15-7に示したように動くでしょう。 +リスト15-7に`Box`に対して使用されている参照外し演算子は、 +リスト15-6で参照に対して使用されている参照外し演算子と同じように機能するでしょう: -リスト15-7とリスト15-6の唯一の違いは、ここでは`y`が、`x`の値を指す参照ではなく、 -`x`の値を指すボックスのインスタンスとして設定されている点にあります。 -最後のアサートでは、参照外し演算子を使ってボックスのポインタを辿ることができます。これは`y`が参照だった時と同じやり方です。 -参照外し演算子が使える以上`Box`には特別な何かがあるので、次はそれについて調べることにします。そのために、独自にボックス型を定義します。 +リスト15-7とリスト15-6の主な違いは、ここでは`y`が、`x`の値を指す参照ではなく、 +`x`からコピーされた値を指す`Box`のインスタンスとして設定されている点にあります。 +最後のアサートでは、参照外し演算子を使って`Box`のポインタを辿ることができます。これは`y`が参照だった時と同じやり方です。 +参照外し演算子が使える以上`Box`には特別な何かがあるので、次はそれについて調べることにします。そのために、独自の型を定義します。 @@ -196,13 +196,7 @@ Listing 15-8 defines a `MyBox` type in the same way. We’ll also define a ファイル名: src/main.rs ```rust -struct MyBox(T); - -impl MyBox { - fn new(x: T) -> MyBox { - MyBox(x) - } -} +{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-08/src/main.rs:here}} ``` src/main.rs:14:19 - | -14 | assert_eq!(5, *y); - | ^^ +```console +{{#include ../listings/ch15-smart-pointers/listing-15-09/output.txt}} ``` -第10章で議論したように、トレイトを実装するにはトレイトの必須メソッドに実装を与える必要があります。 +第10章の[「トレイトを型に実装する」][impl-trait]節で議論したように、トレイトを実装するにはトレイトの必須メソッドに実装を与える必要があります。 `Deref`トレイトは標準ライブラリで提供されており、`deref`という1つのメソッドの実装を要求します。`deref`は`self`を借用し、 内部のデータへの参照を返すメソッドです。 リスト15-10には、`MyBox`の定義に付け足す`Deref`の実装が含まれています。 @@ -305,16 +289,7 @@ contains an implementation of `Deref` to add to the definition of `MyBox`: ファイル名: src/main.rs ```rust -use std::ops::Deref; - -# struct MyBox(T); -impl Deref for MyBox { - type Target = T; - - fn deref(&self) -> &T { - &self.0 - } -} +{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-10/src/main.rs:here}} ``` -`type Target = T;`という記法は、`Deref`トレイトが使用する関連型を定義しています。関連型はまた少し違ったやり方でジェネリック引数を宣言するためのものですが、今は気にする必要はありません。第19章でより詳しく扱います。 +`type Target = T;`という記法は、`Deref`トレイトが使用する関連型を定義しています。 +関連型はまた少し違ったやり方でジェネリック引数を宣言するためのものですが、今は気にする必要はありません。 +第19章でより詳しく扱います。 -`deref`メソッドの本体は`&self.0`だけなので、`deref`が返すのは私達が`*`演算子でアクセスしたい値への参照なわけです。 +`deref`が`*`演算子でアクセスしたい値への参照を返すように、`deref`メソッドの本体は`&self.0`で埋めました; +第5章の[「異なる型を生成する名前付きフィールドのないタプル構造体を使用する」][tuple-structs]節で触れたように、 +`.0`はタプル構造体の最初の値にアクセスするということを思い出してください。 リスト15-9の`MyBox`に`*`を呼び出す`main`関数はこれでコンパイルでき、アサートも通ります! `deref`メソッドが値への参照を返し、`*(y.deref())`のかっこの外にある普通の参照外しがそれでも必要になるのは、 -所有権システムがあるからです。`deref`メソッドが値への参照ではなく値を直接返したら、値は`self`から外にムーブされてしまいます。 +所有権システムに関係します。`deref`メソッドが値への参照ではなく値を直接返したら、値は`self`から外にムーブされてしまいます。 今回もそうですが、参照外し演算子を使用するときはほとんどの場合、`MyBox`の中の値の所有権を奪いたくはありません。 -`*`演算子が`deref`メソッドの呼び出しと`*`演算子の呼び出しに置き換えられるのは、コード内で`*`を打つ毎にただ1回だけ、という点に注意して下さい。 +`*`演算子が`deref`メソッドの呼び出しと`*`演算子の呼び出しに置き換えられるのは、コード内で`*`を使用する毎にただ1回だけ、という点に注意して下さい。 `*`演算子の置き換えは無限に繰り返されないので、型`i32`のデータに行き着きます。これはリスト15-9で`assert_eq!`の`5`と合致します。 -*参照外し型強制*は、コンパイラが関数やメソッドの実引数に行う便利なものです。参照外し型強制は、 -`Deref`を実装する型への参照を`Deref`が元の型を変換できる型への参照に変換します。参照外し型強制は、 +*参照外し型強制*は、`Deref`トレイトを実装する型への参照を、別の型への参照に変換します。 +例えば、`String`は`&str`を返すように`Deref`トレイトを実装しているので、参照外し型強制で`&String`を`&str`に変換することができます。 +参照外し型強制は、コンパイラが関数やメソッドの実引数に行う便利なもので、 +`Deref`トレイトを実装する型に対してのみ機能します。参照外し型強制は、 特定の型の値への参照を関数やメソッド定義の引数型と一致しない引数として関数やメソッドに渡すときに自動的に発生します。 一連の`deref`メソッドの呼び出しが、提供した型を引数が必要とする型に変換します。 @@ -455,9 +439,7 @@ parameter: ファイル名: src/main.rs ```rust -fn hello(name: &str) { - println!("Hello, {}!", name); -} +{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-11/src/main.rs:here}} ``` `(*m)`が`MyBox`を`String`に参照外ししています。そして、`&`と`[..]`により、 文字列全体と等しい`String`の文字列スライスを取り、`hello`のシグニチャと一致するわけです。 -参照外し型強制のないコードは、これらの記号が関係するので、読むのも書くのも理解するのもより難しくなります。 +参照外し型強制のないこのコードは、これらの記号が関係するので、読むのも書くのも理解するのもより難しくなります。 参照外し型強制により、コンパイラはこれらの変換を自動的に扱えるのです。 @@ -643,19 +575,15 @@ cases: * `T: Deref`の時、`&mut T`から`&U` -前者2つは、可変性を除いて一緒です。最初のケースは、`&T`があり、`T`が何らかの型`U`への`Deref`を実装しているなら、 +最初の2つは、2番目は可変性を実装している点を除いて、一緒です。最初のケースは、`&T`があり、`T`が何らかの型`U`への`Deref`を実装しているなら、 透過的に`&U`を得られると述べています。2番目のケースは、同じ参照外し型強制が可変参照についても起こることを述べています。 - - 3番目のケースはもっと巧妙です: Rustはさらに、可変参照を不変参照にも型強制するのです。ですが、逆はできま*せん*: 不変参照は、絶対に可変参照に型強制されないのです。借用規則により、可変参照があるなら、 その可変参照がそのデータへの唯一の参照に違いありません(でなければ、プログラムはコンパイルできません)。 1つの可変参照を1つの不変参照に変換することは、借用規則を絶対に破壊しません。 -不変参照を可変参照にするには、そのデータへの不変参照がたった1つしかないことが必要ですが、 +不変参照を可変参照にするには、変換元の不変参照がそのデータへの唯一の不変参照であることが必要ですが、 借用規則はそれを保証してくれません。故に、不変参照を可変参照に変換することが可能であるという前提を敷けません。 + + + +[impl-trait]: ch10-02-traits.html#トレイトを型に実装する +[tuple-structs]: ch05-01-defining-structs.html#異なる型を生成する名前付きフィールドのないタプル構造体を使用する diff --git a/src/ch15-03-drop.md b/src/ch15-03-drop.md index 9c0e87285..84eecfdd8 100644 --- a/src/ch15-03-drop.md +++ b/src/ch15-03-drop.md @@ -7,57 +7,64 @@ スマートポインタパターンにとって重要な2番目のトレイトは、`Drop`であり、 これのおかげで値がスコープを抜けそうになった時に起こることをカスタマイズできます。 -どんな型に対しても`Drop`トレイトの実装を提供することができ、指定したコードは、 -ファイルやネットワーク接続などのリソースを解放するのに活用できます。 +どんな型に対しても`Drop`トレイトの実装を提供することができ、 +そのコードはファイルやネットワーク接続などのリソースを解放するために使用できます。 + + + `Drop`をスマートポインタの文脈で導入しています。`Drop`トレイトの機能は、ほぼ常にスマートポインタを実装する時に使われるからです。 -例えば、`Box`は`Drop`をカスタマイズしてボックスが指しているヒープの領域を解放しています。 +例えば`Box`はドロップされるときに、そのボックスが指しているヒープの領域を解放するでしょう。 -ある言語では、プログラマがスマートポインタのインスタンスを使い終わる度にメモリやリソースを解放するコードを呼ばなければなりません。 +言語によっては、さらに型によっては、プログラマがその型のインスタンスを使い終わる度に、 +メモリやリソースを解放するコードを呼ばなければならないことがあります。 +そうした型の例にはファイルハンドル、ソケット、またはロックなどが含まれます。 忘れてしまったら、システムは詰め込みすぎになりクラッシュする可能性があります。Rustでは、 値がスコープを抜ける度に特定のコードが走るよう指定でき、コンパイラはこのコードを自動的に挿入します。 結果として、特定の型のインスタンスを使い終わったプログラムの箇所全部にクリーンアップコードを配置するのに配慮する必要はありません。 それでもリソースをリークすることはありません。 -`Drop`トレイトを実装することで値がスコープを抜けた時に走るコードを指定してください。 +`Drop`トレイトを実装することで、値がスコープを抜けた時に走るコードを指定します。 `Drop`トレイトは、`self`への可変参照を取る`drop`という1つのメソッドを実装する必要があります。 いつRustが`drop`を呼ぶのか確認するために、今は`println!`文のある`drop`を実装しましょう。 -リスト15-14は、唯一の独自の機能が、インスタンスがスコープを抜ける時に`Dropping CustomSmartPointer!`と出力するだけの、 -`CustomSmartPointer`構造体です。この例は、コンパイラがいつ`drop`関数を走らせるかをデモしています。 +リスト15-14では、コンパイラがいつ`drop`関数を走らせるかを示すために、 +インスタンスがスコープを抜ける時に`Dropping CustomSmartPointer!`と出力するだけの独自の機能を持つ、 +`CustomSmartPointer`構造体を示します。 -`Drop`トレイトは、初期化処理に含まれるので、インポートする必要はありません。 +`Drop`トレイトは、初期化処理に含まれるので、スコープ内に持ち込む必要はありません。 `CustomSmartPointer`に`Drop`トレイトを実装し、`println!`を呼び出す`drop`メソッドの実装を提供しています。 `drop`関数の本体は、自分の型のインスタンスがスコープを抜ける時に走らせたいあらゆるロジックを配置する場所です。 -ここで何らかのテキストを出力し、コンパイラがいつ`drop`を呼ぶのかデモしています。 +コンパイラがいつ`drop`を呼ぶのかを視覚的に示すために、ここでテキストを出力しています。 インスタンスがスコープを抜けた時に指定したコードを呼び出しながらコンパイラは、`drop`を自動的に呼び出してくれました。 変数は、生成されたのと逆の順序でドロップされるので、`d`は`c`より先にドロップされました。 -この例は、`drop`メソッドの動き方を見た目で案内するだけですが、通常は、メッセージ出力ではなく、 +この例の目的は`drop`メソッドがどう機能するのかを視覚的に案内することですが、通常は、メッセージ出力ではなく、 自分の型が走らせる必要のあるクリーンアップコードを指定するでしょう。 @@ -163,13 +154,13 @@ if you want to force a value to be dropped before the end of its scope. 残念ながら、自動的な`drop`機能を無効化することは、単純ではありません。通常、`drop`を無効化する必要はありません; `Drop`トレイトの最重要な要点は、自動的に考慮されることです。ですが、時として、値を早期に片付けたくなる可能性があります。 一例は、ロックを管理するスマートポインタを使用する時です: 同じスコープの他のコードがロックを獲得できるように、 -ロックを解放する`drop`メソッドを強制的に走らせたくなる可能性があります。Rustは、 +ロックを解放する`drop`メソッドを強制したくなる可能性があります。Rustは、 `Drop`トレイトの`drop`メソッドを手動で呼ばせてくれません; スコープが終わる前に値を強制的にドロップさせたいなら、 代わりに標準ライブラリが提供する`std::mem::drop`関数を呼ばなければなりません。 @@ -182,14 +173,8 @@ compiler error: ファイル名: src/main.rs -```rust,ignore -fn main() { - let c = CustomSmartPointer { data: String::from("some data") }; - println!("CustomSmartPointer created."); - c.drop(); - // mainの終端の前にCustomSmartPointerがドロップされた - println!("CustomSmartPointer dropped before the end of main."); -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-15/src/main.rs:here}} ``` src/main.rs:14:7 - | -14 | c.drop(); - | ^^^^ explicit destructor calls not allowed +```console +{{#include ../listings/ch15-smart-pointers/listing-15-15/output.txt}} ``` コンパイラはそれでも、`main`の終端で値に対して自動的に`drop`を呼び出すので、`drop`を明示的に呼ばせてくれません。 -コンパイラが2回同じ値を片付けようとするので、これは*二重解放*エラーになるでしょう。 +コンパイラが2回同じ値を片付けようとするので、これは*二重解放*エラーを発生させるでしょう。 値がスコープを抜けるときに`drop`が自動的に挿入されるのを無効化できず、`drop`メソッドを明示的に呼ぶこともできません。 -よって、値を早期に片付けさせる必要があるなら、`std::mem::drop`関数を使用できます。 +よって、値を早期に片付けさせる必要があるなら、`std::mem::drop`関数を使用します。 `std::mem::drop`関数は、`Drop`トレイトの`drop`メソッドとは異なります。 -早期に強制的にドロップさせたい値を引数で渡すことで呼びます。この関数は初期化処理に含まれているので、 +強制ドロップさせたい値を引数として渡して呼び出します。この関数はpreludeに含まれているので、 リスト15-15の`main`を変更して`drop`関数を呼び出せます。リスト15-16のようにですね: `Drop`トレイト実装で指定されたコードをいろんな方法で使用し、片付けを便利で安全にすることができます: diff --git a/src/ch15-04-rc.md b/src/ch15-04-rc.md index cc397cc6f..7b1a7e164 100644 --- a/src/ch15-04-rc.md +++ b/src/ch15-04-rc.md @@ -10,25 +10,26 @@ owns a given value. However, there are cases when a single value might have multiple owners. For example, in graph data structures, multiple edges might point to the same node, and that node is conceptually owned by all of the edges that point to it. A node shouldn’t be cleaned up unless it doesn’t have any -edges pointing to it. +edges pointing to it and so has no owners. --> 大多数の場合、所有権は明らかです: 一体どの変数が与えられた値を所有しているかわかるのです。 ところが、単独の値が複数の所有者を持つ可能性のある場合もあります。例えば、グラフデータ構造では、 複数の辺が同じノードを指す可能性があり、概念的にそのノードはそれを指す全ての辺に所有されるわけです。 -指す辺がなくならない限り、ノードは片付けられるべきではありません。 +指す辺がなくならない限り、つまり所有者がなくならない限り、ノードは片付けられるべきではありません。 -複数の所有権を可能にするため、Rustには`Rc`という型があり、これは、*reference counting*(参照カウント)の省略形です。 -`Rc`型は、値がまだ使用中かどうか決定する値への参照の数を追跡します。値への参照が0なら、どの参照も無効にすることなく、 -値は片付けられます。 +`Rc`というRustの型を使用することで、明示的に複数の所有権を可能にしなくてはなりません。 +これは、*reference counting*(参照カウント)の省略形です。 +`Rc`型は、値がまだ使用中かどうか決定するために、値への参照の数を追跡します。 +値への参照が0なら、どの参照も無効にすることなく、値は片付けられます。 src/main.rs:13:30 - | -12 | let b = Cons(3, Box::new(a)); - | - value moved here -13 | let c = Cons(4, Box::new(a)); - | ^ value used here after move - | - = note: move occurs because `a` has type `List`, which does not implement - the `Copy` trait +```console +{{#include ../listings/ch15-smart-pointers/listing-15-17/output.txt}} ``` `Cons`の定義を代わりに参照を保持するように変更することもできますが、そうしたら、 ライフタイム引数を指定しなければなりません。ライフタイム引数を指定することで、 リストの各要素が最低でもリスト全体と同じ期間だけ生きることを指定することになります。 -例えば、借用チェッカーは`let a = Cons(10, &Nil);`をコンパイルさせてくれません。 -一時的な`Nil`値が、`a`が参照を得られるより前にドロップされてしまうからです。 +これはリスト15-17での要素とリストに対しては当てはまりますが、すべての用途で当てはまるものではありません。 プログラム内で参照カウントが変更される度に、参照カウントを出力します。参照カウントは、 -`Rc::strong_count`関数を呼び出すことで得られます。`Rc`型には`weak_count`もあるので、 +`Rc::strong_count`関数を呼び出すことで得ています。`Rc`型には`weak_count`もあるので、 この関数は`count`ではなく`strong_count`と命名されています; `weak_count`の使用目的は、 -「循環参照を回避する」節で確かめます。 +[「循環参照を回避する: `Rc`を`Weak`に変換する」][preventing-ref-cycles]節で確かめます。 この例でわからないことは、`b`そして`a`が、`main`の終端でスコープを抜ける時に、カウントが0になり、 -その時点で`Rc`が完全に片付けられることです。`Rc`を使用すると、単独の値に複数の所有者を持たせることができ、 +`Rc`が完全に片付けられることです。`Rc`を使用すると、単独の値に複数の所有者を持たせることができ、 所有者のいずれかが存在している限り、値が有効であり続けることをカウントは保証します。 + +[preventing-ref-cycles]: ch15-06-reference-cycles.html#循環参照を回避する-rctをweaktに変換する diff --git a/src/ch15-05-interior-mutability.md b/src/ch15-05-interior-mutability.md index 0665aef50..406880974 100644 --- a/src/ch15-05-interior-mutability.md +++ b/src/ch15-05-interior-mutability.md @@ -9,17 +9,25 @@ data even when there are immutable references to that data; normally, this action is disallowed by the borrowing rules. To mutate data, the pattern uses `unsafe` code inside a data structure to bend Rust’s usual rules that govern -mutation and borrowing. We haven’t yet covered unsafe code; we will in -Chapter 19. We can use types that use the interior mutability pattern when we -can ensure that the borrowing rules will be followed at runtime, even though -the compiler can’t guarantee that. The `unsafe` code involved is then wrapped -in a safe API, and the outer type is still immutable. +mutation and borrowing. Unsafe code indicates to the compiler that we’re +checking the rules manually instead of relying on the compiler to check them +for us; we will discuss unsafe code more in Chapter 19. --> 内部可変性は、そのデータへの不変参照がある時でさえもデータを可変化できるRustでのデザインパターンです: 普通、この行動は借用規則により許可されません。データを可変化するために、このパターンは、データ構造内で`unsafe`コードを使用して、 -可変性と借用を支配するRustの通常の規則を捻じ曲げています。まだ、unsafeコードについては講義していません; -第19章で行います。たとえ、コンパイラが保証できなくても、借用規則に実行時に従うことが保証できる時、 +可変性と借用を支配するRustの通常の規則を捻じ曲げています。 +unsafeコードは、コンパイラが規則をチェックしてくれることに頼らず、自分でチェックしていることをコンパイラに表明します; +unsafeコードについては第19章で詳しく議論します。 + + + +たとえ、コンパイラが保証できなくても、借用規則に実行時に従うことが保証できる時に限り、 内部可変性パターンを使用した型を使用できます。関係する`unsafe`コードはそうしたら、安全なAPIにラップされ、 外側の型は、それでも不変です。 @@ -46,12 +54,12 @@ Recall the borrowing rules you learned in Chapter 4: どうして`RefCell`が`Box`のような型と異なるのでしょうか?第4章で学んだ借用規則を思い出してください: -* いかなる時も(以下の両方ではなく、)1つの可変参照かいくつもの不変参照の*どちらか*が可能になる +* いかなる時点においても、1個の可変参照または任意個の不変参照の*どちらか*(両方ではない)が存在できる。 * 参照は常に有効でなければならない。 -借用規則を実行時に代わりに精査する利点は、コンパイル時の精査では許容されない特定のメモリ安全な筋書きが許容されることです。 +借用規則を実行時に代わりに精査する利点は、コンパイル時の精査では許容されなかった特定のメモリ安全な筋書きが許容されることです。 Rustコンパイラのような静的解析は、本質的に保守的です。コードの特性には、コードを解析するだけでは検知できないものもあります: 最も有名な例は停止性問題であり、この本の範疇を超えていますが、調べると面白い話題です。 @@ -131,13 +139,13 @@ Here is a recap of the reasons to choose `Box`, `Rc`, or `RefCell`: * `Rc`は、同じデータに複数の所有者を持たせてくれる; `Box`と`RefCell`は単独の所有者。 @@ -169,35 +177,25 @@ you can’t borrow it mutably. For example, this code won’t compile: 借用規則の結果は、不変値がある時、可変で借用することはできないということです。 例えば、このコードはコンパイルできません: -```rust,ignore -fn main() { - let x = 5; - let y = &mut x; -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/src/main.rs}} ``` このコードをコンパイルしようとしたら、以下のようなエラーが出るでしょう: -```text -error[E0596]: cannot borrow immutable local variable `x` as mutable -(エラー: 不変なローカル変数`x`を可変で借用することはできません) - --> src/main.rs:3:18 - | -2 | let x = 5; - | - consider changing this to `mut x` -3 | let y = &mut x; - | ^ cannot borrow mutably +```console +{{#include ../listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt}} ``` -*テストダブル*は、テスト中に別の型の代わりに使用される型の一般的なプログラミングの概念です。 +プログラマはテスト中に、特定の振る舞いを観測して、それが適切に実装されていることを確認するために、 +ある型の代わりに他の型を使用することがあるでしょう。このプレースホルダ型は*テストダブル*と呼ばれます。 +映画撮影において特定のトリッキーなシーンを演じるために、役者の代わりとして参加する人を指す、 +「スタントダブル」と同じような意味で考えてください。テストダブルはテストの実行時に、他の型の代役を務めます。 *モックオブジェクト*は、テスト中に起きることを記録するテストダブルの特定の型なので、 正しい動作が起きたことをアサートできます。 -> `編注`: テストダブルとは、ソフトウェアテストにおいて、テスト対象が依存しているコンポーネントを置き換える代用品のこと。 - このコードの重要な部分の1つは、`Messenger`トレイトには、`self`への不変参照とメッセージのテキストを取る`send`というメソッドが1つあることです。 -これが、モックオブジェクトが持つ必要のあるインターフェイスなのです。もう1つの重要な部分は、 -`LimitTracker`の`set_value`メソッドの振る舞いをテストしたいということです。`value`引数に渡すものを変えることができますが、 +このトレイトが、モックが実際のオブジェクトと同じように使用できるために、モックオブジェクトが実装する必要のあるインターフェイスなのです。 +もう1つの重要な部分は、`LimitTracker`の`set_value`メソッドの振る舞いをテストしたいということです。`value`引数に渡すものを変えることができますが、 `set_value`はアサートを行えるものは何も返してくれません。`LimitTracker`を`Messenger`トレイトを実装する何かと、 `max`の特定の値で生成したら、`value`に異なる数値を渡した時にメッセンジャーは適切なメッセージを送ると指示されると言えるようになりたいです。 @@ -364,37 +331,8 @@ implement a mock object to do just that, but the borrow checker won’t allow it ファイル名: src/lib.rs -```rust -#[cfg(test)] -mod tests { - use super::*; - - struct MockMessenger { - sent_messages: Vec, - } - - impl MockMessenger { - fn new() -> MockMessenger { - MockMessenger { sent_messages: vec![] } - } - } - - impl Messenger for MockMessenger { - fn send(&self, message: &str) { - self.sent_messages.push(String::from(message)); - } - } - - #[test] - fn it_sends_an_over_75_percent_warning_message() { - let mock_messenger = MockMessenger::new(); - let mut limit_tracker = LimitTracker::new(&mock_messenger, 100); - - limit_tracker.set_value(80); - - assert_eq!(mock_messenger.sent_messages.len(), 1); - } -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-21/src/lib.rs:here}} ``` src/lib.rs:52:13 - | -51 | fn send(&self, message: &str) { - | ----- use `&mut self` here to make mutable -52 | self.sent_messages.push(String::from(message)); - | ^^^^^^^^^^^^^^^^^^ cannot mutably borrow immutable field +```console +{{#include ../listings/ch15-smart-pointers/listing-15-21/output.txt}} ``` これは、内部可変性が役に立つ場面なのです!`sent_messages`を`RefCell`内部に格納し、 -そうしたら`send`メッセージは、`sent_messages`を変更して見かけたメッセージを格納できるようになるでしょう。 +そうしたら`send`メソッドは、`sent_messages`を変更して見かけたメッセージを格納できるようになるでしょう。 リスト15-22は、それがどんな感じかを示しています: `send`メソッドの実装については、最初の引数はそれでも`self`への不変借用で、トレイト定義と合致しています。 @@ -563,7 +464,7 @@ Now that you’ve seen how to use `RefCell`, let’s dig into how it works! `RefCell`の使用法を見かけたので、動作の仕方を深掘りしましょう! #### `RefCell`で実行時に借用を追いかける @@ -615,16 +516,8 @@ at runtime. ファイル名: src/lib.rs -```rust,ignore -impl Messenger for MockMessenger { - fn send(&self, message: &str) { - let mut one_borrow = self.sent_messages.borrow_mut(); - let mut two_borrow = self.sent_messages.borrow_mut(); - - one_borrow.push(String::from(message)); - two_borrow.push(String::from(message)); - } -} +```rust,ignore,panics +{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-23/src/lib.rs:here}} ``` -コンパイル時ではなく実行時に借用エラーをキャッチするということは、開発過程の遅い段階でコードのミスを発見し、 -コードをプロダクションにデプロイする時まで発見しない可能性もあることを意味します。また、 +ここで行ったように、コンパイル時ではなく実行時に借用エラーをキャッチすることを選択するということは、 +開発過程のより遅い段階でコードのミスを発見することになる可能性があることを意味します: +コードをプロダクションにデプロイする時までに発見できないかもしれません。また、 コンパイル時ではなく、実行時に借用を追いかける結果として、少し実行時にパフォーマンスを犠牲にするでしょう。 しかしながら、`RefCell`を使うことで、不変値のみが許可される文脈で使用しつつ、 自身を変更して見かけたメッセージを追跡するモックオブジェクトを書くことが可能になります。 @@ -723,30 +613,7 @@ the lists: ファイル名: src/main.rs ```rust -#[derive(Debug)] -enum List { - Cons(Rc>, Rc), - Nil, -} - -use List::{Cons, Nil}; -use std::rc::Rc; -use std::cell::RefCell; - -fn main() { - let value = Rc::new(RefCell::new(5)); - - let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil))); - - let b = Cons(Rc::new(RefCell::new(6)), Rc::clone(&a)); - let c = Cons(Rc::new(RefCell::new(10)), Rc::clone(&a)); - - *value.borrow_mut() += 10; - - println!("a after = {:?}", a); - println!("b after = {:?}", b); - println!("c after = {:?}", c); -} +{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-24/src/main.rs}} ``` -`a`、`b`、`c`のリストを作成した後、`value`の値に10を足しています。これを`value`の`borrow_mut`を呼び出すことで行い、 -これは、第5章で議論した自動参照外し機能(「`->`演算子はどこに行ったの?」節をご覧ください)を使用して、 +`a`、`b`、`c`のリストを作成した後、`value`の値に10を足したいとします。これを`value`の`borrow_mut`を呼び出すことで行い、 +これは、第5章で議論した自動参照外し機能([「`->`演算子はどこに行ったの?」][wheres-the---operator]節をご覧ください)を使用して、 `Rc`を内部の`RefCell`値に参照外ししています。`borrow_mut`メソッドは、 `RefMut`スマートポインタを返し、それに対して参照外し演算子を使用し、中の値を変更します。 @@ -799,10 +667,8 @@ value of 15 rather than 5: `a`、`b`、`c`を出力すると、全て5ではなく、変更された15という値になっていることがわかります。 -```text -a after = Cons(RefCell { value: 15 }, Nil) -b after = Cons(RefCell { value: 6 }, Cons(RefCell { value: 15 }, Nil)) -c after = Cons(RefCell { value: 10 }, Cons(RefCell { value: 15 }, Nil)) +```console +{{#include ../listings/ch15-smart-pointers/listing-15-24/output.txt}} ``` このテクニックは非常に綺麗です!`RefCell`を使用することで表面上は不変な`List`値を持てます。 しかし、内部可変性へのアクセスを提供する`RefCell`のメソッドを使用できるので、必要な時にはデータを変更できます。 借用規則を実行時に精査することでデータ競合を防ぎ、時としてデータ構造でちょっとのスピードを犠牲にこの柔軟性を得るのは価値があります。 +`RefCell`は、マルチスレッドで実行されるコードに対しては機能しないことに注意してください! +`RefCell`のスレッドセーフなバージョンは`Mutex`で、`Mutex`については第16章で議論しましょう。 -標準ライブラリには、`Cell`などの内部可変性を提供する他の型もあり、この型は、内部値への参照を与える代わりに、 -値は`Cell`の内部や外部へコピーされる点を除き似ています。また`Mutex`もあり、 -これはスレッド間で使用するのが安全な内部可変性を提供します; 第16章でその使いみちについて議論しましょう。 -これらの型の違いをより詳しく知るには、標準ライブラリのドキュメンテーションをチェックしてください。 +[wheres-the---operator]: ch05-03-method-syntax.html#-演算子はどこに行ったの diff --git a/src/ch15-06-reference-cycles.md b/src/ch15-06-reference-cycles.md index aba2c417d..65f1be12e 100644 --- a/src/ch15-06-reference-cycles.md +++ b/src/ch15-06-reference-cycles.md @@ -7,17 +7,17 @@ Rustのメモリ安全保証により誤って絶対に片付けられることのないメモリ(*メモリリーク*として知られています)を生成してしまいにくくなりますが、 -不可能にはなりません。コンパイル時にデータ競合を防ぐのと同じようにメモリリークを完全に回避することは、 -Rustの保証の一つではなく、メモリリークはRustにおいてはメモリ安全であることを意味します。 +不可能にはなりません。メモリリークを完全に回避することは、Rustの保証の一つではなく、 +メモリリークはRustにおいてはメモリ安全であることを意味します。 Rustでは、`Rc`と`RefCell`を使用してメモリリークを許可するとわかります: 要素がお互いに循環して参照する参照を生成することも可能ということです。循環の各要素の参照カウントが絶対に0にならないので、 これはメモリリークを起こし、値は絶対にドロップされません。 @@ -42,29 +42,8 @@ starting with the definition of the `List` enum and a `tail` method in Listing ファイル名: src/main.rs - - ```rust -# fn main() {} -use std::rc::Rc; -use std::cell::RefCell; -use List::{Cons, Nil}; - -#[derive(Debug)] -enum List { - Cons(i32, RefCell>), - Nil, -} - -impl List { - fn tail(&self) -> Option<&RefCell>> { - match *self { - Cons(_, ref item) => Some(item), - Nil => None, - } - } -} +{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-25/src/main.rs}} ``` リスト15-5の`List`定義の別バリエーションを使用しています。`Cons`列挙子の2番目の要素はこれで`RefCell>`になり、 -リスト15-24のように`i32`値を変更する能力があるのではなく、`Cons`列挙子が指している`List`値の先を変えたいということです。 +リスト15-24のように`i32`値を変更する能力があるのではなく、`Cons`列挙子が指している先の`List`値を変えたいということです。 また、`tail`メソッドを追加して`Cons`列挙子があるときに2番目の要素にアクセスするのが便利になるようにしています。 最初のリストが`5, Nil`の`List`値を保持する`Rc`インスタンスを変数`a`に生成します。 そして、値10と`a`のリストを指す別の`List`値を保持する`Rc`インスタンスを変数`b`に生成します。 `a`が`Nil`ではなく`b`を指すように変更して、循環させます。`tail`メソッドを使用して、 @@ -198,37 +129,30 @@ moment, we’ll get this output: 最後の`println!`を今だけコメントアウトしたまま、このコードを実行すると、こんな出力が得られます: -```text -a initial rc count = 1 -a next item = Some(RefCell { value: Nil }) -a rc count after b creation = 2 -b initial rc count = 1 -b next item = Some(RefCell { value: Cons(5, RefCell { value: Nil }) }) -b rc count after changing a = 2 -a rc count after changing a = 2 +```console +{{#include ../listings/ch15-smart-pointers/listing-15-26/output.txt}} ``` `a`のリストを`b`を指すように変更した後の`a`と`b`の`Rc`インスタンスの参照カウントは2です。 -`main`の終端で、コンパイラはまず`b`をドロップしようとし、`a`と`b`の各`Rc`インスタンスのカウントを1減らします。 - - - -しかしながら、それでも`a`は`b`にあった`Rc`を参照しているので、その`Rc`のカウントは0ではなく1になり、 -その`Rc`がヒープに確保していたメモリはドロップされません。メモリはただ、カウント1のままそこに永遠に居座るのです。 -この循環参照を可視化するために、図15-4に図式を作成しました: +`main`の終端で、コンパイラは変数`b`をドロップし、`b` `Rc`インスタンスの参照カウントを2から1に減らします。 +`Rc`の参照カウントが0ではなく1なので、`Rc`がヒープに確保していたメモリは、この時点ではドロップされません。 +次に、コンパイラは`a`をドロップし、`a` `Rc` インスタンスの参照カウントも同様に2から1に減らします。 +他の`Rc`インスタンスがまだ参照しているので、このインスタンスのメモリもドロップされません。 +リストに割り当てられたメモリは、永遠に回収されないままになるでしょう。 +この循環参照を可視化するために、図15-4に図式を作成しました。 -この場合、循環参照を作る直後にプログラムは終了します。この循環の結果は、それほど悲壮なものではありません。しかしながら、 +現実世界のプログラムと比較すれば、この例で循環参照を作成してしまうという結果は、それほど悲壮なものではありません: +循環参照を作った直後にプログラムが終了するからです。しかしながら、 より複雑なプログラムが多くのメモリを循環で確保し長い間その状態を保ったら、プログラムは必要以上のメモリを使用し、 使用可能なメモリを枯渇させてシステムを参らせてしまう可能性があります。 @@ -307,32 +233,34 @@ So far, we’ve demonstrated that calling `Rc::clone` increases the `strong_count` of an `Rc` instance, and an `Rc` instance is only cleaned up if its `strong_count` is 0. You can also create a *weak reference* to the value within an `Rc` instance by calling `Rc::downgrade` and passing a -reference to the `Rc`. When you call `Rc::downgrade`, you get a smart -pointer of type `Weak`. Instead of increasing the `strong_count` in the -`Rc` instance by 1, calling `Rc::downgrade` increases the `weak_count` by 1. -The `Rc` type uses `weak_count` to keep track of how many `Weak` -references exist, similar to `strong_count`. The difference is the `weak_count` -doesn’t need to be 0 for the `Rc` instance to be cleaned up. +reference to the `Rc`. Strong references are how you can share ownership of +an `Rc` instance. Weak references don’t express an ownership relationship, +and their count doesn’t affect when an `Rc` instance is cleaned up. They +won’t cause a reference cycle because any cycle involving some weak references +will be broken once the strong reference count of values involved is 0. --> ここまで、`Rc::clone`を呼び出すと`Rc`インスタンスの`strong_count`が増えることと、 `strong_count`が0になった時に`Rc`インスタンスは片付けられることをデモしてきました。 `Rc::downgrade`を呼び出し、`Rc`への参照を渡すことで、`Rc`インスタンス内部の値への*弱い参照*(weak reference)を作ることもできます。 -`Rc::downgrade`を呼び出すと、型`Weak`のスマートポインタが得られます。 -`Rc`インスタンスの`strong_count`を1増やす代わりに、`Rc::downgrade`を呼び出すと、`weak_count`が1増えます。 -`strong_count`同様、`Rc`型は`weak_count`を使用して、幾つの`Weak`参照が存在しているかを追跡します。 -違いは、`Rc`が片付けられるのに、`weak_count`が0である必要はないということです。 +強い参照は、`Rc`インスタンスの所有権を共有する方法です。弱い参照は所有関係を表現せず、 +そのカウントは`Rc`インスタンスが片付けられるときに影響を与えません。 +ひとたび、関係する値の強い参照カウントが0になれば、弱い参照が関わる循環はなんでも破壊されるので、 +循環参照にはなりません。 -強い参照は、`Rc`インスタンスの所有権を共有する方法です。弱い参照は、所有権関係を表現しません。 -ひとたび、関係する値の強い参照カウントが0になれば、弱い参照が関わる循環はなんでも破壊されるので、 -循環参照にはなりません。 +`Rc::downgrade`を呼び出すと、型`Weak`のスマートポインタが得られます。 +`Rc`インスタンスの`strong_count`を1増やす代わりに、`Rc::downgrade`を呼び出すと、`weak_count`が1増えます。 +`strong_count`同様、`Rc`型は`weak_count`を使用して、幾つの`Weak`参照が存在しているかを追跡します。 +違いは、`Rc`が片付けられるのに、`weak_count`が0である必要はないということです。 `Weak`が参照する値はドロップされてしまっている可能性があるので、`Weak`が指す値に何かをするには、 値がまだ存在することを確認しなければなりません。`Weak`の`upgrade`メソッドを呼び出すことでこれをしてください。 このメソッドは`Option>`を返します。`Rc`値がまだドロップされていなければ、`Some`の結果が、 -`Rc`値がドロップ済みなら、`None`の結果が得られます。`upgrade`が`Option`を返すので、 +`Rc`値がドロップ済みなら、`None`の結果が得られます。`upgrade`が`Option>`を返すので、 コンパイラは、`Some`ケースと`None`ケースが扱われていることを確かめてくれ、無効なポインタは存在しません。 -`leaf`ノードを作成することは、`parent`フィールドの例外を除いてリスト15-27での`leaf`ノードの作成法の見た目に似ています: +`leaf`ノードを作成することは、`parent`フィールドの例外を除いてリスト15-27に似ています: `leaf`は親なしで始まるので、新しく空の`Weak`参照インスタンスを作ります。 次は、Rustでの並行性について語ります。もういくつか新しいスマートポインタについてさえも学ぶでしょう。 + + + +[nomicon]: https://doc.rust-lang.org/nomicon/index.html diff --git a/src/img/trpl15-04.svg b/src/img/trpl15-04.svg index 96ad98ca1..7285ae673 100644 --- a/src/img/trpl15-04.svg +++ b/src/img/trpl15-04.svg @@ -1,55 +1,84 @@ - - - - - -%3 - - -table0 - -a - - -table1 - -5 - - - - -table2 - -b - - -table3 - -10 - - - - -table0:ref->table1:data - - - - -table1:ref->table2:data - - - - -table2:ref->table3:data - - - - -table3:ref->table0:data - - + + + + + + +l1 + +5 + + + + + +l2 + +10 + + + + + +l1:c->l2:data + + + + + +invisible_end + + + + +l2:c->invisible_end:n + + + + +invisible_start + + + + +invisible_start:n->l1 + + + + + +invisible_start:s->invisible_end:s + + + + +a + +a + + + +a->l1:n + + + + + +b + +b + + + +b->l2:n + + From b7f9baf8961d4a265f0e1f0f4d98ab8adeaa9bc4 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:07 +0900 Subject: [PATCH 17/22] =?UTF-8?q?ch16=20=E6=81=90=E3=82=8C=E3=82=8B?= =?UTF-8?q?=E3=81=AA=EF=BC=81=E4=B8=A6=E8=A1=8C=E6=80=A7=E3=81=AE=E5=92=8C?= =?UTF-8?q?=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-16-01/Cargo.toml | 3 +- .../listing-16-01/src/main.rs | 2 + .../listing-16-02/Cargo.toml | 3 +- .../listing-16-03/Cargo.toml | 3 +- .../listing-16-03/output.txt | 13 +- .../listing-16-03/src/main.rs | 1 + .../listing-16-04/Cargo.toml | 3 +- .../listing-16-04/src/main.rs | 2 +- .../listing-16-05/Cargo.toml | 3 +- .../listing-16-06/Cargo.toml | 3 +- .../listing-16-07/Cargo.toml | 3 +- .../listing-16-08/Cargo.toml | 3 +- .../listing-16-08/src/main.rs | 1 + .../listing-16-09/Cargo.toml | 3 +- .../listing-16-09/output.txt | 19 +- .../listing-16-09/src/main.rs | 1 + .../listing-16-10/Cargo.toml | 3 +- .../listing-16-10/src/main.rs | 1 + .../listing-16-11/Cargo.toml | 3 +- .../listing-16-11/src/main.rs | 3 +- .../listing-16-12/Cargo.toml | 3 +- .../listing-16-13/Cargo.toml | 3 +- .../listing-16-13/output.txt | 23 +- .../listing-16-14/Cargo.toml | 3 +- .../listing-16-14/output.txt | 44 +- .../listing-16-15/Cargo.toml | 3 +- .../no-listing-01-join-too-early/Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../output-only-01-move-drop/Cargo.toml | 3 +- .../output-only-01-move-drop/output.txt | 15 +- src/ch16-00-concurrency.md | 14 +- src/ch16-01-threads.md | 369 +++++------------ src/ch16-02-message-passing.md | 314 +++++--------- src/ch16-03-shared-state.md | 387 +++++------------- ...04-extensible-concurrency-sync-and-send.md | 52 ++- 35 files changed, 440 insertions(+), 875 deletions(-) diff --git a/listings/ch16-fearless-concurrency/listing-16-01/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-01/Cargo.toml index 68a31e10b..bd4edf762 100644 --- a/listings/ch16-fearless-concurrency/listing-16-01/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "threads" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-01/src/main.rs b/listings/ch16-fearless-concurrency/listing-16-01/src/main.rs index 6305a98e3..fcb17ec31 100644 --- a/listings/ch16-fearless-concurrency/listing-16-01/src/main.rs +++ b/listings/ch16-fearless-concurrency/listing-16-01/src/main.rs @@ -4,12 +4,14 @@ use std::time::Duration; fn main() { thread::spawn(|| { for i in 1..10 { + // "やあ!立ち上げたスレッドから数字{}だよ!" println!("hi number {} from the spawned thread!", i); thread::sleep(Duration::from_millis(1)); } }); for i in 1..5 { + // "やあ!メインスレッドから数字{}だよ!" println!("hi number {} from the main thread!", i); thread::sleep(Duration::from_millis(1)); } diff --git a/listings/ch16-fearless-concurrency/listing-16-02/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-02/Cargo.toml index 68a31e10b..bd4edf762 100644 --- a/listings/ch16-fearless-concurrency/listing-16-02/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "threads" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-03/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-03/Cargo.toml index 68a31e10b..bd4edf762 100644 --- a/listings/ch16-fearless-concurrency/listing-16-03/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "threads" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-03/output.txt b/listings/ch16-fearless-concurrency/listing-16-03/output.txt index 1dd4deeb2..f6e370af6 100644 --- a/listings/ch16-fearless-concurrency/listing-16-03/output.txt +++ b/listings/ch16-fearless-concurrency/listing-16-03/output.txt @@ -1,14 +1,18 @@ $ cargo run Compiling threads v0.1.0 (file:///projects/threads) error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function +(エラー: クロージャは現在の関数よりも長生きするかもしれませんが、現在の関数が所有している`v`を借用しています) --> src/main.rs:6:32 | 6 | let handle = thread::spawn(|| { | ^^ may outlive borrowed value `v` + | (借用されている値`v`より長生きするかもしれません) 7 | println!("Here's a vector: {:?}", v); | - `v` is borrowed here + | (`v`はここで借用されています) | note: function requires argument type to outlive `'static` +(注釈: 関数は引数型が`'static`より長生きすることを要求しています) --> src/main.rs:6:18 | 6 | let handle = thread::spawn(|| { @@ -17,13 +21,10 @@ note: function requires argument type to outlive `'static` 8 | | }); | |______^ help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword +(ヘルプ: `v`(や他の参照されている変数)の所有権をクロージャに奪わせるには、`move`キーワードを使用してください) | 6 | let handle = thread::spawn(move || { - | ^^^^^^^ - -error: aborting due to previous error + | ++++ For more information about this error, try `rustc --explain E0373`. -error: could not compile `threads`. - -To learn more, run the command again with --verbose. +error: could not compile `threads` (bin "threads") due to 1 previous error diff --git a/listings/ch16-fearless-concurrency/listing-16-03/src/main.rs b/listings/ch16-fearless-concurrency/listing-16-03/src/main.rs index defc87648..06d6f2e23 100644 --- a/listings/ch16-fearless-concurrency/listing-16-03/src/main.rs +++ b/listings/ch16-fearless-concurrency/listing-16-03/src/main.rs @@ -4,6 +4,7 @@ fn main() { let v = vec![1, 2, 3]; let handle = thread::spawn(|| { + // "こちらがベクタ: {:?}" println!("Here's a vector: {:?}", v); }); diff --git a/listings/ch16-fearless-concurrency/listing-16-04/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-04/Cargo.toml index 68a31e10b..bd4edf762 100644 --- a/listings/ch16-fearless-concurrency/listing-16-04/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "threads" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-04/src/main.rs b/listings/ch16-fearless-concurrency/listing-16-04/src/main.rs index 0bccc5f56..1cfa7007c 100644 --- a/listings/ch16-fearless-concurrency/listing-16-04/src/main.rs +++ b/listings/ch16-fearless-concurrency/listing-16-04/src/main.rs @@ -7,7 +7,7 @@ fn main() { println!("Here's a vector: {:?}", v); }); - drop(v); // oh no! + drop(v); // あちゃー! handle.join().unwrap(); } diff --git a/listings/ch16-fearless-concurrency/listing-16-05/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-05/Cargo.toml index 68a31e10b..bd4edf762 100644 --- a/listings/ch16-fearless-concurrency/listing-16-05/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "threads" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-06/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-06/Cargo.toml index 8fd8808ea..24bd2ee7b 100644 --- a/listings/ch16-fearless-concurrency/listing-16-06/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "message-passing" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-07/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-07/Cargo.toml index 8fd8808ea..24bd2ee7b 100644 --- a/listings/ch16-fearless-concurrency/listing-16-07/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "message-passing" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-08/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-08/Cargo.toml index 8fd8808ea..24bd2ee7b 100644 --- a/listings/ch16-fearless-concurrency/listing-16-08/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "message-passing" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-08/src/main.rs b/listings/ch16-fearless-concurrency/listing-16-08/src/main.rs index fbba9167d..53ebedc76 100644 --- a/listings/ch16-fearless-concurrency/listing-16-08/src/main.rs +++ b/listings/ch16-fearless-concurrency/listing-16-08/src/main.rs @@ -10,5 +10,6 @@ fn main() { }); let received = rx.recv().unwrap(); + // "取得しました: {}" println!("Got: {}", received); } diff --git a/listings/ch16-fearless-concurrency/listing-16-09/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-09/Cargo.toml index 8fd8808ea..24bd2ee7b 100644 --- a/listings/ch16-fearless-concurrency/listing-16-09/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "message-passing" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-09/output.txt b/listings/ch16-fearless-concurrency/listing-16-09/output.txt index 11bfc6fe3..39a40851b 100644 --- a/listings/ch16-fearless-concurrency/listing-16-09/output.txt +++ b/listings/ch16-fearless-concurrency/listing-16-09/output.txt @@ -1,18 +1,25 @@ $ cargo run Compiling message-passing v0.1.0 (file:///projects/message-passing) error[E0382]: borrow of moved value: `val` +(エラー: ムーブされた値の借用: `val`) --> src/main.rs:10:31 | 8 | let val = String::from("hi"); - | --- move occurs because `val` has type `std::string::String`, which does not implement the `Copy` trait + | --- move occurs because `val` has type `String`, which does not implement the `Copy` trait + | (`val`は`Copy`トレイトを実装しない`String`型を持つので、ムーブが発生します) 9 | tx.send(val).unwrap(); | --- value moved here + | (値はここでムーブされます) 10 | println!("val is {}", val); | ^^^ value borrowed here after move - -error: aborting due to previous error + | (ここでムーブ後に借用されます) + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable +(ヘルプ: パフォーマンスコストが許容できる場合は、クローンすることを検討してください) + | +9 | tx.send(val.clone()).unwrap(); + | ++++++++ For more information about this error, try `rustc --explain E0382`. -error: could not compile `message-passing`. - -To learn more, run the command again with --verbose. +error: could not compile `message-passing` (bin "message-passing") due to 1 previous error diff --git a/listings/ch16-fearless-concurrency/listing-16-09/src/main.rs b/listings/ch16-fearless-concurrency/listing-16-09/src/main.rs index 98a8129ab..fe0c0f479 100644 --- a/listings/ch16-fearless-concurrency/listing-16-09/src/main.rs +++ b/listings/ch16-fearless-concurrency/listing-16-09/src/main.rs @@ -7,6 +7,7 @@ fn main() { thread::spawn(move || { let val = String::from("hi"); tx.send(val).unwrap(); + // "valは{}です" println!("val is {}", val); }); diff --git a/listings/ch16-fearless-concurrency/listing-16-10/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-10/Cargo.toml index 8fd8808ea..24bd2ee7b 100644 --- a/listings/ch16-fearless-concurrency/listing-16-10/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "message-passing" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-10/src/main.rs b/listings/ch16-fearless-concurrency/listing-16-10/src/main.rs index 82b220de4..22cc1ef32 100644 --- a/listings/ch16-fearless-concurrency/listing-16-10/src/main.rs +++ b/listings/ch16-fearless-concurrency/listing-16-10/src/main.rs @@ -6,6 +6,7 @@ fn main() { let (tx, rx) = mpsc::channel(); thread::spawn(move || { + // スレッドからやあ (hi from the thread) let vals = vec![ String::from("hi"), String::from("from"), diff --git a/listings/ch16-fearless-concurrency/listing-16-11/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-11/Cargo.toml index 8fd8808ea..24bd2ee7b 100644 --- a/listings/ch16-fearless-concurrency/listing-16-11/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "message-passing" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-11/src/main.rs b/listings/ch16-fearless-concurrency/listing-16-11/src/main.rs index f0acf4c2d..964327790 100644 --- a/listings/ch16-fearless-concurrency/listing-16-11/src/main.rs +++ b/listings/ch16-fearless-concurrency/listing-16-11/src/main.rs @@ -8,7 +8,7 @@ fn main() { let (tx, rx) = mpsc::channel(); - let tx1 = mpsc::Sender::clone(&tx); + let tx1 = tx.clone(); thread::spawn(move || { let vals = vec![ String::from("hi"), @@ -24,6 +24,7 @@ fn main() { }); thread::spawn(move || { + // 君のためにもっとメッセージを (more messages for you) let vals = vec![ String::from("more"), String::from("messages"), diff --git a/listings/ch16-fearless-concurrency/listing-16-12/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-12/Cargo.toml index e7c75ac91..da297eaba 100644 --- a/listings/ch16-fearless-concurrency/listing-16-12/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "shared-state" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-13/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-13/Cargo.toml index e7c75ac91..da297eaba 100644 --- a/listings/ch16-fearless-concurrency/listing-16-13/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "shared-state" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-13/output.txt b/listings/ch16-fearless-concurrency/listing-16-13/output.txt index 7369ec41b..7341ef3b9 100644 --- a/listings/ch16-fearless-concurrency/listing-16-13/output.txt +++ b/listings/ch16-fearless-concurrency/listing-16-13/output.txt @@ -1,19 +1,20 @@ $ cargo run Compiling shared-state v0.1.0 (file:///projects/shared-state) -error[E0382]: use of moved value: `counter` - --> src/main.rs:9:36 +error[E0382]: borrow of moved value: `counter` +(エラー: ムーブされた値の借用: `counter`) + --> src/main.rs:21:29 | 5 | let counter = Mutex::new(0); - | ------- move occurs because `counter` has type `std::sync::Mutex`, which does not implement the `Copy` trait + | ------- move occurs because `counter` has type `Mutex`, which does not implement the `Copy` trait + | (`counter`は`Copy`トレイトを実装しない`Mutex`型を持つので、ムーブが発生します) ... 9 | let handle = thread::spawn(move || { - | ^^^^^^^ value moved into closure here, in previous iteration of loop -10 | let mut num = counter.lock().unwrap(); - | ------- use occurs due to use in closure - -error: aborting due to previous error + | ------- value moved into closure here, in previous iteration of loop + | (値は、ループの前回の反復時に、ここでクロージャ内にムーブされます) +... +21 | println!("Result: {}", *counter.lock().unwrap()); + | ^^^^^^^ value borrowed here after move + | (値はここでムーブ後に借用されています) For more information about this error, try `rustc --explain E0382`. -error: could not compile `shared-state`. - -To learn more, run the command again with --verbose. +error: could not compile `shared-state` (bin "shared-state") due to 1 previous error diff --git a/listings/ch16-fearless-concurrency/listing-16-14/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-14/Cargo.toml index e7c75ac91..da297eaba 100644 --- a/listings/ch16-fearless-concurrency/listing-16-14/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-14/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "shared-state" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/listing-16-14/output.txt b/listings/ch16-fearless-concurrency/listing-16-14/output.txt index 200c55e22..7b33b099d 100644 --- a/listings/ch16-fearless-concurrency/listing-16-14/output.txt +++ b/listings/ch16-fearless-concurrency/listing-16-14/output.txt @@ -1,17 +1,35 @@ $ cargo run Compiling shared-state v0.1.0 (file:///projects/shared-state) -error[E0277]: `std::rc::Rc>` cannot be sent between threads safely - --> src/main.rs:11:22 - | -11 | let handle = thread::spawn(move || { - | ^^^^^^^^^^^^^ `std::rc::Rc>` cannot be sent between threads safely - | - = help: within `[closure@src/main.rs:11:36: 15:10 counter:std::rc::Rc>]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@src/main.rs:11:36: 15:10 counter:std::rc::Rc>]` - -error: aborting due to previous error +error[E0277]: `Rc>` cannot be sent between threads safely +(エラー: `Rc>`はスレッド間で安全に送信できません) + --> src/main.rs:11:36 + | +11 | let handle = thread::spawn(move || { + | ------------- ^------ + | | | + | ______________________|_____________within this `{closure@src/main.rs:11:36: 11:43}` + | | | (この`{[closure@src/main.rs:11:36: 11:43}`の中で) + | | | + | | required by a bound introduced by this call + | | (この呼び出しによって導入される境界によって必要とされます) +12 | | let mut num = counter.lock().unwrap(); +13 | | +14 | | *num += 1; +15 | | }); + | |_________^ `Rc>` cannot be sent between threads safely + | (`Rc>`はスレッド間で安全に送信できません) + | + = help: within `{closure@src/main.rs:11:36: 11:43}`, the trait `Send` is not implemented for `Rc>` + =(ヘルプ: `{closure@src/main.rs:11:36: 11:43}`の中で、トレイト`Send`は`Rc>`に対して実装されていません +note: required because it's used within this closure +(注釈: このクロージャの中で使用されているので、要求されます) + --> src/main.rs:11:36 + | +11 | let handle = thread::spawn(move || { + | ^^^^^^^ +note: required by a bound in `spawn` +(注釈: `spawn`の境界によって要求されます) + --> /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/thread/mod.rs:678:1 For more information about this error, try `rustc --explain E0277`. -error: could not compile `shared-state`. - -To learn more, run the command again with --verbose. +error: could not compile `shared-state` (bin "shared-state") due to 1 previous error diff --git a/listings/ch16-fearless-concurrency/listing-16-15/Cargo.toml b/listings/ch16-fearless-concurrency/listing-16-15/Cargo.toml index e7c75ac91..da297eaba 100644 --- a/listings/ch16-fearless-concurrency/listing-16-15/Cargo.toml +++ b/listings/ch16-fearless-concurrency/listing-16-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "shared-state" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/no-listing-01-join-too-early/Cargo.toml b/listings/ch16-fearless-concurrency/no-listing-01-join-too-early/Cargo.toml index 68a31e10b..bd4edf762 100644 --- a/listings/ch16-fearless-concurrency/no-listing-01-join-too-early/Cargo.toml +++ b/listings/ch16-fearless-concurrency/no-listing-01-join-too-early/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "threads" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/no-listing-02-no-loop-to-understand-error/Cargo.toml b/listings/ch16-fearless-concurrency/no-listing-02-no-loop-to-understand-error/Cargo.toml index e7c75ac91..da297eaba 100644 --- a/listings/ch16-fearless-concurrency/no-listing-02-no-loop-to-understand-error/Cargo.toml +++ b/listings/ch16-fearless-concurrency/no-listing-02-no-loop-to-understand-error/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "shared-state" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/output-only-01-move-drop/Cargo.toml b/listings/ch16-fearless-concurrency/output-only-01-move-drop/Cargo.toml index 68a31e10b..bd4edf762 100644 --- a/listings/ch16-fearless-concurrency/output-only-01-move-drop/Cargo.toml +++ b/listings/ch16-fearless-concurrency/output-only-01-move-drop/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "threads" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt b/listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt index 2d1cb3c8b..21ebaf499 100644 --- a/listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt +++ b/listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt @@ -1,22 +1,23 @@ $ cargo run Compiling threads v0.1.0 (file:///projects/threads) error[E0382]: use of moved value: `v` +(エラー: ムーブされた値の使用: `v`) --> src/main.rs:10:10 | 4 | let v = vec![1, 2, 3]; - | - move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait -5 | + | - move occurs because `v` has type `Vec`, which does not implement the `Copy` trait + | (`v`は`Copy`トレイトを実装しない`Vec`型を持つので、ムーブが発生します) +5 | 6 | let handle = thread::spawn(move || { | ------- value moved into closure here + | (値はここでクロージャ内にムーブされます) 7 | println!("Here's a vector: {:?}", v); | - variable moved due to use in closure + | (変数はクロージャ内で使用されているためムーブされます) ... 10 | drop(v); // oh no! | ^ value used here after move - -error: aborting due to previous error + | (値はここでムーブ後に使用されています) For more information about this error, try `rustc --explain E0382`. -error: could not compile `threads`. - -To learn more, run the command again with --verbose. +error: could not compile `threads` (bin "threads") due to 1 previous error diff --git a/src/ch16-00-concurrency.md b/src/ch16-00-concurrency.md index 26ca5cacd..e421abd05 100644 --- a/src/ch16-00-concurrency.md +++ b/src/ch16-00-concurrency.md @@ -46,11 +46,11 @@ Rustのこの方向性を*恐れるな!並行性*とニックネーム付け 新しいバグを導入することなく簡単にリファクタリングできるコードを書くことができます。 > 注釈: 簡潔性のため、並行または並列と述べることで正確を期するのではなく、 @@ -88,9 +88,9 @@ Here are the topics we’ll cover in this chapter: * How to create threads to run multiple pieces of code at the same time * *Message-passing* concurrency, where channels send messages between threads * *Shared-state* concurrency, where multiple threads have access to some piece -of data + of data * The `Sync` and `Send` traits, which extend Rust’s concurrency guarantees to -user-defined types as well as types provided by the standard library + user-defined types as well as types provided by the standard library --> * スレッドを生成して、複数のコードを同時に走らせる方法 diff --git a/src/ch16-01-threads.md b/src/ch16-01-threads.md index 2f0705666..69c027d64 100644 --- a/src/ch16-01-threads.md +++ b/src/ch16-01-threads.md @@ -6,124 +6,65 @@ -多くの現代のOSでは、実行中のプログラムのコードは*プロセス*で走り、OSは同時に複数のプロセスを管理します。 -自分のプログラム内で、独立した部分を同時に実行できます。これらの独立した部分を走らせる機能を*スレッド*と呼びます。 +多くの現代のOSでは、実行中のプログラムのコードは*プロセス*で走り、OSは同時に複数のプロセスを管理するでしょう。 +プログラム内では、独立した部分を同時に実行することもできます。これらの独立した部分を走らせる機能を*スレッド*と呼びます。 +例えばwebサーバは、同時に複数のリクエストに応答できるように、複数のスレッドを使用することができます。 -プログラム内の計算を複数のスレッドに分けると、パフォーマンスが改善します。プログラムが同時に複数の作業をするからですが、 +同時に複数のタスクを実行するために、プログラム内の計算を複数のスレッドに分けることで、パフォーマンスを改善することができますが、 複雑度も増します。スレッドは同時に走らせることができるので、異なるスレッドのコードが走る順番に関して、 本来的に保証はありません。これは例えば以下のような問題を招きます: * スレッドがデータやリソースに矛盾した順番でアクセスする競合状態 -* 2つのスレッドがお互いにもう一方が持っているリソースを使用し終わるのを待ち、両者が継続するのを防ぐデッドロック +* 2つのスレッドがお互いを待ち、両者が継続するのを防ぐデッドロック * 特定の状況でのみ起き、確実な再現や修正が困難なバグ Rustは、スレッドを使用する際の悪影響を軽減しようとしていますが、それでも、マルチスレッドの文脈でのプログラミングでは、 -注意深い思考とシングルスレッドで走るプログラムとは異なるコード構造が必要です。 +注意深い思考と、シングルスレッドで走るプログラムでのそれとは異なるコード構造が必要です。 -プログラミング言語によってスレッドはいくつかの方法で実装されています。多くのOSで、新規スレッドを生成するAPIが提供されています。 -言語がOSのAPIを呼び出してスレッドを生成するこのモデルを時に*1:1*と呼び、1つのOSスレッドに対して1つの言語スレッドを意味します。 - - - -多くのプログラミング言語がスレッドの独自の特別な実装を提供しています。プログラミング言語が提供するスレッドは、 -*グリーン*スレッドとして知られ、このグリーンスレッドを使用する言語は、それを異なる数のOSスレッドの文脈で実行します。 -このため、グリーンスレッドのモデルは*M:N*モデルと呼ばれます: `M`個のグリーンスレッドに対して、 -`N`個のOSスレッドがあり、`M`と`N`は必ずしも同じ数字ではありません。 - - - -各モデルには、それだけの利点と代償があり、Rustにとって最も重要な代償は、ランタイムのサポートです。 -*ランタイム*は、混乱しやすい用語で文脈によって意味も変わります。 - - - -この文脈での*ランタイム*とは、言語によって全てのバイナリに含まれるコードのことを意味します。 -言語によってこのコードの大小は決まりますが、非アセンブリ言語は全てある量の実行時コードを含みます。 -そのため、口語的に誰かが「ノーランタイム」と言ったら、「小さいランタイム」のことを意味することがしばしばあります。 -ランタイムが小さいと機能も少ないですが、バイナリのサイズも小さくなるという利点があり、 -その言語を他の言語とより多くの文脈で組み合わせることが容易になります。多くの言語では、 -より多くの機能と引き換えにランタイムのサイズが膨れ上がるのは、受け入れられることですが、 -Rustにはほとんどゼロのランタイムが必要でパフォーマンスを維持するためにCコードを呼び出せることを妥協できないのです。 - - - -M:Nのグリーンスレッドモデルは、スレッドを管理するのにより大きな言語ランタイムが必要です。よって、 -Rustの標準ライブラリは、1:1スレッドの実装のみを提供しています。Rustはそのような低級言語なので、 -例えば、むしろどのスレッドがいつ走るかのより詳細な制御や、より低コストの文脈切り替えなどの一面をオーバーヘッドと引き換えるなら、 -M:Nスレッドの実装をしたクレートもあります。 - - - -今やRustにおけるスレッドを定義したので、標準ライブラリで提供されているスレッド関連のAPIの使用法を探究しましょう。 +プログラミング言語によってスレッドはいくつかの方法で実装されており、多くのOSは、言語が呼び出すことができる、 +新規スレッドを生成するためのAPIを提供しています。 +Rust標準ライブラリは*1:1*モデルのスレッド実装を使用しており、1つの言語スレッドに対して1つのOSスレッドを使用します。 +1:1モデルとは異なるトレードオフを選択して、他のモデルのスレッドを実装するクレートもあります。 -この関数では、新しいスレッドは、実行が終わったかどうかにかかわらず、メインスレッドが終了したら停止することに注意してください。 -このプログラムからの出力は毎回少々異なる可能性がありますが、だいたい以下のような感じでしょう: +Rustプログラムのメインスレッドが完了するときには、立ち上げられたすべてのスレッドは、その実行が完了したかどうかにかかわらず、 +停止されることに注意してください。このプログラムからの出力は毎回少々異なる可能性がありますが、だいたい以下のような感じでしょう: + + ```text hi number 1 from the main thread! @@ -230,26 +158,25 @@ for the operating system to switch between the threads. -リスト16-1のコードは、メインスレッドが終了するためにほとんどの場合、立ち上げたスレッドがすべて実行されないだけでなく、 -立ち上げたスレッドが実行されるかどうかも保証できません。原因は、スレッドの実行順に保証がないからです。 +リスト16-1のコードはほとんどの場合、メインスレッドが終了することで、立ち上げたスレッドが完了する前に停止されるだけでなく、 +スレッドの実行順に保証がないことから、立ち上げたスレッドがそもそも実行されるかどうかも保証できません。 `thread::spawn`の戻り値を変数に保存することで、立ち上げたスレッドが実行されなかったり、 -完全には実行されなかったりする問題を修正することができます。`thread::spawn`の戻り値の型は`JoinHandle`です。 +完了する前に終了してしまったりする問題を修正することができます。`thread::spawn`の戻り値の型は`JoinHandle`です。 `JoinHandle`は、その`join`メソッドを呼び出したときにスレッドの終了を待つ所有された値です。 リスト16-2は、リスト16-1で生成したスレッドの`JoinHandle`を使用し、`join`を呼び出して、 `main`が終了する前に、立ち上げたスレッドが確実に完了する方法を示しています: @@ -261,24 +188,7 @@ in Listing 16-1 and call `join` to make sure the spawned thread finishes before ファイル名: src/main.rs ```rust -use std::thread; -use std::time::Duration; - -fn main() { - let handle = thread::spawn(|| { - for i in 1..10 { - println!("hi number {} from the spawned thread!", i); - thread::sleep(Duration::from_millis(1)); - } - }); - - for i in 1..5 { - println!("hi number {} from the main thread!", i); - thread::sleep(Duration::from_millis(1)); - } - - handle.join().unwrap(); -} +{{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-02/src/main.rs}} ``` + ```text hi number 1 from the main thread! hi number 2 from the main thread! @@ -339,24 +253,7 @@ But let’s see what happens when we instead move `handle.join()` before the ファイル名: src/main.rs ```rust -use std::thread; -use std::time::Duration; - -fn main() { - let handle = thread::spawn(|| { - for i in 1..10 { - println!("hi number {} from the spawned thread!", i); - thread::sleep(Duration::from_millis(1)); - } - }); - - handle.join().unwrap(); - - for i in 1..5 { - println!("hi number {} from the main thread!", i); - thread::sleep(Duration::from_millis(1)); - } -} +{{#rustdoc_include ../listings/ch16-fearless-concurrency/no-listing-01-join-too-early/src/main.rs}} ``` + ```text hi number 1 from the spawned thread! hi number 2 from the spawned thread! @@ -397,23 +298,18 @@ threads run at the same time. ### スレッドで`move`クロージャを使用する -`move`クロージャは、`thread::spawn`とともによく使用されます。 -あるスレッドのデータを別のスレッドで使用できるようになるからです。 - - - -第13章で、クロージャの引数リストの前に`move`キーワードを使用して、 -クロージャに環境で使用している値の所有権を強制的に奪わせることができると述べました。 -このテクニックは、あるスレッドから別のスレッドに値の所有権を移すために新しいスレッドを生成する際に特に有用です。 +`thread::spawn`に渡されるクロージャでは、`move`キーワードを多用することになるでしょう。 +そうすることで、クロージャは環境から使用する値の所有権を奪い、あるスレッドから別のスレッドに値の所有権を移すからです。 +第13章の[「参照をキャプチャするか、所有権を移動するか」][capture]節では、クロージャの文脈で`move`について議論しました。 +それでは、`move`と`thread::spawn`の相互作用により集中していきましょう。 リスト16-1において、`thread::spawn`に渡したクロージャには引数がなかったことに注目してください: 立ち上げたスレッドのコードでメインスレッドからのデータは何も使用していないのです。 立ち上げたスレッドでメインスレッドのデータを使用するには、立ち上げるスレッドのクロージャは、 必要な値をキャプチャしなければなりません。リスト16-3は、メインスレッドでベクタを生成し、 -立ち上げたスレッドで使用する試みを示しています。しかしながら、すぐにわかるように、これはまだ動きません: +立ち上げたスレッドで使用する試みを示しています。しかしながら、すぐにわかるように、これはまだ動きません。 src/main.rs:6:32 - | -6 | let handle = thread::spawn(|| { - | ^^ may outlive borrowed value `v` -7 | println!("Here's a vector: {:?}", v); - | - `v` is borrowed here - | -help: to force the closure to take ownership of `v` (and any other referenced -variables), use the `move` keyword -(助言: `v`(や他の参照されている変数)の所有権をクロージャに奪わせるには、`move`キーワードを使用してください) - | -6 | let handle = thread::spawn(move || { - | ^^^^^^^ +```console +{{#include ../listings/ch16-fearless-concurrency/listing-16-03/output.txt}} ``` + ```text -help: to force the closure to take ownership of `v` (and any other referenced -variables), use the `move` keyword +help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword +(ヘルプ: `v`(や他の参照されている変数)の所有権をクロージャに奪わせるには、`move`キーワードを使用してください) | 6 | let handle = thread::spawn(move || { - | ^^^^^^^ + | ++++ ``` -`move`クロージャを使用していたら、メインスレッドが`drop`を呼び出すリスト16-4のコードはどうなるのでしょうか? -`move`で解決するのでしょうか?残念ながら、違います; リスト16-4が試みていることは別の理由によりできないので、 -違うエラーが出ます。クロージャに`move`を付与したら、`v`をクロージャの環境にムーブするので、 +リスト16-4の、メインスレッドが`drop`を呼び出すコードを修正するためにも、 +`move`クロージャを使用して同じことを試したくなるかもしれません。しかしながら、 +リスト16-4が試みていることは別の理由によりできないので、この修正はうまくいきません。 +クロージャに`move`を付与したら、`v`をクロージャの環境にムーブするので、 最早メインスレッドで`drop`を呼び出すことは叶わなくなるでしょう。代わりにこのようなコンパイルエラーが出るでしょう: -```text -error[E0382]: use of moved value: `v` -(エラー: ムーブされた値の使用: `v`) - --> src/main.rs:10:10 - | -6 | let handle = thread::spawn(move || { - | ------- value moved (into closure) here -... -10 | drop(v); // oh no! - | ^ value used here after move - | - = note: move occurs because `v` has type `std::vec::Vec`, which does - not implement the `Copy` trait - (注釈: `v`の型が`std::vec::Vec`のためムーブが起きました。この型は、`Copy`トレイトを実装していません) + +```console +{{#include ../listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt}} ``` スレッドとスレッドAPIの基礎知識を得たので、スレッドで*できる*ことを見ていきましょう。 + + + +[capture]: ch13-01-closures.html#参照をキャプチャするか所有権を移動するか diff --git a/src/ch16-02-message-passing.md b/src/ch16-02-message-passing.md index 1ff7092cd..50e0753c2 100644 --- a/src/ch16-02-message-passing.md +++ b/src/ch16-02-message-passing.md @@ -8,45 +8,48 @@ One increasingly popular approach to ensuring safe concurrency is *message passing*, where threads or actors communicate by sending each other messages containing data. Here’s the idea in a slogan from [the Go language -documentation](http://golang.org/doc/effective_go.html): “Do not communicate by -sharing memory; instead, share memory by communicating.” +documentation](https://golang.org/doc/effective_go.html#concurrency): +“Do not communicate by sharing memory; instead, share memory by communicating.” --> 人気度を増してきている安全な並行性を保証する一つのアプローチが*メッセージ受け渡し*で、 スレッドやアクターがデータを含むメッセージを相互に送り合うことでやり取りします。 -こちらが、[Go言語のドキュメンテーション](http:golang.org/doc/effective_go.html)のスローガンにある考えです: +こちらが、[Go言語のドキュメンテーション](https://golang.org/doc/effective_go.html#concurrency)のスローガンにある考えです: 「メモリを共有することでやり取りするな; 代わりにやり取りすることでメモリを共有しろ」 -メッセージ送信並行性を達成するためにRustに存在する一つの主な道具は、*チャンネル*で、 -Rustの標準ライブラリが実装を提供しているプログラミング概念です。プログラミングのチャンネルは、 -水の流れのように考えることができます。小川とか川ですね。アヒルのおもちゃやボートみたいなものを流れに置いたら、 -水路の終端まで下流に流れていきます。 +メッセージ送信による並行性を達成するために、Rustの標準ライブラリは*チャンネル*の実装を提供しています。 +チャンネルは、あるスレッドから別のスレッドへデータを送信する手段である、普遍的なプログラミング概念です。 + +プログラミングのチャンネルは、川などの、向きのある水路のように考えることができます(訳注: channelは日常語としては水路を意味します)。 +アヒルのおもちゃなどを川に置いたら、水路の終端まで下流に流れていきます。 + + -プログラミングにおけるチャンネルは、2分割できます: 転送機と受信機です。転送機はアヒルのおもちゃを川に置く上流になり、 +チャンネルは、2分割できます: 転送機と受信機です。転送機はアヒルのおもちゃを川に置く上流になり、 受信機は、アヒルのおもちゃが行き着く下流になります。コードのある箇所が送信したいデータとともに転送機のメソッドを呼び出し、 別の部分がメッセージが到着していないか受信側を調べます。転送機と受信機のどちらかがドロップされると、 チャンネルは*閉じられた*と言います。 @@ -56,15 +59,16 @@ Here, we’ll work up to a program that has one thread to generate values and send them down a channel, and another thread that will receive the values and print them out. We’ll be sending simple values between threads using a channel to illustrate the feature. Once you’re familiar with the technique, you could -use channels to implement a chat system or a system where many threads perform -parts of a calculation and send the parts to one thread that aggregates the -results. +use channels for any threads that need to communicate between each other, such +as a chat system or a system where many threads perform parts of a calculation +and send the parts to one thread that aggregates the results. --> ここで、1つのスレッドが値を生成し、それをチャンネルに送信し、別のスレッドがその値を受け取り、 出力するプログラムに取り掛かります。チャンネルを使用してスレッド間に単純な値を送り、 -機能の説明を行います。一旦、そのテクニックに慣れてしまえば、チャンネルを使用してチャットシステムや、 -多くのスレッドが計算の一部を担い、結果をまとめる1つのスレッドにその部分を送るようなシステムを実装できるでしょう。 +機能の説明を行います。一旦そのテクニックに慣れてしまえば、チャットシステムや、 +多くのスレッドが計算の一部を担い、結果をまとめる1つのスレッドにその部分を送るようなシステムなど、 +任意のスレッドが互いに通信する必要があるシステムに対して、チャンネルを使用できるでしょう。 - -`mpsc::channel`関数はタプルを返し、1つ目の要素は、送信側、2つ目の要素は受信側になります。 +`mpsc::channel`関数はタプルを返し、1つ目の要素は、送信側(転送機)、2つ目の要素は受信側(受信機)になります。 `tx`と`rx`という略称は、多くの分野で伝統的に*転送機*と*受信機*にそれぞれ使用されているので、 変数をそのように名付けて、各終端を示します。タプルを分配するパターンを伴う`let`文を使用しています; -`let`文でパターンを使用することと分配については、第18章で議論しましょう。このように`let`文を使うと、 -`mpsc::channel`で返ってくるタプルの部品を抽出するのが便利になります。 +`let`文でパターンを使用することと分配については、第18章で議論しましょう。今のところは、 +このように`let`文を使うと、`mpsc::channel`で返ってくるタプルの部品を抽出するのが便利になるということだけ知っておいてください。 - -今回も、`thread::spawn`を使用して新しいスレッドを生成し、それから`move`を使用して、 -立ち上げたスレッドが`tx`を所有するようにクロージャに`tx`をムーブしています。立ち上げたスレッドは、 -メッセージをチャンネルを通して送信できるように、チャンネルの送信側を所有する必要があります。 - - -転送側には、送信したい値を取る`send`メソッドがあります。`send`メソッドは`Result`型を返すので、 -既に受信側がドロップされ、値を送信する場所がなければ、送信処理はエラーを返します。 +今回も、`thread::spawn`を使用して新しいスレッドを生成し、それから`move`を使用して、 +立ち上げたスレッドが`tx`を所有するようにクロージャに`tx`をムーブしています。立ち上げたスレッドは、 +メッセージをチャンネルを通して送信できるように、転送機を所有する必要があります。 +転送機には、送信したい値を取る`send`メソッドがあります。`send`メソッドは`Result`型を返すので、 +既に受信機がドロップされ、値を送信する場所がなければ、送信処理はエラーを返します。 この例では、エラーの場合には、パニックするように`unwrap`を呼び出しています。ですが、実際のアプリケーションでは、 ちゃんと扱うでしょう: 第9章に戻ってちゃんとしたエラー処理の方法を再確認してください。 -リスト16-8において、メインスレッドのチャンネルの受信側から値を得ます。 -アヒルのおもちゃを川の終端で水から回収したり、チャットメッセージを取得するみたいですね。 +リスト16-8において、メインスレッドのチャンネルの受信機から値を得ます。 +アヒルのおもちゃを川の終端で水から回収したり、チャットメッセージを受信するみたいですね。 -チャンネルの受信側には有用なメソッドが2つあります: `recv`と`try_recv`です。 +受信機には有用なメソッドが2つあります: `recv`と`try_recv`です。 *receive*の省略形である`recv`を使っています。これは、メインスレッドの実行をブロックし、 値がチャンネルを流れてくるまで待機します。一旦値が送信されたら、`recv`はそれを`Result`に含んで返します。 -チャンネルの送信側が閉じたら、`recv`はエラーを返し、もう値は来ないと通知します。 +転送機が閉じたら、`recv`はエラーを返し、もう値は来ないと通知します。 + ```text Got: hi ``` @@ -305,7 +275,7 @@ Perfect! @@ -364,17 +319,8 @@ us an error if we try to compile the code in Listing 16-9: 可能性として、その別のスレッドの変更により、矛盾していたり存在しないデータのせいでエラーが発生したり、 予期しない結果になるでしょう。ですが、リスト16-9のコードのコンパイルを試みると、Rustはエラーを返します: -```text -error[E0382]: use of moved value: `val` - --> src/main.rs:10:31 - | -9 | tx.send(val).unwrap(); - | --- value moved here -10 | println!("val is {}", val); - | ^^^ value used here after move - | - = note: move occurs because `val` has type `std::string::String`, which does -not implement the `Copy` trait +```console +{{#include ../listings/ch16-fearless-concurrency/listing-16-09/output.txt}} ``` + ```text Got: hi Got: from @@ -502,12 +427,12 @@ the spawned thread. Earlier we mentioned that `mpsc` was an acronym for *multiple producer, single consumer*. Let’s put `mpsc` to use and expand the code in Listing 16-10 to create multiple threads that all send values to the same receiver. We can do -so by cloning the transmitting half of the channel, as shown in Listing 16-11: +so by cloning the transmitter, as shown in Listing 16-11: --> `mpsc`は、*mutiple producer, single consumer*の頭字語であると前述しました。 `mpsc`を使い、リスト16-10のコードを拡張して、全ての値を同じ受信機に送信する複数のスレッドを生成しましょう。 -チャンネルの転送の片割れをクローンすることでそうすることができます。リスト16-11のようにですね: +転送機をクローンすることでそうすることができます。リスト16-11のようにですね: -今回、最初のスレッドを立ち上げる前に、チャンネルの送信側に対して`clone`を呼び出しています。 -これにより、最初に立ち上げたスレッドに渡せる新しい送信ハンドルが得られます。 -元のチャンネルの送信側は、2番目に立ち上げたスレッドに渡します。これにより2つスレッドが得られ、 -それぞれチャンネルの受信側に異なるメッセージを送信します。 +今回、最初のスレッドを立ち上げる前に、転送機に対して`clone`を呼び出しています。 +これにより、最初に立ち上げたスレッドに渡せる新しい転送機が得られます。 +元の転送機は、2番目に立ち上げたスレッドに渡します。これにより2つスレッドが得られ、 +1つの受信機にそれぞれ異なるメッセージを送信します。 + ```text Got: hi Got: more @@ -601,13 +485,13 @@ Got: you ``` -別の順番で値が出る可能性もあります; システム次第です。並行性が面白いと同時に難しい部分でもあります。 +システム次第で、別の順番で値が出る可能性もあります。並行性が面白いと同時に難しい部分でもあります。 異なるスレッドで色々な値を与えて`thread::sleep`で実験をしたら、走らせるたびにより非決定的になり、 毎回異なる出力をするでしょう。 diff --git a/src/ch16-03-shared-state.md b/src/ch16-03-shared-state.md index 0d05d1e6f..54f4b409c 100644 --- a/src/ch16-03-shared-state.md +++ b/src/ch16-03-shared-state.md @@ -6,21 +6,23 @@ メッセージ受け渡しは、並行性を扱う素晴らしい方法ですが、唯一の方法ではありません。 +他の方法としては、複数のスレッドが同一の共有されたデータにアクセスする方法があるでしょう。 Go言語ドキュメンテーションのスローガンのこの部分を再び考えてください: -「メモリを共有することでやり取りする。」 +「メモリを共有することでやり取りするな。」 メモリを共有することでやり取りするとはどんな感じなのでしょうか?さらに、 -なぜメッセージ受け渡しに熱狂的な人は、それを使わず、代わりに全く反対のことをするのでしょうか? +なぜメッセージ受け渡しに熱狂的な人は、メモリ共有を使うなと警告するのでしょうか? ミューテックスは、どんな時も1つのスレッドにしかなんらかのデータへのアクセスを許可しないというように、 -"mutual exclusion"(相互排他)の省略形です。ミューテックスにあるデータにアクセスするには、 +*mutual exclusion*(相互排他)の省略形です。ミューテックスにあるデータにアクセスするには、 ミューテックスのロックを所望することでアクセスしたいことをまず、スレッドは通知しなければなりません。 ロックとは、現在誰がデータへの排他的アクセスを行なっているかを追跡するミューテックスの一部をなすデータ構造です。 故に、ミューテックスはロックシステム経由で保持しているデータを*死守する*(guarding)と解説されます。 @@ -77,7 +79,7 @@ remember two rules: * データを使用する前にロックの獲得を試みなければならない。 @@ -131,18 +133,7 @@ single-threaded context, as shown in Listing 16-12: ファイル名: src/main.rs ```rust -use std::sync::Mutex; - -fn main() { - let m = Mutex::new(5); - - { - let mut num = m.lock().unwrap(); - *num = 6; - } - - println!("m = {:?}", m); -} +{{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-12/src/main.rs}} ``` ロックを獲得した後、今回の場合、`num`と名付けられていますが、戻り値を中に入っているデータへの可変参照として扱うことができます。 -型システムにより、`m`の値を使用する前にロックを獲得していることが確認されます: `Mutex`は`i32`ではないので、 -`i32`を使用できるようにするには、ロックを獲得し*なければならない*のです。忘れることはあり得ません; +型システムにより、`m`の値を使用する前にロックを獲得していることが確認されます。`m`の型は`Mutex`であって`i32`ではないので、 +`i32`を使用できるようにするには、`lock`を呼び出さ*なければならない*のです。忘れることはあり得ません; 型システムにより、それ以外の場合に内部の`i32`にアクセスすることは許されません。 お察しかもしれませんが、`Mutex`はスマートポインタです。より正確を期すなら、 -`lock`の呼び出しが`MutexGuard`というスマートポインタを*返却*します。このスマートポインタが、 +`lock`を呼び出すと`LockResult`に包まれた形で`MutexGuard`というスマートポインタを*返却*し、 +これを`unwrap`の呼び出しによって処理しました。`MutexGuard`スマートポインタが、 内部のデータを指す`Deref`を実装しています; このスマートポインタはさらに`MutexGuard`がスコープを外れた時に、 -自動的にロックを解除する`Drop`実装もしていて、これがリスト16-12の内部スコープの終わりで発生します。 +自動的にロックを解除する`Drop`実装もしていて、これが内部スコープの終わりで発生します。 結果として、ロックの解除が自動的に行われるので、ロックの解除を忘れ、 ミューテックスが他のスレッドで使用されるのを阻害するリスクを負いません。 @@ -220,46 +214,23 @@ to change the inner `i32` to 6. さて、`Mutex`を使って複数のスレッド間で値を共有してみましょう。10個のスレッドを立ち上げ、 各々カウンタの値を1ずつインクリメントさせるので、カウンタは0から10まで上がります。 -以下の数例は、コンパイルエラーになることに注意し、そのエラーを使用して`Mutex`の使用法と、 -コンパイラがそれを正しく活用する手助けをしてくれる方法について学びます。リスト16-13が最初の例です: - +次のリスト16-13の例はコンパイルエラーになりますが、そのエラーを使用して、`Mutex`の使用法と、 +コンパイラがそれを正しく活用する手助けをしてくれる方法について学びます。 ファイル名: src/main.rs -```rust,ignore -use std::sync::Mutex; -use std::thread; - -fn main() { - let counter = Mutex::new(0); - let mut handles = vec![]; - - for _ in 0..10 { - let handle = thread::spawn(move || { - let mut num = counter.lock().unwrap(); - - *num += 1; - }); - handles.push(handle); - } - - for handle in handles { - handle.join().unwrap(); - } - - println!("Result: {}", *counter.lock().unwrap()); -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-13/src/main.rs}} ``` リスト16-12のように、`counter`変数を生成して`Mutex`の内部に`i32`を保持しています。 -次に、数値の範囲をマッピングして10個のスレッドを生成しています。`thread::spawn`を使用して、 +次に、数値の範囲を走査して10個のスレッドを生成しています。`thread::spawn`を使用して、 全スレッドに同じクロージャを与えています。このクロージャは、スレッド内にカウンタをムーブし、 `lock`メソッドを呼ぶことで`Mutex`のロックを獲得し、それからミューテックスの値に1を足します。 スレッドがクロージャを実行し終わったら、`num`はスコープ外に出てロックを解除するので、 @@ -288,12 +259,12 @@ lock so another thread can acquire it. -メインスレッドで全てのjoinハンドルを収集します。それからリスト16-2のように、各々に対して`join`を呼び出し、 +メインスレッドで全てのjoinハンドルを収集します。それからリスト16-2のように、各ハンドルに対して`join`を呼び出し、 全スレッドが終了するのを確かめています。その時点で、メインスレッドはロックを獲得し、このプログラムの結果を出力します。 src/main.rs:10:27 - | -9 | let handle = thread::spawn(move || { - | ------- value moved (into closure) here -10 | let mut num = counter.lock().unwrap(); - | ^^^^^^^ value captured here after move - | - = note: move occurs because `counter` has type `std::sync::Mutex`, - which does not implement the `Copy` trait - -error[E0382]: use of moved value: `counter` - --> src/main.rs:21:29 - | -9 | let handle = thread::spawn(move || { - | ------- value moved (into closure) here -... -21 | println!("Result: {}", *counter.lock().unwrap()); - | ^^^^^^^ value used here after move - | - = note: move occurs because `counter` has type `std::sync::Mutex`, - which does not implement the `Copy` trait - -error: aborting due to 2 previous errors -(エラー: 前述の2つのエラーによりアボート) +```console +{{#include ../listings/ch16-fearless-concurrency/listing-16-13/output.txt}} ``` -エラーメッセージは、`counter`値はクロージャにムーブされ、それから`lock`を呼び出したときにキャプチャされていると述べています。 -その説明は、所望した動作のように聞こえますが、許可されていないのです! - -プログラムを単純化してこれを理解しましょう。`for`ループで10個スレッドを生成する代わりに、 -ループなしで2つのスレッドを作るだけにしてどうなるか確認しましょう。 -リスト16-13の最初の`for`ループを代わりにこのコードと置き換えてください: - -```rust,ignore -use std::sync::Mutex; -use std::thread; - -fn main() { - let counter = Mutex::new(0); - let mut handles = vec![]; - - let handle = thread::spawn(move || { - let mut num = counter.lock().unwrap(); - - *num += 1; - }); - handles.push(handle); - - let handle2 = thread::spawn(move || { - let mut num2 = counter.lock().unwrap(); - - *num2 += 1; - }); - handles.push(handle2); - - for handle in handles { - handle.join().unwrap(); - } - - println!("Result: {}", *counter.lock().unwrap()); -} -``` - - - -2つのスレッドを生成し、2番目のスレッドの変数名を`handle2`と`num2`に変更しています。 -今回このコードを走らせると、コンパイラは以下の出力をします: - -```text -error[E0382]: capture of moved value: `counter` - --> src/main.rs:16:24 - | -8 | let handle = thread::spawn(move || { - | ------- value moved (into closure) here -... -16 | let mut num2 = counter.lock().unwrap(); - | ^^^^^^^ value captured here after move - | - = note: move occurs because `counter` has type `std::sync::Mutex`, - which does not implement the `Copy` trait - -error[E0382]: use of moved value: `counter` - --> src/main.rs:26:29 - | -8 | let handle = thread::spawn(move || { - | ------- value moved (into closure) here -... -26 | println!("Result: {}", *counter.lock().unwrap()); - | ^^^^^^^ value used here after move - | - = note: move occurs because `counter` has type `std::sync::Mutex`, - which does not implement the `Copy` trait - -error: aborting due to 2 previous errors -``` - - - -なるほど!最初のエラーメッセージは、`handle`に紐づけられたスレッドのクロージャに`counter`がムーブされていることを示唆しています。 -そのムーブにより、それに対して`lock`を呼び出し、結果を2番目のスレッドの`num2`に保持しようとした時に、 -`counter`をキャプチャすることを妨げています!ゆえに、コンパイラは、`counter`の所有権を複数のスレッドに移すことはできないと教えてくれています。 -これは、以前では確認しづらかったことです。なぜなら、スレッドはループの中にあり、 -ループの違う繰り返しにある違うスレッドをコンパイラは指し示せないからです。 -第15章で議論した複数所有権メソッドによりコンパイルエラーを修正しましょう。 +エラーメッセージには、`counter`値はループの前回の反復時にムーブされたと書いてあります。 +コンパイラは、ロック`counter`の所有権を複数のスレッドに移動することはできないと教えてくれているのです。 +第15章で議論した、複数所有権の手法を使って、コンパイラエラーを修正しましょう。 第15章で、スマートポインタの`Rc`を使用して参照カウントの値を作ることで、1つの値に複数の所有者を与えました。 同じことをここでもして、どうなるか見ましょう。リスト16-14で`Rc`に`Mutex`を包含し、 -所有権をスレッドに移す前に`Rc`をクローンします。今やエラーを確認したので、 -`for`ループの使用に立ち戻り、クロージャに`move`キーワードを使用し続けます。 +所有権をスレッドに移す前に`Rc`をクローンします。 src/main.rs:11:22 - | -11 | let handle = thread::spawn(move || { - | ^^^^^^^^^^^^^ `std::rc::Rc>` -cannot be sent between threads safely - (`std::rc::Rc>`は、スレッド間で安全に送信できません) - | - = help: within `[closure@src/main.rs:11:36: 15:10 -counter:std::rc::Rc>]`, the trait `std::marker::Send` is -not implemented for `std::rc::Rc>` - (ヘルプ: `[closure@src/main.rs:11:36 15:10 - counter:std::rc::Rc>]`内でトレイト`std::marker::Send`は、 - `std::rc::Rc>`に対して実装されていません) - = note: required because it appears within the type -`[closure@src/main.rs:11:36: 15:10 counter:std::rc::Rc>]` - (注釈: 型`[closure@src/main.rs:11:36 15:10 - counter:std::rc::Rc>]`内に出現するので必要です) - = note: required by `std::thread::spawn` - (注釈: `std::thread::spawn`により必要とされています) +```console +{{#include ../listings/ch16-fearless-concurrency/listing-16-14/output.txt}} ``` -おお、このエラーメッセージはとても長ったらしいですね!こちらが、注目すべき重要な部分です: -最初のインラインエラーは`` `std::rc::Rc>` cannot be sent -between threads safely``と述べています。この理由は、エラーメッセージの次に注目すべき重要な部分にあります。 -洗練されたエラーメッセージは、`` the trait bound `Send` is not satisfied``と述べています。 +おお、このエラーメッセージはとても長ったらしいですね!注目すべき重要な部分はここです: +`` `Rc>` cannot be sent between threads safely ``。コンパイラは、 +その理由も伝えてくれています: `` the trait `Send` is not implemented for `Rc>` ``。 `Send`については、次の節で語ります: スレッドとともに使用している型が並行な場面で使われることを意図したものであることを保証するトレイトの1つです。 @@ -575,15 +380,15 @@ Fortunately, `Arc` *is* a type like `Rc` that is safe to use in concurrent situations. The *a* stands for *atomic*, meaning it’s an *atomically reference counted* type. Atomics are an additional kind of concurrency primitive that we won’t cover in detail here: see the standard library -documentation for `std::sync::atomic` for more details. At this point, you just -need to know that atomics work like primitive types but are safe to share -across threads. +documentation for [`std::sync::atomic`][atomic] for more +details. At this point, you just need to know that atomics work like primitive +types but are safe to share across threads. --> 幸いなことに、`Arc`は`Rc`のような並行な状況で安全に使用できる型*です*。 *a*は*atomic*を表し、原子的に参照カウントする型を意味します。アトミックは、 ここでは詳しく講義しない並行性の別の基本型です: 詳細は、 -`std::sync::atomic`の標準ライブラリドキュメンテーションを参照されたし。現時点では、 +[`std::sync::atomic`][atomic]の標準ライブラリドキュメンテーションを参照されたし。現時点では、 アトミックは、基本型のように動くけれども、スレッド間で共有しても安全なことだけ知っていれば良いです。 + ```text Result: 10 ``` @@ -672,6 +459,20 @@ thread update the final result with its part. 計算を独立した部分に小分けにし、その部分をスレッドに分割し、それから`Mutex`を使用して、 各スレッドに最終結果を更新させることができます。 + + +単純な数値演算を行おうとしているなら、`Mutex`型よりも単純な、 +[標準ライブラリの`std::sync::atomic`モジュール][atomic]によって提供される型があることに注意してください。 +これらの型はプリミティブ型に対する安全かつ並行的なアトミックアクセスを提供します。 +この例では`Mutex`がどのように機能するかに集中できるように、 +プリミティブ型に対して`Mutex`を使用することをあえて選択しました。 + @@ -721,3 +522,9 @@ how we can use them with custom types. --> `Send`と`Sync`トレイトと、それらを独自の型で使用する方法について語って、この章を締めくくります。 + + + +[atomic]: https://doc.rust-lang.org/std/sync/atomic/index.html diff --git a/src/ch16-04-extensible-concurrency-sync-and-send.md b/src/ch16-04-extensible-concurrency-sync-and-send.md index 5bb8b5a3e..cae294e88 100644 --- a/src/ch16-04-extensible-concurrency-sync-and-send.md +++ b/src/ch16-04-extensible-concurrency-sync-and-send.md @@ -34,16 +34,17 @@ However, two concurrency concepts are embedded in the language: the --> -`Send`マーカートレイトは、`Send`を実装した型の所有権をスレッド間で転送できることを示唆します。 +`Send`マーカートレイトは、`Send`を実装した型を持つ値の所有権をスレッド間で転送できることを示唆します。 Rustのほとんどの型は`Send`ですが、`Rc`を含めて一部例外があります: この型は、`Rc`の値をクローンし、 クローンしたものの所有権を別のスレッドに転送しようとしたら、両方のスレッドが同時に参照カウントを更新できてしまうので、 `Send`になり得ません。このため、`Rc`はスレッド安全性のためのパフォーマンスの犠牲を支払わなくても済む、 @@ -79,13 +80,13 @@ we’ll discuss in Chapter 19. `Sync`マーカートレイトは、`Sync`を実装した型は、複数のスレッドから参照されても安全であることを示唆します。 -言い換えると、`&T`(`T`への参照)が`Send`なら、型`T`は`Sync`であり、参照が他のスレッドに安全に送信できることを意味します。 +言い換えると、`&T`(`T`への不変参照)が`Send`なら、型`T`は`Sync`であり、参照が他のスレッドに安全に送信できることを意味します。 `Send`同様、基本型は`Sync`であり、`Sync`の型からのみ構成される型もまた`Sync`です。 `Send`ではなかったのと同じ理由で、スマートポインタの`Rc`もまた`Sync`ではありません。 `RefCell`型(これについては第15章で話しました)と関連する`Cell`系についても`Sync`ではありません。 `RefCell`が実行時に行う借用チェックの実装は、スレッド安全ではないのです。 -スマートポインタの`Mutex`は`Sync`で、「複数のスレッド間で`Mutex`を共有する」節で見たように、 +スマートポインタの`Mutex`は`Sync`で、[「複数のスレッド間で`Mutex`を共有する」][sharing-a-mutext-between-multiple-threads]節で見たように、 複数のスレッドでアクセスを共有するのに使用することができます。 これらのトレイトを手動で実装するには、unsafeなRustコードを実装することが関わってきます。 unsafeなRustコードを使用することについては第19章で語ります; とりあえず、重要な情報は、 `Send`と`Sync`ではない部品からなる新しい並行な型を構成するには、安全性保証を保持するために、 -注意深い思考が必要になるということです。[The Rustonomicon]には、 +注意深い思考が必要になるということです。[“The Rustonomicon”][nomicon]には、 これらの保証とそれを保持する方法についての情報がより多くあります。 > 訳注: 日本語版のThe Rustonomiconは[こちら][nomicon-ja]です。 -[The Rustonomicon]: https://doc.rust-lang.org/stable/nomicon/ [nomicon-ja]: https://doc.rust-jp.rs/rust-nomicon-ja/index.html 次は、Rustプログラムが肥大化するにつれて問題をモデル化し、解決策を構造化する慣例的な方法について話します。 さらに、Rustのイディオムがオブジェクト指向プログラミングで馴染み深いかもしれないイディオムにどのように関連しているかについても議論します。 + + + +[sharing-a-mutext-between-multiple-threads]: +ch16-03-shared-state.html#複数のスレッド間でmutextを共有する +[nomicon]: https://doc.rust-lang.org/stable/nomicon/ From d61d23dbdd32bc98407519dd3768721f2f01eaa3 Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:07 +0900 Subject: [PATCH 18/22] =?UTF-8?q?ch17=20Rust=E3=81=AE=E3=82=AA=E3=83=96?= =?UTF-8?q?=E3=82=B8=E3=82=A7=E3=82=AF=E3=83=88=E6=8C=87=E5=90=91=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=82=B0=E3=83=A9=E3=83=9F=E3=83=B3=E3=82=B0=E6=A9=9F?= =?UTF-8?q?=E8=83=BD=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0?= =?UTF-8?q?=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- listings/ch17-oop/listing-17-01/Cargo.toml | 3 +- listings/ch17-oop/listing-17-02/Cargo.toml | 3 +- listings/ch17-oop/listing-17-03/Cargo.toml | 3 +- listings/ch17-oop/listing-17-04/Cargo.toml | 3 +- listings/ch17-oop/listing-17-05/Cargo.toml | 3 +- listings/ch17-oop/listing-17-06/Cargo.toml | 3 +- listings/ch17-oop/listing-17-07/Cargo.toml | 3 +- listings/ch17-oop/listing-17-07/src/lib.rs | 3 +- listings/ch17-oop/listing-17-08/Cargo.toml | 3 +- listings/ch17-oop/listing-17-08/src/main.rs | 1 + listings/ch17-oop/listing-17-09/Cargo.toml | 3 +- listings/ch17-oop/listing-17-09/src/main.rs | 3 + listings/ch17-oop/listing-17-10/Cargo.toml | 3 +- listings/ch17-oop/listing-17-10/output.txt | 13 +- listings/ch17-oop/listing-17-11/Cargo.toml | 3 +- listings/ch17-oop/listing-17-11/src/main.rs | 1 + listings/ch17-oop/listing-17-12/Cargo.toml | 3 +- listings/ch17-oop/listing-17-13/Cargo.toml | 3 +- listings/ch17-oop/listing-17-13/src/lib.rs | 2 - listings/ch17-oop/listing-17-14/Cargo.toml | 3 +- listings/ch17-oop/listing-17-14/src/lib.rs | 2 - listings/ch17-oop/listing-17-15/Cargo.toml | 3 +- listings/ch17-oop/listing-17-15/src/lib.rs | 2 - listings/ch17-oop/listing-17-16/Cargo.toml | 3 +- listings/ch17-oop/listing-17-17/Cargo.toml | 3 +- listings/ch17-oop/listing-17-18/Cargo.toml | 3 +- listings/ch17-oop/listing-17-19/Cargo.toml | 3 +- listings/ch17-oop/listing-17-20/Cargo.toml | 3 +- listings/ch17-oop/listing-17-21/Cargo.toml | 3 +- .../Cargo.lock | 6 - .../Cargo.toml | 7 - .../output.txt | 16 - .../src/lib.rs | 3 - src/ch17-00-oop.md | 32 +- src/ch17-01-what-is-oo.md | 158 ++--- src/ch17-02-trait-objects.md | 402 +++--------- src/ch17-03-oo-design-patterns.md | 584 ++++++------------ 37 files changed, 410 insertions(+), 888 deletions(-) delete mode 100644 listings/ch17-oop/no-listing-01-trait-object-of-clone/Cargo.lock delete mode 100644 listings/ch17-oop/no-listing-01-trait-object-of-clone/Cargo.toml delete mode 100644 listings/ch17-oop/no-listing-01-trait-object-of-clone/output.txt delete mode 100644 listings/ch17-oop/no-listing-01-trait-object-of-clone/src/lib.rs diff --git a/listings/ch17-oop/listing-17-01/Cargo.toml b/listings/ch17-oop/listing-17-01/Cargo.toml index ab96488d1..aed614e93 100644 --- a/listings/ch17-oop/listing-17-01/Cargo.toml +++ b/listings/ch17-oop/listing-17-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "averaged-collection" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-02/Cargo.toml b/listings/ch17-oop/listing-17-02/Cargo.toml index ab96488d1..aed614e93 100644 --- a/listings/ch17-oop/listing-17-02/Cargo.toml +++ b/listings/ch17-oop/listing-17-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "averaged-collection" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-03/Cargo.toml b/listings/ch17-oop/listing-17-03/Cargo.toml index 1f61cd20e..9b816e766 100644 --- a/listings/ch17-oop/listing-17-03/Cargo.toml +++ b/listings/ch17-oop/listing-17-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "gui" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-04/Cargo.toml b/listings/ch17-oop/listing-17-04/Cargo.toml index 1f61cd20e..9b816e766 100644 --- a/listings/ch17-oop/listing-17-04/Cargo.toml +++ b/listings/ch17-oop/listing-17-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "gui" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-05/Cargo.toml b/listings/ch17-oop/listing-17-05/Cargo.toml index 1f61cd20e..9b816e766 100644 --- a/listings/ch17-oop/listing-17-05/Cargo.toml +++ b/listings/ch17-oop/listing-17-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "gui" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-06/Cargo.toml b/listings/ch17-oop/listing-17-06/Cargo.toml index 1f61cd20e..9b816e766 100644 --- a/listings/ch17-oop/listing-17-06/Cargo.toml +++ b/listings/ch17-oop/listing-17-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "gui" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-07/Cargo.toml b/listings/ch17-oop/listing-17-07/Cargo.toml index 1f61cd20e..9b816e766 100644 --- a/listings/ch17-oop/listing-17-07/Cargo.toml +++ b/listings/ch17-oop/listing-17-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "gui" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-07/src/lib.rs b/listings/ch17-oop/listing-17-07/src/lib.rs index 413dc6ff1..94f353bb9 100644 --- a/listings/ch17-oop/listing-17-07/src/lib.rs +++ b/listings/ch17-oop/listing-17-07/src/lib.rs @@ -24,8 +24,7 @@ pub struct Button { impl Draw for Button { fn draw(&self) { // code to actually draw a button + // 実際にボタンを描画するコード } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch17-oop/listing-17-08/Cargo.toml b/listings/ch17-oop/listing-17-08/Cargo.toml index 1f61cd20e..9b816e766 100644 --- a/listings/ch17-oop/listing-17-08/Cargo.toml +++ b/listings/ch17-oop/listing-17-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "gui" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-08/src/main.rs b/listings/ch17-oop/listing-17-08/src/main.rs index 9575d407e..dc45526e6 100644 --- a/listings/ch17-oop/listing-17-08/src/main.rs +++ b/listings/ch17-oop/listing-17-08/src/main.rs @@ -10,6 +10,7 @@ struct SelectBox { impl Draw for SelectBox { fn draw(&self) { // code to actually draw a select box + //セレクトボックスを実際に描画するコード } } // ANCHOR_END: here diff --git a/listings/ch17-oop/listing-17-09/Cargo.toml b/listings/ch17-oop/listing-17-09/Cargo.toml index 1f61cd20e..9b816e766 100644 --- a/listings/ch17-oop/listing-17-09/Cargo.toml +++ b/listings/ch17-oop/listing-17-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "gui" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-09/src/main.rs b/listings/ch17-oop/listing-17-09/src/main.rs index 4eb13f6b7..276d6e7b6 100644 --- a/listings/ch17-oop/listing-17-09/src/main.rs +++ b/listings/ch17-oop/listing-17-09/src/main.rs @@ -22,8 +22,11 @@ fn main() { width: 75, height: 10, options: vec![ + // はい String::from("Yes"), + // 多分 String::from("Maybe"), + // いいえ String::from("No"), ], }), diff --git a/listings/ch17-oop/listing-17-10/Cargo.toml b/listings/ch17-oop/listing-17-10/Cargo.toml index 1f61cd20e..9b816e766 100644 --- a/listings/ch17-oop/listing-17-10/Cargo.toml +++ b/listings/ch17-oop/listing-17-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "gui" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-10/output.txt b/listings/ch17-oop/listing-17-10/output.txt index b18e1e9b4..78d7c39a3 100644 --- a/listings/ch17-oop/listing-17-10/output.txt +++ b/listings/ch17-oop/listing-17-10/output.txt @@ -1,16 +1,13 @@ $ cargo run Compiling gui v0.1.0 (file:///projects/gui) -error[E0277]: the trait bound `std::string::String: gui::Draw` is not satisfied +error[E0277]: the trait bound `String: Draw` is not satisfied --> src/main.rs:5:26 | 5 | components: vec![Box::new(String::from("Hi"))], - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `gui::Draw` is not implemented for `std::string::String` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Draw` is not implemented for `String` | - = note: required for the cast to the object type `dyn gui::Draw` - -error: aborting due to previous error + = help: the trait `Draw` is implemented for `Button` + = note: required for the cast from `Box` to `Box` For more information about this error, try `rustc --explain E0277`. -error: could not compile `gui`. - -To learn more, run the command again with --verbose. +error: could not compile `gui` (bin "gui") due to 1 previous error diff --git a/listings/ch17-oop/listing-17-11/Cargo.toml b/listings/ch17-oop/listing-17-11/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-11/Cargo.toml +++ b/listings/ch17-oop/listing-17-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-11/src/main.rs b/listings/ch17-oop/listing-17-11/src/main.rs index d99170a97..2c598a5c5 100644 --- a/listings/ch17-oop/listing-17-11/src/main.rs +++ b/listings/ch17-oop/listing-17-11/src/main.rs @@ -5,6 +5,7 @@ use blog::Post; fn main() { let mut post = Post::new(); + // "今日はお昼にサラダを食べた" post.add_text("I ate a salad for lunch today"); assert_eq!("", post.content()); // ANCHOR_END: here diff --git a/listings/ch17-oop/listing-17-12/Cargo.toml b/listings/ch17-oop/listing-17-12/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-12/Cargo.toml +++ b/listings/ch17-oop/listing-17-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-13/Cargo.toml b/listings/ch17-oop/listing-17-13/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-13/Cargo.toml +++ b/listings/ch17-oop/listing-17-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-13/src/lib.rs b/listings/ch17-oop/listing-17-13/src/lib.rs index 0ae3fa6e8..bd68557a0 100644 --- a/listings/ch17-oop/listing-17-13/src/lib.rs +++ b/listings/ch17-oop/listing-17-13/src/lib.rs @@ -26,5 +26,3 @@ trait State {} struct Draft {} impl State for Draft {} - -fn main() {} diff --git a/listings/ch17-oop/listing-17-14/Cargo.toml b/listings/ch17-oop/listing-17-14/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-14/Cargo.toml +++ b/listings/ch17-oop/listing-17-14/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-14/src/lib.rs b/listings/ch17-oop/listing-17-14/src/lib.rs index 0d010f50c..09cf0c466 100644 --- a/listings/ch17-oop/listing-17-14/src/lib.rs +++ b/listings/ch17-oop/listing-17-14/src/lib.rs @@ -30,5 +30,3 @@ trait State {} struct Draft {} impl State for Draft {} - -fn main() {} diff --git a/listings/ch17-oop/listing-17-15/Cargo.toml b/listings/ch17-oop/listing-17-15/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-15/Cargo.toml +++ b/listings/ch17-oop/listing-17-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-15/src/lib.rs b/listings/ch17-oop/listing-17-15/src/lib.rs index 806b4e49d..909dd5274 100644 --- a/listings/ch17-oop/listing-17-15/src/lib.rs +++ b/listings/ch17-oop/listing-17-15/src/lib.rs @@ -50,5 +50,3 @@ impl State for PendingReview { } } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch17-oop/listing-17-16/Cargo.toml b/listings/ch17-oop/listing-17-16/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-16/Cargo.toml +++ b/listings/ch17-oop/listing-17-16/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-17/Cargo.toml b/listings/ch17-oop/listing-17-17/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-17/Cargo.toml +++ b/listings/ch17-oop/listing-17-17/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-18/Cargo.toml b/listings/ch17-oop/listing-17-18/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-18/Cargo.toml +++ b/listings/ch17-oop/listing-17-18/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-19/Cargo.toml b/listings/ch17-oop/listing-17-19/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-19/Cargo.toml +++ b/listings/ch17-oop/listing-17-19/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-20/Cargo.toml b/listings/ch17-oop/listing-17-20/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-20/Cargo.toml +++ b/listings/ch17-oop/listing-17-20/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/listing-17-21/Cargo.toml b/listings/ch17-oop/listing-17-21/Cargo.toml index 9a395e23a..1619af5c6 100644 --- a/listings/ch17-oop/listing-17-21/Cargo.toml +++ b/listings/ch17-oop/listing-17-21/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "blog" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch17-oop/no-listing-01-trait-object-of-clone/Cargo.lock b/listings/ch17-oop/no-listing-01-trait-object-of-clone/Cargo.lock deleted file mode 100644 index 00d7b2182..000000000 --- a/listings/ch17-oop/no-listing-01-trait-object-of-clone/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "gui" -version = "0.1.0" - diff --git a/listings/ch17-oop/no-listing-01-trait-object-of-clone/Cargo.toml b/listings/ch17-oop/no-listing-01-trait-object-of-clone/Cargo.toml deleted file mode 100644 index 1f61cd20e..000000000 --- a/listings/ch17-oop/no-listing-01-trait-object-of-clone/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "gui" -version = "0.1.0" -authors = ["Your Name "] -edition = "2018" - -[dependencies] diff --git a/listings/ch17-oop/no-listing-01-trait-object-of-clone/output.txt b/listings/ch17-oop/no-listing-01-trait-object-of-clone/output.txt deleted file mode 100644 index 33a492556..000000000 --- a/listings/ch17-oop/no-listing-01-trait-object-of-clone/output.txt +++ /dev/null @@ -1,16 +0,0 @@ -$ cargo build - Compiling gui v0.1.0 (file:///projects/gui) -error[E0038]: the trait `std::clone::Clone` cannot be made into an object - --> src/lib.rs:2:5 - | -2 | pub components: Vec>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` cannot be made into an object - | - = note: the trait cannot require that `Self : Sized` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0038`. -error: could not compile `gui`. - -To learn more, run the command again with --verbose. diff --git a/listings/ch17-oop/no-listing-01-trait-object-of-clone/src/lib.rs b/listings/ch17-oop/no-listing-01-trait-object-of-clone/src/lib.rs deleted file mode 100644 index e6b1a37f0..000000000 --- a/listings/ch17-oop/no-listing-01-trait-object-of-clone/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub struct Screen { - pub components: Vec>, -} diff --git a/src/ch17-00-oop.md b/src/ch17-00-oop.md index c9c159dc2..688045d38 100644 --- a/src/ch17-00-oop.md +++ b/src/ch17-00-oop.md @@ -5,24 +5,24 @@ # Rustのオブジェクト指向プログラミング機能 -オブジェクト指向プログラミング(OOP)は、プログラムをモデル化する手段です。オブジェクトは、 -1960年代のSimulaに端緒を発しています。このオブジェクトは、 +オブジェクト指向プログラミング(OOP)は、プログラムをモデル化する手段です。プログラム上の概念としてのオブジェクトは、 +1960年代のプログラミング言語Simulaで導入されました。このオブジェクトは、 お互いにメッセージを渡し合うというアラン・ケイ(Alan Kay)のプログラミングアーキテクチャに影響を及ぼしました。 -彼は、このアーキテクチャを解説するために、*オブジェクト指向プログラミング*という用語を造語しました。 -多くの競合する定義がOOPが何かを解説しています; Rustをオブジェクト指向と区分する定義もありますし、 -しない定義もあります。この章では、広くオブジェクト指向と捉えられる特定の特徴と、 +彼は、このアーキテクチャを記述するために、*オブジェクト指向プログラミング*という用語を造語しました。 +多くの競合する定義がOOPが何かを記述しており、こうした定義の一部によれば、Rustはオブジェクト指向であり +他の定義によれば、Rustはオブジェクト指向ではありません。この章では、広くオブジェクト指向と捉えられる特定の特徴と、 それらの特徴がこなれたRustでどう表現されるかを探究します。それからオブジェクト指向のデザインパターンをRustで実装する方法を示し、 そうすることとRustの強みを活用して代わりの解決策を実装する方法の代償を議論します。 diff --git a/src/ch17-01-what-is-oo.md b/src/ch17-01-what-is-oo.md index 237e5c048..b07c7cbb6 100644 --- a/src/ch17-01-what-is-oo.md +++ b/src/ch17-01-what-is-oo.md @@ -6,12 +6,12 @@ 言語がオブジェクト指向と考えられるのになければならない機能について、プログラミングコミュニティ内での総意はありません。 @@ -28,15 +28,14 @@ OOP言語は特定の一般的な特徴を共有しています。具体的に -エーリヒ・ガンマ(Enoch Gamma)、リチャード・ヘルム(Richard Helm)、ラルフ・ジョンソン(Ralph Johnson)、 -ジョン・ブリシディース(John Vlissides)(アディソン・ワズリー・プロ)により、 -1994年に書かれた*デザインパターン: 再利用可能なオブジェクト指向ソフトウェアの要素*という本は、 -俗に*4人のギャングの本*(`訳注`: the Gang of Four book; GoFとよく略される)と呼ばれ、オブジェクト指向デザインパターンのカタログです。 +エーリヒ・ガンマ(Erich Gamma)、リチャード・ヘルム(Richard Helm)、ラルフ・ジョンソン(Ralph Johnson)、 +ジョン・ブリシディース(John Vlissides)による本*Design Patterns: Elements of Reusable Object-Oriented Software* (Addison-Wesley Professional, 1994)は、 +俗に*4人のギャング*の本と呼ばれる、オブジェクト指向デザインパターンのカタログです。 そこでは、OOPは以下のように定義されています: -`add`、`remove`、`average`の公開メソッドが`AveragedCollection`のインスタンスを変更する唯一の方法になります。 -要素が`add`メソッドを使用して`list`に追加されたり、`remove`メソッドを使用して削除されたりすると、 +`add`、`remove`、`average`の公開メソッドが、`AveragedCollection`のインスタンス内のデータにアクセスまたは変更するための、 +唯一の方法になります。要素が`add`メソッドを使用して`list`に追加されたり、`remove`メソッドを使用して削除されたりすると、 各メソッドの実装が`average`フィールドの更新を扱う非公開の`update_average`メソッドも呼び出します。 `list`と`average`フィールドを非公開のままにしているので、外部コードが要素を`list`フィールドに直接追加したり削除したりする方法はありません; @@ -211,7 +178,7 @@ code to read the `average` but not modify it. Because we’ve encapsulated the implementation details of the struct `AveragedCollection`, we can easily change aspects, such as the data structure, in the future. For instance, we could use a `HashSet` instead of a -`Vec` for the `list` field. As long as the signatures of the `add` +`Vec` for the `list` field. As long as the signatures of the `add`, `remove`, and `average` public methods stay the same, code using `AveragedCollection` wouldn’t need to change. If we made `list` public instead, this wouldn’t necessarily be the case: `HashSet` and `Vec` have @@ -227,9 +194,9 @@ likely have to change if it were modifying `list` directly. 外部コードも変更しなければならない可能性が高いでしょう。 カプセル化が、言語がオブジェクト指向と考えられるのに必要な側面ならば、Rustはその条件を満たしています。 @@ -242,45 +209,51 @@ different parts of code enables encapsulation of implementation details. ### 型システム、およびコード共有としての継承 -*継承*は、それによってオブジェクトが他のオブジェクトの定義から受け継ぐことができる機構であり、 +*継承*は、それによってオブジェクトが他のオブジェクトの定義から要素を受け継ぐことができる機構であり、 それ故に、再定義する必要なく、親オブジェクトのデータと振る舞いを得ます。 言語がオブジェクト指向言語であるために継承がなければならないのならば、Rustは違います。 -親構造体のフィールドとメソッドの実装を受け継ぐ構造体を定義する方法はありません。しかしながら、 -継承がプログラミング道具箱にあることに慣れていれば、そもそも継承に手を伸ばす理由によって、 -Rustで他の解決策を使用することができます。 +親構造体のフィールドとメソッドの実装を受け継ぐ構造体をマクロを使わずに定義する方法はありません。 + +しかしながら、継承がプログラミング道具箱にあることに慣れていれば、 +そもそも継承に手を伸ばす理由によって、Rustで他の解決策を使用することができます。 + + 継承を選択する理由は主に2つあります。1つ目は、コードの再利用です: ある型に特定の振る舞いを実装し、 -継承により、その実装を他の型にも再利用できるわけです。デフォルトのトレイトメソッド実装を代わりに使用して、 -Rustコードを共有でき、これは、リスト10-14で`Summary`トレイトに`summarize`メソッドのデフォルト実装を追加した時に見かけました。 +継承により、その実装を他の型にも再利用できるわけです。Rustコードでは、 +デフォルトのトレイトメソッド実装を使用することで、限定された形でこれを行うことができ、 +これは、リスト10-14で`Summary`トレイトに`summarize`メソッドのデフォルト実装を追加した時に見かけました。 `Summary`トレイトを実装する型は全て、追加のコードなく`summarize`メソッドが使用できます。 これは、親クラスにメソッドの実装があり、継承した子クラスにもそのメソッドの実装があることと似ています。 また、`Summary`トレイトを実装する時に、`summarize`メソッドのデフォルト実装を上書きすることもでき、 @@ -324,9 +297,9 @@ than necessary. Subclasses shouldn’t always share all characteristics of their parent class but will do so with inheritance. This can make a program’s design less flexible. It also introduces the possibility of calling methods on subclasses that don’t make sense or that cause errors because the methods don’t -apply to the subclass. Some languages will also only allow a subclass -to inherit from one class, further restricting the flexibility of a program’s -design. +apply to the subclass. In addition, some languages will only allow single +inheritance (meaning a subclass can only inherit from one class), further +restricting the flexibility of a program’s design. --> 継承は、近年、多くのプログラミング言語において、プログラムの設計解決策としては軽んじられています。 @@ -334,12 +307,13 @@ design. 必ずしも親クラスの特徴を全て共有するべきではないのに、継承ではそうなってしまうのです。 これにより、プログラムの設計の柔軟性を失わせることもあります。また、道理に合わなかったり、メソッドがサブクラスには適用されないために、 エラーを発生させるようなサブクラスのメソッドの呼び出しを引き起こす可能性が出てくるのです。 -さらに、サブクラスに1つのクラスからだけ継承させる言語もあり、さらにプログラムの設計の柔軟性が制限されます。 +さらに、単一継承のみを許可する(サブクラスは1つのクラスからのみ継承できる)言語もあり、さらにプログラムの設計の柔軟性が制限されます。 -これらの理由により、継承ではなくトレイトオブジェクトを使用してRustは異なるアプローチを取っています。 +これらの理由によりRustは、継承ではなくトレイトオブジェクトを使用するという異なるアプローチを取っています。 Rustにおいて、トレイトオブジェクトがどう多相性を可能にするかを見ましょう。 diff --git a/src/ch17-02-trait-objects.md b/src/ch17-02-trait-objects.md index 1b689a583..b452eb13e 100644 --- a/src/ch17-02-trait-objects.md +++ b/src/ch17-02-trait-objects.md @@ -1,12 +1,12 @@ ## トレイトオブジェクトで異なる型の値を許容する 第8章で、ベクタの1つの制限は、たった1つの型の要素を保持することしかできないことだと述べました。 -リスト8-10で整数、浮動小数点数、テキストを保持する列挙子のある`SpreadsheetCell` enumを定義して、 +リスト8-9で整数、浮動小数点数、テキストを保持する列挙子のある`SpreadsheetCell` enumを定義して、 これを回避しました。つまり、各セルに異なる型のデータを格納しつつ、1行のセルを表すベクタを保持するということです。 コンパイル時にわかるある固定されたセットの型にしか取り替え可能な要素がならない場合には、 完璧な解決策です。 @@ -83,28 +83,31 @@ allow users to extend it with new types. `gui`に欲しい振る舞いを実装するには、`draw`という1つのメソッドを持つ`Draw`というトレイトを定義します。 それから*トレイトオブジェクト*を取るベクタを定義できます。トレイトオブジェクトは、 -指定したトレイトを実装するある型のインスタンスを指します。`&`参照や`Box`スマートポインタなどの、 -何らかのポインタを指定し、それから関係のあるトレイトを指定する(トレイトオブジェクトがポインタを使用しなければならない理由については、 -第19章の「動的サイズ決定型とSizedトレイト」節で語ります)ことでトレイトオブジェクトを作成します。 +指定されたトレイトを実装するある型のインスタンスと、実行時にその型に対するトレイトメソッドを探すのに使用されるテーブルの、 +両方を指します。`&`参照や`Box`スマートポインタなどの、何らかのポインタを指定し、 +それから`dyn`キーワード、そして対象のトレイトを指定する(トレイトオブジェクトがポインタを使用しなければならない理由については、 +第19章の[「動的サイズ決定型と`Sized`トレイト」][dynamically-sized]節で語ります)ことでトレイトオブジェクトを作成します。 ジェネリックまたは具体的な型があるところにトレイトオブジェクトは使用できます。どこでトレイトオブジェクトを使用しようと、 Rustの型システムは、コンパイル時にその文脈で使用されているあらゆる値がそのトレイトオブジェクトのトレイトを実装していることを保証します。 結果としてコンパイル時に可能性のある型を全て知る必要はなくなるのです。 この記法は、第10章のトレイトの定義方法に関する議論で馴染み深いはずです。その次は、新しい記法です: リスト17-4では、`components`というベクタを保持する`Screen`という名前の構造体を定義しています。 -このベクタの型は`Box`で、これはトレイトオブジェクトです; `Draw`トレイトを実装する`Box`内部の任意の型に対する代役です。 +このベクタの型は`Box`で、これはトレイトオブジェクトです; `Draw`トレイトを実装する`Box`内部の任意の型に対する代役です。 -`Button`の`width`、`height`、`label`フィールドは、`TextField`型のように、 -それらのフィールドプラス`placeholder`フィールドを代わりに持つ可能性のある他のコンポーネントのフィールドとは異なるでしょう。 +`Button`の`width`、`height`、`label`フィールドは、他のコンポーネントのフィールドとは異なるでしょう; +例えば`TextField`型は、それらと同じフィールドに加えて`placeholder`フィールドを持つかもしれません。 スクリーンに描画したい型のコンポーネントはそれぞれ`Draw`トレイトを実装しますが、 -`Button`がここでしているように、`draw`メソッドでは異なるコードを使用してその特定の型を描画する方法を定義しています(実際のGUIコードは、 -この章の範疇を超えるのでありませんが)。例えば、`Button`には、ユーザがボタンをクリックした時に起こることに関連するメソッドを含む、 +`Button`がここでしているように、`draw`メソッドでは異なるコードを使用してその特定の型を描画する方法を定義しています +(先にも書いた通り、実際のGUIコードはありませんが)。例えば、`Button`には、ユーザがボタンをクリックした時に起こることに関連するメソッドを含む、 追加の`impl`ブロックがある可能性があります。この種のメソッドは、`TextField`のような型には適用されません。 ライブラリを記述した時点では、誰かが`SelectBox`型を追加する可能性があるなんて知りませんでしたが、 -`Screen`の実装は、新しい型を処理し、描画することができました。何故なら、`SelectBox`は`Draw`型、 +`Screen`の実装は、新しい型を処理し、描画することができました。何故なら、`SelectBox`は`Draw`トレイト、 つまり、`draw`メソッドを実装しているからです。 この値の具体的な型ではなく、値が応答したメッセージにのみ関係するという概念は、 @@ -488,7 +400,7 @@ It doesn’t check whether a component is an instance of a `Button` or a アヒルに違いないのです!リスト17-5の`Screen`の`run`の実装では、`run`は、 各コンポーネントの実際の型がなんであるか知る必要はありません。コンポーネントが、 `Button`や`SelectBox`のインスタンスであるかを確認することはなく、コンポーネントの`draw`メソッドを呼び出すだけです。 -`components`ベクタで`Box`を値の型として指定することで、`Screen`を、 +`components`ベクタで`Box`を値の型として指定することで、`Screen`を、 `draw`メソッドを呼び出せる値を必要とするように定義できたのです。 > #### 注釈: ダックタイピングについて @@ -526,19 +438,8 @@ with a `String` as a component: ファイル名: src/main.rs -```rust,ignore -extern crate gui; -use gui::Screen; - -fn main() { - let screen = Screen { - components: vec![ - Box::new(String::from("Hi")), - ], - }; - - screen.run(); -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch17-oop/listing-17-10/src/main.rs}} ``` src/main.rs:7:13 - | - 7 | Box::new(String::from("Hi")), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait gui::Draw is not - implemented for `std::string::String` - | - = note: required for the cast to the object type `gui::Draw` +```console +{{#include ../listings/ch17-oop/listing-17-10/output.txt}} ``` - - @@ -585,19 +475,20 @@ didn’t mean to pass and we should pass a different type or we should implement ### トレイトオブジェクトは、ダイナミックディスパッチを行う -第10章の「ジェネリクスを使用したコードのパフォーマンス」節でジェネリクスに対してトレイト境界を使用した時に、 +第10章の[「ジェネリクスを使用したコードのパフォーマンス」][performance-of-code-using-generics]節でジェネリクスに対してトレイト境界を使用した時に、 コンパイラが行う単相化過程の議論を思い出してください: コンパイラは、関数やメソッドのジェネリックでない実装を、 ジェネリックな型引数の箇所に使用している具体的な型に対して生成するのでした。単相化の結果吐かれるコードは、 *スタティックディスパッチ*を行い、これは、コンパイル時にコンパイラがどのメソッドを呼び出しているかわかる時のことです。 @@ -606,141 +497,30 @@ method to call. トレイトオブジェクトを使用すると、コンパイラはダイナミックディスパッチを使用しなければなりません。 コンパイラは、トレイトオブジェクトを使用しているコードで使用される可能性のある型全てを把握しないので、 どの型に実装されたどのメソッドを呼び出すかわからないのです。代わりに実行時に、トレイトオブジェクト内でポインタを使用して、 -コンパイラは、どのメソッドを呼ぶか知ります。スタティックディスパッチでは行われないこの検索が起きる時には、 -実行時コストがあります。また、ダイナミックディスパッチは、コンパイラがメソッドのコードをインライン化することも妨げ、 +コンパイラは、どのメソッドを呼ぶか知ります。この検索は、スタティックディスパッチでは発生しない実行時コストを招きます。 +また、ダイナミックディスパッチは、コンパイラがメソッドのコードをインライン化することも妨げ、 そのため、ある種の最適化が不可能になります。ですが、リスト17-5で記述し、 リスト17-9ではサポートできたコードで追加の柔軟性を確かに得られたので、考慮すべき代償です。 - -### トレイトオブジェクトには、オブジェクト安全性が必要 - - -トレイトオブジェクトには、*オブジェクト安全*なトレイトしか作成できません。 -トレイトオブジェクトを安全にする特性全てを司る複雑な規則がありますが、実際には、2つの規則だけが関係があります。 -トレイトは、トレイト内で定義されているメソッド全てに以下の特性があれば、オブジェクト安全になります。 - - - -* 戻り値の型が`Self`でない。 -* ジェネリックな型引数がない。 - - - -`Self`キーワードは、トレイトやメソッドを実装しようとしている型の別名です。トレイトオブジェクトは、 -一旦、トレイトオブジェクトを使用したら、コンパイラにはそのトレイトを実装している具体的な型を知りようがないので、 -オブジェクト安全でなければなりません。トレイトメソッドが具体的な`Self`型を返すのに、 -トレイトオブジェクトが`Self`の具体的な型を忘れてしまったら、メソッドが元の具体的な型を使用できる手段はなくなってしまいます。 -同じことがトレイトを使用する時に具体的な型引数で埋められるジェネリックな型引数に対しても言えます: -具体的な型がトレイトを実装する型の一部になるのです。トレイトオブジェクトの使用を通して型が忘却されたら、 -そのジェネリックな型引数を埋める型がなんなのか知る術はないのです。 - - - -メソッドがオブジェクト安全でないトレイトの例は、標準ライブラリの`Clone`トレイトです。 -`Clone`トレイトの`clone`メソッドのシグニチャは以下のような感じです: - -```rust -pub trait Clone { - fn clone(&self) -> Self; -} -``` - - - -`String`型は`Clone`トレイトを実装していて、`String`のインスタンスに対して`clone`メソッドを呼び出すと、 -`String`のインスタンスが返ってきます。同様に、`Vec`のインスタンスに対して`clone`を呼び出すと、 -`Vec`のインスタンスが返ってきます。`clone`のシグニチャは、`Self`の代わりに入る型を知る必要があります。 -それが、戻り値の型になるからです。 - - - -コンパイラは、トレイトオブジェクトに関していつオブジェクト安全の規則を侵害するようなことを試みているかを示唆します。 -例えば、リスト17-4で`Screen`構造体を実装して`Draw`トレイトではなく、 -`Clone`トレイトを実装した型を保持しようとしたとしましょう。こんな感じで: - -```rust,ignore -pub struct Screen { - pub components: Vec>, -} -``` - - - -こんなエラーになるでしょう: - -```text -error[E0038]: the trait `std::clone::Clone` cannot be made into an object -(エラー: `std::clone::Clone`トレイトは、オブジェクトにすることはできません) - --> src/lib.rs:2:5 - | -2 | pub components: Vec>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` cannot be -made into an object - | - = note: the trait cannot require that `Self : Sized` - (注釈: このトレイトは、`Self : Sized`を満たせません) -``` - - - -このエラーは、このようにこのトレイトをトレイトオブジェクトとして使用することはできないことを意味しています。 -オブジェクト安全性についての詳細に興味があるのなら、[Rust RFC 255]を参照されたし。 - -[Rust RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md +[performance-of-code-using-generics]: +ch10-01-syntax.html#ジェネリクスを使用したコードのパフォーマンス +[dynamically-sized]: ch19-04-advanced-types.html#動的サイズ決定型とsizedトレイト diff --git a/src/ch17-03-oo-design-patterns.md b/src/ch17-03-oo-design-patterns.md index e0f13ddbc..139bec16d 100644 --- a/src/ch17-03-oo-design-patterns.md +++ b/src/ch17-03-oo-design-patterns.md @@ -6,48 +6,66 @@ - -ステートパターンは、オブジェクト指向デザインパターンの1つです。このパターンの肝は、 -値が一連の*ステートオブジェクト*で表されるなんらかの内部状態を持ち、 -その内部の状態に基づいて値の振る舞いが変化するというものです。ステートオブジェクトは、 -機能を共有します: Rustでは、もちろん、オブジェクトと継承ではなく、構造体とトレイトを使用します。 +pattern is that we define a set of states a value can have internally. The +states are represented by a set of *state objects*, and the value’s behavior +changes based on its state. We’re going to work through an example of a blog +post struct that has a field to hold its state, which will be a state object +from the set "draft", "review", or "published". +--> + +ステートパターンは、オブジェクト指向デザインパターンの1つです。 +このパターンの肝は、値が内部的に持つことができる状態の集合を定義するということです。 +状態は*ステートオブジェクト*の集合として表現され、その状態に基づいて値の振る舞いが変化します。 +ここでは、自身の状態を保持するフィールドを持つ、ブログ記事構造体の例に取り組んでいきます。 +この構造体のフィールドは「草稿」、「査読」、「公開済み」からなる集合のうちのいずれかの状態オブジェクトになるでしょう。 + + + +ステートオブジェクトは機能を共有します: Rustでは、もちろん、オブジェクトと継承ではなく、構造体とトレイトを使用します。 各ステートオブジェクトは、自身の振る舞いと別の状態に変化すべき時を司ることに責任を持ちます。 ステートオブジェクトを保持する値は、状態ごとの異なる振る舞いや、いつ状態が移行するかについては何も知りません。 -ステートパターンを使用することは、プログラムの業務要件が変わる時、状態を保持する値のコードや、 -値を使用するコードを変更する必要はないことを意味します。ステートオブジェクトの1つのコードを更新して、 +ステートパターンを使用することの利点は、プログラムの業務要件が変わる時、状態を保持する値のコードや、 +値を使用するコードを変更する必要がない点です。ステートオブジェクトの1つのコードを更新して、 規則を変更したり、あるいはおそらくステートオブジェクトを追加する必要しかないのです。 -ステートデザインパターンの例と、そのRustでの使用方法を見ましょう。 -ブログ記事のワークフローを少しずつ実装していきます。ブログの最終的な機能は以下のような感じになるでしょう: +まずは、より伝統的なオブジェクト指向の手法でステートパターンを実装し、 +その後、Rustとしてもう少し自然なアプローチを使用します。 +それでは、ステートパターンを利用したブログ記事のワークフローの漸進的な実装に取り組んでいきましょう。 + + + +最終的な機能は以下のような感じになるでしょう: 1. ブログ記事は、空の草稿から始まる。 @@ -67,11 +85,11 @@ should remain an unpublished draft. リスト17-11は、このワークフローをコードの形で示しています: これは、 -`blog`というライブラリクレートに実装するAPIの使用例です。まだ`blog`クレートを実装していないので、 +`blog`というライブラリクレートに実装するAPIの使用例です。`blog`クレートを実装していないので、 コンパイルはできません。 -ユーザが`Post::new`で新しいブログ記事の草稿を作成できるようにしたいです。それから、 -草稿状態の間にブログ記事にテキストを追加できるようにしたいです。承認前に記事の内容を即座に得ようとしたら、 -記事はまだ草稿なので、何も起きるべきではありません。デモ目的でコードに`assert_eq!`を追加しました。 +ユーザが`Post::new`で新しいブログ記事の草稿を作成できるようにしたいです。 +ブログ記事にテキストを追加できるようにしたいです。承認前に記事の内容を即座に得ようとしたら、 +記事はまだ草稿なので、何のテキストも得られるべきではありません。デモ目的でコードに`assert_eq!`を追加しました。 これに対する素晴らしい単体テストは、ブログ記事の草稿が`content`メソッドから空の文字列を返すことをアサートすることでしょうが、 この例に対してテストを書くつもりはありません。 @@ -161,42 +164,32 @@ Let’s get started on the implementation of the library! We know we need a public `Post` struct that holds some content, so we’ll start with the definition of the struct and an associated public `new` function to create an instance of `Post`, as shown in Listing 17-12. We’ll also make a private -`State` trait. Then `Post` will hold a trait object of `Box` inside an -`Option` in a private field named `state`. You’ll see why the `Option` is -necessary in a bit. +`State` trait that will define the behavior that all state objects for a `Post` +must have. --> ライブラリの実装に取り掛かりましょう!なんらかの内容を保持する公開の`Post`構造体が必要なことはわかるので、 構造体の定義と、関連する公開の`Post`インスタンスを生成する`new`関数から始めましょう。リスト17-12のようにですね。 -また、非公開の`State`トレイトも作成します。それから、`Post`は`state`という非公開のフィールドに、 -`Option`で`Box`のトレイトオブジェクトを保持します。`Option`が必要な理由はすぐわかります。 +また、`Post`のすべての状態オブジェクトが持たなくてはならない振る舞いを定義する、 +非公開の`State`トレイトも作成します。 -ファイル名: src/lib.rs - -```rust -pub struct Post { - state: Option>, - content: String, -} - -impl Post { - pub fn new() -> Post { - Post { - state: Some(Box::new(Draft {})), - content: String::new(), - } - } -} +それから`Post`は、状態オブジェクトを保持するための`state`という非公開のフィールドに、 +`Option`で`Box`のトレイトオブジェクトを保持します。`Option`が必要な理由はすぐわかります。 -trait State {} + -struct Draft {} +ファイル名: src/lib.rs -impl State for Draft {} +```rust,noplayground +{{#rustdoc_include ../listings/ch17-oop/listing-17-12/src/lib.rs}} ``` -`State`トレイトは、異なる記事の状態で共有される振る舞いを定義し、`Draft`、`PendingReview`、`Published`状態は全て、 -`State`トレイトを実装します。今は、トレイトにメソッドは何もなく、`Draft`が記事の初期状態にしたい状態なので、 +`State`トレイトは、異なる記事の状態で共有される振る舞いを定義します。状態オブジェクトは`Draft`、`PendingReview`、`Published`で、 +これらはすべて`State`トレイトを実装します。今は、トレイトにメソッドは何もなく、`Draft`が記事の初期状態にしたい状態なので、 その状態だけを定義することから始めます。 新しい`Post`を作る時、`state`フィールドは、`Box`を保持する`Some`値にセットします。 @@ -240,18 +234,18 @@ create a `Post` in any other state! In the `Post::new` function, we set the ### 記事の内容のテキストを格納する -リスト17-11は、`add_text`というメソッドを呼び出し、ブログ記事のテキスト内容に追加される`&str`を渡せるようになりたいことを示しました。 -これを`content`フィールドを`pub`にして晒すのではなく、メソッドとして実装しています。 -これは、後ほど`content`フィールドデータの読まれ方を制御するメソッドを実装できることを意味しています。 +リスト17-11で、`add_text`というメソッドを呼び出し、ブログ記事のテキスト内容として追加される`&str`を渡せるようになりたいことを確認しました。 +後ほど`content`フィールドデータの読まれ方を制御するメソッドを実装できるように、 +`content`フィールドを`pub`にして晒すのではなく、これをメソッドとして実装しています。 `add_text`メソッドは非常に素直なので、リスト17-13の実装を`impl Post`ブロックに追加しましょう: -この追加された`content`メソッドとともに、リスト17-11の8行目までのコードは、想定通り動きます。 +この追加された`content`メソッドとともに、リスト17-11の7行目までのコードは、想定通り動きます。 -`State`トレイトに`request_review`メソッドを追加しました; このトレイトを実装する型は全て、 +`State`トレイトに`request_review`メソッドを追加します; このトレイトを実装する型は全て、 これで`request_review`メソッドを実装する必要があります。メソッドの第1引数に`self`、`&self`、`&mut self`ではなく、 `self: Box`としていることに注意してください。この記法は、型を保持する`Box`に対して呼ばれた時のみ、 このメソッドが合法になることを意味しています。この記法は、`Box`の所有権を奪い、古い状態を無効化するので、 @@ -475,15 +419,15 @@ we’ve transformed it into a new state. `Post`が古い`state`値を使えないことが保証されるのです。 -`Draft`の`request_review`メソッドは、新しい`PendingReview`構造体の新しいボックスのインスタンスを返す必要があり、 +`Draft`の`request_review`メソッドは、新しい`PendingReview`構造体の新しいボックスのインスタンスを返し、 これが、記事が査読待ちの時の状態を表します。`PendingReview`構造体も`request_review`メソッドを実装しますが、 何も変形はしません。むしろ、自身を返します。というのも、既に`PendingReview`状態にある記事の査読を要求したら、 `PendingReview`状態に留まるべきだからです。 @@ -501,18 +445,23 @@ state is responsible for its own rules. We’ll leave the `content` method on `Post` as is, returning an empty string slice. We can now have a `Post` in the `PendingReview` state as well as in the `Draft` state, but we want the same behavior in the `PendingReview` state. -Listing 17-11 now works up to line 11! +Listing 17-11 now works up to line 10! --> `Post`の`content`メソッドを空の文字列スライスを返してそのままにします。 これで`Post`は`PendingReview`と`Draft`状態になり得ますが、`PendingReview`状態でも、 -同じ振る舞いが欲しいです。もうリスト17-11は11行目まで動くようになりました! +同じ振る舞いが欲しいです。もうリスト17-11は10行目まで動くようになりました! + + + -### `content`の振る舞いを変化させる`approve`メソッドを追加する +### `content`の振る舞いを変化させる`approve`を追加する -`request_review`のように、`Draft`に対して`approve`メソッドを呼び出したら、`self`を返すので、 +`PendingReview`に対して`request_review`が行っているのと同様に、 +`Draft`に対して`approve`メソッドを呼び出しても、`approve`は`self`を返すので、 何も効果はありません。`PendingReview`に対して`approve`を呼び出すと、 `Published`構造体の新しいボックス化されたインスタンスを返します。`Published`構造体は`State`トレイトを実装し、 `request_review`メソッドと`approve`メソッド両方に対して、自身を返します。 そのような場合に記事は、`Published`状態に留まるべきだからです。 -さて、`Post`の`content`メソッドを更新する必要が出てきました: 状態が`Published`なら、 -記事の`content`フィールドの値を返したいのです; それ以外なら、空の文字列スライスを返したいです。 +さて、`Post`の`content`メソッドを更新する必要が出てきました。 +`content`から返される値を`Post`の現在の状態に依存するようにしたいので、 +`Post`は、その`state`に定義された`content`メソッドに委譲するようにします。 リスト17-17のようにですね: @@ -671,39 +555,40 @@ returned from using the `content` method on the `state` value. `Option`に対して`as_ref`メソッドを呼び出します。値の所有権ではなく、`Option`内部の値への参照が欲しいからです。 -`state`は`Option>`なので、`as_ref`を呼び出すと、`Option<&Box>`が返ってきます。 +`state`は`Option>`なので、`as_ref`を呼び出すと、`Option<&Box>`が返ってきます。 `as_ref`を呼ばなければ、`state`を関数引数の借用した`&self`からムーブできないので、エラーになるでしょう。 さらに`unwrap`メソッドを呼び出し、これは絶対にパニックしないことがわかっています。何故なら、 `Post`のメソッドが、それらのメソッドが完了した際に`state`は常に`Some`値を含んでいることを保証するからです。 これは、コンパイラには理解不能であるものの、 -`None`値が絶対にあり得ないとわかる第9章の「コンパイラよりも情報を握っている場合」節で語った一例です。 +`None`値が絶対にあり得ないとわかる第9章の[「コンパイラよりもプログラマがより情報を持っている場合」][more-info-than-rustc]節で語った一例です。 -この時点で、`&Box`に対して`content`を呼び出すと、参照外し型強制が`&`と`Box`に働くので、 +この時点で、`&Box`に対して`content`を呼び出すと、参照外し型強制が`&`と`Box`に働くので、 究極的に`content`メソッドが`State`トレイトを実装する型に対して呼び出されることになります。 つまり、`content`を`State`トレイト定義に追加する必要があり、そこが現在の状態に応じてどの内容を返すべきかというロジックを配置する場所です。 リスト17-18のようにですね: @@ -714,26 +599,8 @@ Listing 17-18: ファイル名: src/lib.rs -```rust -# pub struct Post { -# content: String -# } -trait State { - // --snip-- - fn content<'a>(&self, post: &'a Post) -> &'a str { - "" - } -} - -// --snip-- -struct Published {} - -impl State for Published { - // --snip-- - fn content<'a>(&self, post: &'a Post) -> &'a str { - &post.content - } -} +```rust,noplayground +{{#rustdoc_include ../listings/ch17-oop/listing-17-18/src/lib.rs:here}} ``` + +> #### enumを使えばいいのでは? +> +> 可能な記事の状態を列挙子とする`enum`を使わなかったのはなぜか、疑問に感じているかもしれません。 +> それももちろんあり得る解決策です。試してみて、どちらが好みか、最終結果を比較してみてください! +> enumを使うことの不利な点のひとつは、enumの値をチェックするすべての場所で、 +> `match`式か、それに類似する、すべての可能な列挙子を処理するための方法が必要になるだろうということです。 +> これは、トレイトオブジェクトを使用する解決策と比較して、より煩わしくなることがあります。 + + @@ -799,7 +686,7 @@ Rustにあることを示してきました。`Post`のメソッドは、種々 `Published`構造体の`State`トレイトの実装です。 @@ -838,11 +725,11 @@ pattern, try a few of these suggestions: * 記事の状態を`PendingReview`から`Draft`に戻す`reject`メソッドを追加する。 @@ -887,12 +774,13 @@ and `approve` methods on `Post`. Both methods delegate to the implementation of the same method on the value in the `state` field of `Option` and set the new value of the `state` field to the result. If we had a lot of methods on `Post` that followed this pattern, we might consider defining a macro to eliminate the -repetition (see Appendix D for more on Macros). +repetition (see the [“Macros”][macros] section in Chapter 19). --> 他の重複には、`Post`の`request_review`と`approve`メソッドの実装が似ていることが含まれます。 両メソッドは`Option`の`state`の値に対する同じメソッドの実装に委譲していて、`state`フィールドの新しい値を結果にセットします。 -このパターンに従う`Post`のメソッドが多くあれば、マクロを定義して繰り返しを排除することも考慮する可能性があります(マクロについては付録Dを参照)。 +このパターンに従う`Post`のメソッドが多くあれば、マクロを定義して繰り返しを排除することも考慮する可能性があります +(第19章の[「マクロ」][macros]節を参照)。 @@ -1157,20 +988,7 @@ The updated code in `main` is shown in Listing 17-21: ファイル名: src/main.rs ```rust,ignore -extern crate blog; -use blog::Post; - -fn main() { - let mut post = Post::new(); - - post.add_text("I ate a salad for lunch today"); - - let post = post.request_review(); - - let post = post.approve(); - - assert_eq!("I ate a salad for lunch today", post.content()); -} +{{#rustdoc_include ../listings/ch17-oop/listing-17-21/src/main.rs}} ``` -`blog`クレートに関してこの節の冒頭で触れた追加の要求に提言される作業をそのままリスト17-20の後に試してみて、 +`blog`クレートに関してこの節の冒頭で提言される作業をそのままリスト17-21の後に試してみて、 このバージョンのコードについてどう思うか確かめてください。この設計では、 既に作業の一部が達成されている可能性があることに注意してください。 @@ -1262,3 +1080,11 @@ haven’t seen their full capability yet. Let’s go! 次は、パターンを見ます。パターンも多くの柔軟性を可能にするRustの別の機能です。 本全体を通して僅かに見かけましたが、まだその全能力は目の当たりにしていません。さあ、行きましょう! + + + +[more-info-than-rustc]: ch09-03-to-panic-or-not-to-panic.html#コンパイラよりもプログラマがより情報を持っている場合 +[macros]: ch19-06-macros.html#マクロ From 3c459bbb94c22247ee75f0d756c6a22f00375e4d Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:08 +0900 Subject: [PATCH 19/22] =?UTF-8?q?ch18=20=E3=83=91=E3=82=BF=E3=83=BC?= =?UTF-8?q?=E3=83=B3=E3=81=A8=E3=83=9E=E3=83=83=E3=83=81=E3=83=B3=E3=82=B0?= =?UTF-8?q?=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88?= =?UTF-8?q?=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-18-01/Cargo.toml | 3 +- .../listing-18-01/src/main.rs | 7 +- .../listing-18-02/Cargo.toml | 3 +- .../listing-18-03/Cargo.toml | 3 +- .../listing-18-04/Cargo.toml | 3 +- .../listing-18-05/Cargo.toml | 3 +- .../listing-18-05/output.txt | 12 +- .../listing-18-06/Cargo.toml | 3 +- .../listing-18-07/Cargo.toml | 3 +- .../listing-18-07/src/main.rs | 1 + .../listing-18-08/Cargo.toml | 3 +- .../listing-18-08/output.txt | 21 +- .../listing-18-09/Cargo.toml | 3 +- .../listing-18-10/Cargo.toml | 3 +- .../listing-18-10/output.txt | 17 +- .../listing-18-11/Cargo.toml | 3 +- .../listing-18-11/src/main.rs | 8 +- .../listing-18-12/Cargo.toml | 3 +- .../listing-18-13/Cargo.toml | 3 +- .../listing-18-14/Cargo.toml | 3 +- .../listing-18-14/src/main.rs | 11 +- .../listing-18-15/Cargo.toml | 3 +- .../listing-18-15/src/main.rs | 22 +- .../listing-18-16/Cargo.toml | 3 +- .../listing-18-16/src/main.rs | 16 +- .../listing-18-17/Cargo.toml | 3 +- .../listing-18-17/src/main.rs | 1 + .../listing-18-18/Cargo.toml | 3 +- .../listing-18-18/src/main.rs | 2 + .../listing-18-19/Cargo.toml | 3 +- .../listing-18-19/src/main.rs | 3 +- .../listing-18-20/Cargo.toml | 3 +- .../listing-18-21/Cargo.toml | 3 +- .../listing-18-21/src/main.rs | 2 + .../listing-18-22/Cargo.toml | 3 +- .../listing-18-23/Cargo.toml | 3 +- .../listing-18-24/Cargo.toml | 3 +- .../listing-18-24/src/main.rs | 2 +- .../listing-18-25/Cargo.toml | 3 +- .../listing-18-25/output.txt | 7 +- .../listing-18-26/Cargo.toml | 3 +- .../listing-18-26/src/main.rs | 6 +- .../listing-18-27/Cargo.toml | 3 +- .../listing-18-27/src/main.rs | 4 +- .../listing-18-28/Cargo.toml | 3 +- .../listing-18-28/src/main.rs | 2 + .../listing-18-29/Cargo.toml | 3 +- .../listing-18-29/src/main.rs | 3 + .../no-listing-01-literals/Cargo.toml | 3 +- .../no-listing-01-literals/src/main.rs | 8 +- .../Cargo.toml | 3 +- .../src/main.rs | 3 + .../no-listing-03-ranges/Cargo.toml | 3 +- .../no-listing-03-ranges/src/main.rs | 2 + .../no-listing-04-ranges-of-char/Cargo.toml | 3 +- .../no-listing-04-ranges-of-char/src/main.rs | 3 + .../Cargo.toml | 3 +- src/ch18-00-patterns.md | 17 +- src/ch18-01-all-the-places-for-patterns.md | 228 ++--- src/ch18-02-refutability.md | 67 +- src/ch18-03-pattern-syntax.md | 851 +++++------------- 61 files changed, 478 insertions(+), 950 deletions(-) diff --git a/listings/ch18-patterns-and-matching/listing-18-01/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-01/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-01/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-01/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-01/src/main.rs index d28c369f5..b47c69880 100644 --- a/listings/ch18-patterns-and-matching/listing-18-01/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-01/src/main.rs @@ -4,16 +4,21 @@ fn main() { let age: Result = "34".parse(); if let Some(color) = favorite_color { - println!("Using your favorite color, {}, as the background", color); + // "あなたのお気に入りの色、{color}を背景色に使用します" + println!("Using your favorite color, {color}, as the background"); } else if is_tuesday { + // "火曜日は緑の日!" println!("Tuesday is green day!"); } else if let Ok(age) = age { if age > 30 { + // "紫を背景色に使用します" println!("Using purple as the background color"); } else { + // "オレンジを背景色に使用します" println!("Using orange as the background color"); } } else { + // "青を背景色に使用します" println!("Using blue as the background color"); } } diff --git a/listings/ch18-patterns-and-matching/listing-18-02/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-02/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-02/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-03/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-03/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-03/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-04/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-04/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-04/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-05/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-05/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-05/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-05/output.txt b/listings/ch18-patterns-and-matching/listing-18-05/output.txt index eae835e37..98d819f2c 100644 --- a/listings/ch18-patterns-and-matching/listing-18-05/output.txt +++ b/listings/ch18-patterns-and-matching/listing-18-05/output.txt @@ -4,14 +4,14 @@ error[E0308]: mismatched types --> src/main.rs:2:9 | 2 | let (x, y) = (1, 2, 3); - | ^^^^^^ expected a tuple with 3 elements, found one with 2 elements + | ^^^^^^ --------- this expression has type `({integer}, {integer}, {integer})` + | | (この式は型`({integer}, {integer}, {integer})`を持ちます) + | | + | expected a tuple with 3 elements, found one with 2 elements + | (3要素のタプルを予期したのに、2要素のタプルが見つかりました) | = note: expected tuple `({integer}, {integer}, {integer})` found tuple `(_, _)` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `patterns`. - -To learn more, run the command again with --verbose. +error: could not compile `patterns` (bin "patterns") due to 1 previous error diff --git a/listings/ch18-patterns-and-matching/listing-18-06/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-06/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-06/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-07/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-07/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-07/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-07/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-07/src/main.rs index 4eccb8088..d63e3a32e 100644 --- a/listings/ch18-patterns-and-matching/listing-18-07/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-07/src/main.rs @@ -1,4 +1,5 @@ fn print_coordinates(&(x, y): &(i32, i32)) { + // "現在の位置: ({}, {})" println!("Current location: ({}, {})", x, y); } diff --git a/listings/ch18-patterns-and-matching/listing-18-08/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-08/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-08/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-08/output.txt b/listings/ch18-patterns-and-matching/listing-18-08/output.txt index 551250ff8..e39cb9419 100644 --- a/listings/ch18-patterns-and-matching/listing-18-08/output.txt +++ b/listings/ch18-patterns-and-matching/listing-18-08/output.txt @@ -1,21 +1,24 @@ $ cargo run Compiling patterns v0.1.0 (file:///projects/patterns) -error[E0005]: refutable pattern in local binding: `None` not covered +error[E0005]: refutable pattern in local binding +(エラー: ローカル束縛に論駁可能なパターン) --> src/main.rs:3:9 | 3 | let Some(x) = some_option_value; | ^^^^^^^ pattern `None` not covered + | (パターン`None`がカバーされていません) | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + (注釈: `let`束縛は`struct`や単一の列挙子を持つ`enum`などの「論駁不可能なパターン」を必要とします) = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -help: you might want to use `if let` to ignore the variant that isn't matched + (注釈: さらなる情報についてはhttps://doc.rust-lang.org/book/ch18-02-refutability.htmlを確認してください) + = note: the matched value is of type `Option` + (注釈: マッチ対象の値は`Option`型を持ちます) +help: you might want to use `let else` to handle the variant that isn't matched +(ヘルプ: マッチしない列挙子を処理するために`let else`を使用するといいかもしれません) | -3 | if let Some(x) = some_option_value { /* */ } - | - -error: aborting due to previous error +3 | let Some(x) = some_option_value else { todo!() }; + | ++++++++++++++++ For more information about this error, try `rustc --explain E0005`. -error: could not compile `patterns`. - -To learn more, run the command again with --verbose. +error: could not compile `patterns` (bin "patterns") due to 1 previous error diff --git a/listings/ch18-patterns-and-matching/listing-18-09/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-09/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-09/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-10/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-10/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-10/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-10/output.txt b/listings/ch18-patterns-and-matching/listing-18-10/output.txt index 8b72e1813..c615a81ac 100644 --- a/listings/ch18-patterns-and-matching/listing-18-10/output.txt +++ b/listings/ch18-patterns-and-matching/listing-18-10/output.txt @@ -1,15 +1,20 @@ $ cargo run Compiling patterns v0.1.0 (file:///projects/patterns) -warning: irrefutable if-let pattern - --> src/main.rs:2:5 +warning: irrefutable `if let` pattern +(警告: 論駁不可能な`if let`パターン) + --> src/main.rs:2:8 | -2 | / if let x = 5 { -3 | | println!("{}", x); -4 | | }; - | |_____^ +2 | if let x = 5 { + | ^^^^^^^^^ | + = note: this pattern will always match, so the `if let` is useless + (注釈: このパターンは常にマッチするので`if let`は無意味です) + = help: consider replacing the `if let` with a `let` + (ヘルプ: `if let`を`let`で置き換えることを検討してください) = note: `#[warn(irrefutable_let_patterns)]` on by default + (注釈: `#[warn(irrefutable_let_patterns)]`はデフォルトでオンです) +warning: `patterns` (bin "patterns") generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 0.39s Running `target/debug/patterns` 5 diff --git a/listings/ch18-patterns-and-matching/listing-18-11/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-11/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-11/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-11/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-11/src/main.rs index 25eaa79ff..e7c709b9b 100644 --- a/listings/ch18-patterns-and-matching/listing-18-11/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-11/src/main.rs @@ -4,11 +4,15 @@ fn main() { let y = 10; match x { + // 50だったよ Some(50) => println!("Got 50"), - Some(y) => println!("Matched, y = {:?}", y), + // マッチしたよ、y = {y} + Some(y) => println!("Matched, y = {y}"), + // 既定のケース、x = {:?} _ => println!("Default case, x = {:?}", x), } - println!("at the end: x = {:?}, y = {:?}", x, y); + // 最後には: x = {:?}, y = {y} + println!("at the end: x = {:?}, y = {y}", x); // ANCHOR_END: here } diff --git a/listings/ch18-patterns-and-matching/listing-18-12/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-12/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-12/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-13/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-13/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-13/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-14/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-14/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-14/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-14/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-14/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-14/src/main.rs index 8d445d9b9..67305a2b6 100644 --- a/listings/ch18-patterns-and-matching/listing-18-14/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-14/src/main.rs @@ -8,9 +8,14 @@ fn main() { let p = Point { x: 0, y: 7 }; match p { - Point { x, y: 0 } => println!("On the x axis at {}", x), - Point { x: 0, y } => println!("On the y axis at {}", y), - Point { x, y } => println!("On neither axis: ({}, {})", x, y), + // x軸上の{x} + Point { x, y: 0 } => println!("On the x axis at {x}"), + // y軸上の{y} + Point { x: 0, y } => println!("On the y axis at {y}"), + // どちらの軸上でもない: ({x}, {y}) + Point { x, y } => { + println!("On neither axis: ({x}, {y})"); + } } } // ANCHOR_END: here diff --git a/listings/ch18-patterns-and-matching/listing-18-15/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-15/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-15/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-15/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-15/src/main.rs index 9b8dac193..5104389e8 100644 --- a/listings/ch18-patterns-and-matching/listing-18-15/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-15/src/main.rs @@ -10,18 +10,20 @@ fn main() { match msg { Message::Quit => { - println!("The Quit variant has no data to destructure.") + // Quit列挙子には分配すべきデータがない + println!("The Quit variant has no data to destructure."); } Message::Move { x, y } => { - println!( - "Move in the x direction {} and in the y direction {}", - x, y - ); + // x方向に{x}、y方向に{y}だけ動く + println!("Move in the x direction {x} and in the y direction {y}"); + } + Message::Write(text) => { + // テキストメッセージ: {text} + println!("Text message: {text}"); + } + Message::ChangeColor(r, g, b) => { + // 色を赤{r}, 緑{g}, 青{b}に変更 + println!("Change the color to red {r}, green {g}, and blue {b}",) } - Message::Write(text) => println!("Text message: {}", text), - Message::ChangeColor(r, g, b) => println!( - "Change the color to red {}, green {}, and blue {}", - r, g, b - ), } } diff --git a/listings/ch18-patterns-and-matching/listing-18-16/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-16/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-16/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-16/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-16/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-16/src/main.rs index ed6a20bf4..b712c280c 100644 --- a/listings/ch18-patterns-and-matching/listing-18-16/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-16/src/main.rs @@ -14,14 +14,14 @@ fn main() { let msg = Message::ChangeColor(Color::Hsv(0, 160, 255)); match msg { - Message::ChangeColor(Color::Rgb(r, g, b)) => println!( - "Change the color to red {}, green {}, and blue {}", - r, g, b - ), - Message::ChangeColor(Color::Hsv(h, s, v)) => println!( - "Change the color to hue {}, saturation {}, and value {}", - h, s, v - ), + Message::ChangeColor(Color::Rgb(r, g, b)) => { + // 色を赤{r}, 緑{g}, 青{b}に変更 + println!("Change color to red {r}, green {g}, and blue {b}"); + } + Message::ChangeColor(Color::Hsv(h, s, v)) => { + // 色を色相{h}, 彩度{s}, 明度{v}に変更 + println!("Change color to hue {h}, saturation {s}, value {v}") + } _ => (), } } diff --git a/listings/ch18-patterns-and-matching/listing-18-17/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-17/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-17/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-17/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-17/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-17/src/main.rs index cf1fbe072..ffdbd7dc1 100644 --- a/listings/ch18-patterns-and-matching/listing-18-17/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-17/src/main.rs @@ -1,4 +1,5 @@ fn foo(_: i32, y: i32) { + // このコードは、y引数を使うだけです: {} println!("This code only uses the y parameter: {}", y); } diff --git a/listings/ch18-patterns-and-matching/listing-18-18/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-18/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-18/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-18/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-18/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-18/src/main.rs index b776c64c4..3319914b4 100644 --- a/listings/ch18-patterns-and-matching/listing-18-18/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-18/src/main.rs @@ -5,6 +5,7 @@ fn main() { match (setting_value, new_setting_value) { (Some(_), Some(_)) => { + // 既存の値の変更を上書きできません println!("Can't overwrite an existing customized value"); } _ => { @@ -12,6 +13,7 @@ fn main() { } } + // 設定は{:?}です println!("setting is {:?}", setting_value); // ANCHOR_END: here } diff --git a/listings/ch18-patterns-and-matching/listing-18-19/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-19/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-19/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-19/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-19/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-19/src/main.rs index 59b48c94d..b18571e05 100644 --- a/listings/ch18-patterns-and-matching/listing-18-19/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-19/src/main.rs @@ -4,7 +4,8 @@ fn main() { match numbers { (first, _, third, _, fifth) => { - println!("Some numbers: {}, {}, {}", first, third, fifth) + // 何らかの数値: {first}, {third}, {fifth} + println!("Some numbers: {first}, {third}, {fifth}") } } // ANCHOR_END: here diff --git a/listings/ch18-patterns-and-matching/listing-18-20/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-20/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-20/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-20/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-21/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-21/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-21/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-21/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-21/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-21/src/main.rs index 980610503..c0bf56e64 100644 --- a/listings/ch18-patterns-and-matching/listing-18-21/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-21/src/main.rs @@ -1,8 +1,10 @@ fn main() { // ANCHOR: here + // こんにちは! let s = Some(String::from("Hello!")); if let Some(_s) = s { + // 文字列が見つかりました println!("found a string"); } diff --git a/listings/ch18-patterns-and-matching/listing-18-22/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-22/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-22/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-22/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-23/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-23/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-23/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-23/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-24/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-24/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-24/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-24/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-24/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-24/src/main.rs index f22dbe8ed..3f9aaafc2 100644 --- a/listings/ch18-patterns-and-matching/listing-18-24/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-24/src/main.rs @@ -3,7 +3,7 @@ fn main() { match numbers { (first, .., last) => { - println!("Some numbers: {}, {}", first, last); + println!("Some numbers: {first}, {last}"); } } } diff --git a/listings/ch18-patterns-and-matching/listing-18-25/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-25/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-25/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-25/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-25/output.txt b/listings/ch18-patterns-and-matching/listing-18-25/output.txt index 3044c4b30..bcca79660 100644 --- a/listings/ch18-patterns-and-matching/listing-18-25/output.txt +++ b/listings/ch18-patterns-and-matching/listing-18-25/output.txt @@ -1,6 +1,7 @@ $ cargo run Compiling patterns v0.1.0 (file:///projects/patterns) error: `..` can only be used once per tuple pattern +(エラー: `..`は、タプルパターン1つにつき、1回しか使用できません) --> src/main.rs:5:22 | 5 | (.., second, ..) => { @@ -8,8 +9,4 @@ error: `..` can only be used once per tuple pattern | | | previously used here -error: aborting due to previous error - -error: could not compile `patterns`. - -To learn more, run the command again with --verbose. +error: could not compile `patterns` (bin "patterns") due to 1 previous error diff --git a/listings/ch18-patterns-and-matching/listing-18-26/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-26/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-26/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-26/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-26/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-26/src/main.rs index 4ec86cba7..f2e7d5a55 100644 --- a/listings/ch18-patterns-and-matching/listing-18-26/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-26/src/main.rs @@ -3,8 +3,10 @@ fn main() { let num = Some(4); match num { - Some(x) if x < 5 => println!("less than five: {}", x), - Some(x) => println!("{}", x), + // 数{}は偶数です + Some(x) if x % 2 == 0 => println!("The number {} is even", x), + // 数{}は奇数です + Some(x) => println!("The number {} is odd", x), None => (), } // ANCHOR_END: here diff --git a/listings/ch18-patterns-and-matching/listing-18-27/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-27/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-27/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-27/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-27/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-27/src/main.rs index 348e36723..8386a0ab8 100644 --- a/listings/ch18-patterns-and-matching/listing-18-27/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-27/src/main.rs @@ -4,9 +4,9 @@ fn main() { match x { Some(50) => println!("Got 50"), - Some(n) if n == y => println!("Matched, n = {}", n), + Some(n) if n == y => println!("Matched, n = {n}"), _ => println!("Default case, x = {:?}", x), } - println!("at the end: x = {:?}, y = {}", x, y); + println!("at the end: x = {:?}, y = {y}", x); } diff --git a/listings/ch18-patterns-and-matching/listing-18-28/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-28/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-28/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-28/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-28/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-28/src/main.rs index 15804553f..e51f40dd9 100644 --- a/listings/ch18-patterns-and-matching/listing-18-28/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-28/src/main.rs @@ -4,7 +4,9 @@ fn main() { let y = false; match x { + // はい 4 | 5 | 6 if y => println!("yes"), + // いいえ _ => println!("no"), } // ANCHOR_END: here diff --git a/listings/ch18-patterns-and-matching/listing-18-29/Cargo.toml b/listings/ch18-patterns-and-matching/listing-18-29/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/listing-18-29/Cargo.toml +++ b/listings/ch18-patterns-and-matching/listing-18-29/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/listing-18-29/src/main.rs b/listings/ch18-patterns-and-matching/listing-18-29/src/main.rs index 3514deb63..6398aebb4 100644 --- a/listings/ch18-patterns-and-matching/listing-18-29/src/main.rs +++ b/listings/ch18-patterns-and-matching/listing-18-29/src/main.rs @@ -7,12 +7,15 @@ fn main() { let msg = Message::Hello { id: 5 }; match msg { + // 範囲内のidが見つかりました: {} Message::Hello { id: id_variable @ 3..=7, } => println!("Found an id in range: {}", id_variable), + // 別の範囲内のidが見つかりました Message::Hello { id: 10..=12 } => { println!("Found an id in another range") } + // それ以外のidが見つかりました Message::Hello { id } => println!("Found some other id: {}", id), } // ANCHOR_END: here diff --git a/listings/ch18-patterns-and-matching/no-listing-01-literals/Cargo.toml b/listings/ch18-patterns-and-matching/no-listing-01-literals/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/no-listing-01-literals/Cargo.toml +++ b/listings/ch18-patterns-and-matching/no-listing-01-literals/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/no-listing-01-literals/src/main.rs b/listings/ch18-patterns-and-matching/no-listing-01-literals/src/main.rs index 7978e1ade..c383df848 100644 --- a/listings/ch18-patterns-and-matching/no-listing-01-literals/src/main.rs +++ b/listings/ch18-patterns-and-matching/no-listing-01-literals/src/main.rs @@ -3,10 +3,10 @@ fn main() { let x = 1; match x { - 1 => println!("one"), - 2 => println!("two"), - 3 => println!("three"), - _ => println!("anything"), + 1 => println!("one"), // 1 + 2 => println!("two"), // 2 + 3 => println!("three"), // 3 + _ => println!("anything"), // なにか } // ANCHOR_END: here } diff --git a/listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/Cargo.toml b/listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/Cargo.toml +++ b/listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/src/main.rs b/listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/src/main.rs index e52d815d8..3a7e798cf 100644 --- a/listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/src/main.rs +++ b/listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/src/main.rs @@ -3,8 +3,11 @@ fn main() { let x = 1; match x { + // 1か2 1 | 2 => println!("one or two"), + // 3 3 => println!("three"), + // なにか _ => println!("anything"), } // ANCHOR_END: here diff --git a/listings/ch18-patterns-and-matching/no-listing-03-ranges/Cargo.toml b/listings/ch18-patterns-and-matching/no-listing-03-ranges/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/no-listing-03-ranges/Cargo.toml +++ b/listings/ch18-patterns-and-matching/no-listing-03-ranges/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/no-listing-03-ranges/src/main.rs b/listings/ch18-patterns-and-matching/no-listing-03-ranges/src/main.rs index a3ebe7af0..bf9d158e0 100644 --- a/listings/ch18-patterns-and-matching/no-listing-03-ranges/src/main.rs +++ b/listings/ch18-patterns-and-matching/no-listing-03-ranges/src/main.rs @@ -3,7 +3,9 @@ fn main() { let x = 5; match x { + // 1から5まで 1..=5 => println!("one through five"), + // それ以外 _ => println!("something else"), } // ANCHOR_END: here diff --git a/listings/ch18-patterns-and-matching/no-listing-04-ranges-of-char/Cargo.toml b/listings/ch18-patterns-and-matching/no-listing-04-ranges-of-char/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/no-listing-04-ranges-of-char/Cargo.toml +++ b/listings/ch18-patterns-and-matching/no-listing-04-ranges-of-char/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch18-patterns-and-matching/no-listing-04-ranges-of-char/src/main.rs b/listings/ch18-patterns-and-matching/no-listing-04-ranges-of-char/src/main.rs index 8cebfef5e..b056032eb 100644 --- a/listings/ch18-patterns-and-matching/no-listing-04-ranges-of-char/src/main.rs +++ b/listings/ch18-patterns-and-matching/no-listing-04-ranges-of-char/src/main.rs @@ -3,8 +3,11 @@ fn main() { let x = 'c'; match x { + // ASCII文字前半 'a'..='j' => println!("early ASCII letter"), + // ASCII文字後半 'k'..='z' => println!("late ASCII letter"), + // それ以外 _ => println!("something else"), } // ANCHOR_END: here diff --git a/listings/ch18-patterns-and-matching/no-listing-05-destructuring-structs-and-tuples/Cargo.toml b/listings/ch18-patterns-and-matching/no-listing-05-destructuring-structs-and-tuples/Cargo.toml index f77be077b..82fe057bb 100644 --- a/listings/ch18-patterns-and-matching/no-listing-05-destructuring-structs-and-tuples/Cargo.toml +++ b/listings/ch18-patterns-and-matching/no-listing-05-destructuring-structs-and-tuples/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "patterns" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/src/ch18-00-patterns.md b/src/ch18-00-patterns.md index 10f7e29b9..fe997eade 100644 --- a/src/ch18-00-patterns.md +++ b/src/ch18-00-patterns.md @@ -5,13 +5,14 @@ # パターンとマッチング -パターンは、複雑であれ、単純であれ、Rustで型の構造に一致する特別な記法です。`match`式や他の構文と組み合わせてパターンを使用すると、 +*パターン*は、型の構造にマッチするためのRustの特別な記法で、複合的なものから単純なものまで様々です。 +`match`式や他の構文と組み合わせてパターンを使用すると、 プログラムの制御フローをよりコントロールできます。パターンは、以下を組み合わせることで構成されます: -これらの要素が取り組んでいるデータの形を説明し、それから値に対してマッチを行い、 -プログラムに正しい値があって特定のコードを実行し続けられるかどうかを決定します。 +パターンの例としては`x`や`(a, 3)`や`Some(Color::Red)`などが含まれます。 +有効なパターンの文脈では、これらの構成要素はデータの形を記述します。 +プログラムは値をパターンとマッチングして、特定のコードを実行し続けるために正しいデータの形を持っているかどうかを判断します。 @@ -38,6 +38,27 @@ match VALUE { } ``` + + +例えば、以下はリスト6-5の変数`x`内の`Option`値に対してマッチする`match`式です: + +```rust,ignore +match x { + None => None, + Some(i) => Some(i + 1), +} +``` + + + +この`match`式に含まれるパターンは、各矢印の左側にある`Node`と`Some(i)`です。 + `_`という特定のパターンは何にでもマッチしますが、変数には束縛されないので、よく最後のマッチアームに使用されます。 例えば、`_`パターンは、指定されていないあらゆる値を無視したい時に有用です。 -`_`パターンについて詳しくは、この章の後ほど、「パターンで値を無視する」節で講義します。 +`_`パターンについて詳しくは、この章の後ほど、[「パターンの値を無視する」][ignoring-values-in-a-pattern]節で講義します。 リスト18-1は、`if let`、`else if`、`else if let`式を混ぜてマッチさせることもできることを示しています。 @@ -91,13 +113,13 @@ let` arms aren’t required to relate to each other. また、一連の`if let`、`else if`、`else if let`アームの条件は、お互いに関連している必要はありません。 -リスト18-1のコードは、背景色が何になるべきかを決定するいくつかの条件を連なって確認するところを示しています。 +リスト18-1のコードは、いくつかの条件を連続してチェックし、それに応じて背景を何色にするかを決定しています。 この例では、実際のプログラムではユーザ入力を受け付ける可能性のある変数をハードコードされた値で生成しています。 -ユーザがお気に入りの色を指定したら、その色が背景色になります。今日が火曜日なら、背景色は緑です。 -ユーザが年齢を文字列で指定し、数値として解析することができたら、背景色は、その数値の値によって紫かオレンジになります。 -どの条件も適用できなければ、背景色は青になります: +ユーザがお気に入りの色を指定したら、その色が背景として使われます。 +お気に入りの色が指定されておらず、今日が火曜日なら、背景色は緑です。 +もしそうではなく、ユーザが年齢を文字列で指定し、数値として解析することができたら、 +背景色は、その数値によって紫かオレンジになります。 +どの条件も適用できなければ、背景色は青になります。 @@ -195,25 +197,17 @@ not alert us to the possible logic bug. `if let`と構成が似て、`while let`条件分岐ループは、パターンが合致し続ける限り、`while`ループを走らせます。 -リスト18-2の例は、ベクタをスタックとして使用する`while let`ループを示し、 -ベクタの値をプッシュしたのとは逆順に出力します: +リスト18-2では、ベクタをスタックとして使用する`while let`ループを書き、 +ベクタの値をプッシュしたのとは逆順に出力します。 ```rust -let mut stack = Vec::new(); - -stack.push(1); -stack.push(2); -stack.push(3); - -while let Some(top) = stack.pop() { - println!("{}", top); -} +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-02/src/main.rs:here}} ``` - -第3章で、Rustコードにおいては、`for`ループが最もありふれたループ構造だと述べましたが、 -`for`が取るパターンについてはまだ議論していませんでした。`for`ループにおいて、 -直接キーワード`for`に続く値がパターンなので、`for x in y`では、`x`がパターンになります。 - - +`for`ループにおいて、キーワード`for`の直後に続く値はパターンです。 +例えば、`for x in y`では、`x`がパターンになります。 リスト18-3は`for`ループでパターンを使用して`for`ループの一部としてタプルを分配あるいは、分解する方法をデモしています。 ```rust -let v = vec!['a', 'b', 'c']; - -for (index, value) in v.iter().enumerate() { - println!("{} is at index {}", value, index); -} +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-03/src/main.rs:here}} ``` -`enumerate`メソッドを使用してイテレータを改造し、値とその値のイテレータでの添え字をタプルに配置して生成しています。 -`enumerate`の最初の呼び出しは、タプル`(0, 'a')`を生成します。この値がパターン`(index, value)`とマッチさせられると、 +`enumerate`メソッドを使用して、値とその値の添え字をタプルに配置して生成するようにイテレータを調整しています。 +最初に生成される値はタプル`(0, 'a')`です。この値がパターン`(index, value)`とマッチさせられると、 `index`は`0`、`value`は`'a'`になり、出力の最初の行を出力するのです。 -この本を通してこのような`let`を何百回も使用してきて、お気付きではなかったかもしれませんが、 -パターンを使用していたのです!より正式には、`let`文はこんな見た目をしています: +お気付きではなかったかもしれませんが、このように`let`文を使うときは毎回、パターンを使っていたのです! +より正式には、`let`文はこんな見た目をしています: ```text let PATTERN = EXPRESSION; @@ -354,7 +335,7 @@ To see the pattern matching aspect of `let` more clearly, consider Listing これは`let`でパターンを使用し、タプルを分配します。 ```rust -let (x, y, z) = (1, 2, 3); +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-04/src/main.rs:here}} ``` src/main.rs:2:9 - | -2 | let (x, y) = (1, 2, 3); - | ^^^^^^ expected a tuple with 3 elements, found one with 2 elements - | (3要素のタプルを予期したのに、2要素のタプルが見つかりました) - | - = note: expected type `({integer}, {integer}, {integer})` - found type `(_, _)` +```console +{{#include ../listings/ch18-patterns-and-matching/listing-18-05/output.txt}} ``` -タプルの値のうち1つ以上を無視したかったら、「パターンで値を無視する」節で見かけるように、 -`_`か`..`を使用できるでしょう。パターンに変数が多すぎるというのが問題なら、変数の数がタプルの要素数と一致するように変数を減らすことで、 +このエラーを修正するには、[「パターンの値を無視する」][ignoring-values-in-a-pattern]節で見ることになりますが、 +`_`か`..`を使用してタプルの値のうち1つ以上を無視することができます。 +パターンに変数が多すぎるというのが問題なら、変数の数がタプルの要素数と一致するように変数を減らすことで、 型を一致させることが解決策です。 この時点で、パターンを使用する方法をいくつか見てきましたが、パターンを使用できる箇所全部で同じ動作をするわけではありません。 パターンが論駁不可能でなければならない箇所もあります。他の状況では、論駁可能にもなり得ます。この2つの概念を次に議論します。 + + + +[ignoring-values-in-a-pattern]: +ch18-03-pattern-syntax.html#パターンの値を無視する diff --git a/src/ch18-02-refutability.md b/src/ch18-02-refutability.md index 999579077..0fcd2775d 100644 --- a/src/ch18-02-refutability.md +++ b/src/ch18-02-refutability.md @@ -10,28 +10,32 @@ for any possible value passed are *irrefutable*. An example would be `x` in the statement `let x = 5;` because `x` matches anything and therefore cannot fail to match. Patterns that can fail to match for some possible value are *refutable*. An example would be `Some(x)` in the expression `if let Some(x) = -a_value`; because if the value in `a_value` variable is `None` rather than +a_value` because if the value in the `a_value` variable is `None` rather than `Some`, the `Some(x)` pattern will not match. --> パターンには2つの形態があります: 論駁可能なものと論駁不可能なものです。渡される可能性のあるあらゆる値に合致するパターンは、 *論駁不可能*なものです。文`let x = 5;`の`x`は一例でしょう。`x`は何にでも合致し、故に合致に失敗することがあり得ないからです。 なんらかの可能性のある値に対して合致しないことがあるパターンは、*論駁可能*なものです。 -一例は、式`if let Some(x) = a_value`の`Some(x)`になるでしょう; `a_value`変数の値が`Some`ではなく、 -`None`なら、`Some(x)`パターンは合致しないでしょうから。 +一例は、式`if let Some(x) = a_value`の`Some(x)`になるでしょう。`a_value`変数の値が`Some`ではなく、 +`None`なら、`Some(x)`パターンは合致しないからです。 関数の引数、`let`文、`for`ループは、値が合致しなかったら何も意味のあることをプログラムが実行できないので、 -論駁不可能なパターンしか受け付けられません。`if let`と`while let`式は、定義により失敗する可能性を処理することを意図したものなので、 -論駁可能なパターンのみを受け付けます: 条件式の機能は、成功か失敗によって異なる振る舞いをする能力にあるのです。 +論駁不可能なパターンしか受け付けられません。 +`if let`と`while let`式は論駁可能なパターンも論駁不可能なパターンも受け付けますが、 +定義により失敗する可能性を処理することを意図したものなので、 +コンパイラは論駁不可能なパターンに対しては警告を発します: +条件式の機能は、成功か失敗によって異なる振る舞いをする能力にあるのです。 - | -3 | let Some(x) = some_option_value; - | ^^^^^^^ pattern `None` not covered +```console +{{#include ../listings/ch18-patterns-and-matching/listing-18-08/output.txt}} ``` -論駁不可能なパターンが必要な箇所に論駁可能なパターンがある問題を修正するには、パターンを使用するコードを変えればいいのです: +論駁不可能なパターンが必要な箇所に論駁可能なパターンがある場合は、パターンを使用するコードを変えることで修正することができます: `let`の代わりに`if let`を使用できます。そして、パターンが合致しなかったら、コードは合法に継続する手段を残して、 波括弧内のコードを飛ばすだけでしょう。リスト18-9は、リスト18-8のコードの修正方法を示しています。 ```rust -# let some_option_value: Option = None; -if let Some(x) = some_option_value { - println!("{}", x); -} +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-09/src/main.rs:here}} ``` コードに逃げ道を与えました!このコードは完全に合法ですが、エラーを受け取らないで論駁不可能なパターンを使用することはできないことを意味します。 -リスト18-10のように、`x`のような常にマッチするパターンを`if let`に与えたら、コンパイルできないでしょう。 +リスト18-10のように、`x`のような常にマッチするパターンを`if let`に与えたら、コンパイラは警告を発するでしょう。 -```rust,ignore -if let x = 5 { - println!("{}", x); -}; +```rust +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-10/src/main.rs:here}} ``` :2:8 - | -2 | if let x = 5 { - | ^ irrefutable pattern +```console +{{#include ../listings/ch18-patterns-and-matching/listing-18-10/output.txt}} ``` -本全体で、多くの種類のパターンの例を見かけてきました。この節では、パターンで合法な記法全てを集め、 -それぞれを使用したくなる可能性がある理由について議論します。 +この節ではパターンとして有効な記法をすべて集め、それぞれについて使用するとよい理由と状況について議論します。 シャドーイングされた変数を導入するのではなく、外側の`x`と`y`の値を比較する`match`式を生成するには、 代わりにマッチガード条件式を使用する必要があるでしょう。マッチガードについては、後ほど、 -「マッチガードで追加の条件式」節で語ります。 +[「マッチガードで追加の条件式」](#マッチガードで追加の条件式)節で語ります。 -`match`式で`|`記法で複数のパターンに合致させることができ、これは*or*を意味します。例えば、以下のコードは`x`の値をマッチアームに合致させ、 +`match`式で`|`記法で複数のパターンに合致させることができ、これがパターン*or*演算子です。例えば、以下のコードでは`x`の値をマッチアームに合致させ、 最初のマッチアームには*or*選択肢があり、`x`の値がそのアームのどちらかの値に合致したら、そのアームのコードが走ることを意味します: ```rust -let x = 1; - -match x { - // 1か2 - 1 | 2 => println!("one or two"), - // 3 - 3 => println!("three"), - // なんでも - _ => println!("anything"), -} +{{#rustdoc_include ../listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/src/main.rs:here}} ``` `..=`記法により、限度値を含む値の範囲にマッチさせることができます。以下のコードでは、 -パターンが範囲内のどれかの値に合致すると、そのアームが実行されます: +パターンが与えられた範囲内のどれかの値に合致すると、そのアームが実行されます: ```rust -let x = 5; - -match x { - // 1から5まで - 1..=5 => println!("one through five"), - // それ以外 - _ => println!("something else"), -} +{{#rustdoc_include ../listings/ch18-patterns-and-matching/no-listing-03-ranges/src/main.rs:here}} ``` -`x`が1、2、3、4か5なら、最初のアームが合致します。この記法は、`|`演算子を使用して同じ考えを表現するより便利です; -`1..=5`ではなく、`|`を使用したら、`1 | 2 | 3 | 4 | 5`と指定しなければならないでしょう。 +`x`が1、2、3、4か5なら、最初のアームが合致します。複数のマッチ値に対しては、この記法は`|`演算子を使用して同じ考えを表現するより便利です; +もし`|`を使うとしたら、`1 | 2 | 3 | 4 | 5`と指定しなければならないでしょう。 範囲を指定する方が遥かに短いのです。特に1から1000までの値と合致させたいとかなら! -範囲は、数値か`char`値でのみ許可されます。コンパイラがコンパイル時に範囲が空でないことを確認しているからです。 -範囲が空かそうでないかコンパイラにわかる唯一の型が`char`か数値なのです。 +コンパイラはコンパイル時に範囲が空でないことを確認します。 +範囲が空かそうでないかコンパイラにわかる型は`char`と数値のみなので、 +範囲は、数値か`char`値でのみ許可されます。 -また、パターンを使用して構造体、enum、タプル、参照を分配し、これらの値の異なる部分を使用することもできます。 +また、パターンを使用して構造体、enum、およびタプルを分配し、これらの値の異なる部分を使用することもできます。 各値を見ていきましょう。 - -このコードは、`p`変数の`x`と`y`フィールドの値に合致する変数`a`と`b`を生成します。この例は、 -パターンの変数の名前は、構造体のフィールド名と合致する必要はないことを示しています。しかし、 -変数名をフィールド名と一致させてどの変数がどのフィールド由来のものなのか覚えやすくしたくなることは一般的なことです。 +and `y` fields of the `p` struct. This example shows that the names of the +variables in the pattern don’t have to match the field names of the struct. +However, it’s common to match the variable names to the field names to make it +easier to remember which variables came from which fields. Because of this +common usage, and because writing `let Point { x: x, y: y } = p;` contains a +lot of duplication, Rust has a shorthand for patterns that match struct fields: +you only need to list the name of the struct field, and the variables created +from the pattern will have the same names. Listing 18-13 behaves in the same +way as the code in Listing 18-12, but the variables created in the `let` +pattern are `x` and `y` instead of `a` and `b`. - -変数名をフィールドに一致させることは一般的であり、`let Point{ x: x, y: y } = p;`と書くことは多くの重複を含むので、 -構造体のフィールドと一致するパターンには省略法があります: 構造体のフィールドの名前を列挙するだけで、 -パターンから生成される変数は同じ名前になるのです。リスト18-13は、リスト18-12と同じ振る舞いをするコードを表示していますが、 +このコードは、`p`構造体の`x`と`y`フィールドの値に合致する変数`a`と`b`を生成します。この例は、 +パターンの変数の名前は、構造体のフィールド名と合致する必要はないことを示しています。しかし、 +この一般的な用法から、そして`let Point{ x: x, y: y } = p;`と書くことは多くの重複を含むことから、 +Rustには構造体のフィールドと一致するパターンには省略法があります: 構造体のフィールドの名前を列挙するだけで、 +パターンから生成される変数は同じ名前になるのです。リスト18-13は、リスト18-12と同じように振る舞いますが、 `let`パターンで生成される変数は`a`と`b`ではなく、`x`と`y`です。 -リスト18-14は、`Point`値を3つの場合に区別する`match`式を表示しています: `x`軸上の点(`y = 0`ならそうなる)、 +リスト18-14には、`Point`値を3つの場合に区別する`match`式があります: `x`軸上の点(`y = 0`ならそうなる)、 `y`軸上の点(`x = 0`)、あるいはどちらでもありません。 + +`match`式は、マッチする最初のパターンを見つけたら、アームの確認をやめることを思い出してください。 +そのため、`Point { x: 0, y: 0}`は`x`軸上および`y`軸上にありますが、このコードは`On the x axis at 0`を出力するでしょう。 + @@ -473,16 +392,15 @@ containing a 0, so this code will print `On the y axis at 7`. #### enumを分配する -例えば、第6章のリスト6-5で`Option`を分配するなどこの本の前半でenumを分配しました。 -明示的に触れなかった詳細の1つは、enumを分配するパターンは、enum内に格納されているデータが定義されている手段に対応すべきということです。 +この本の中でenumを分配してきました(例えば、第6章のリスト6-5)が、 +enumを分配するパターンはenum内に格納されているデータの定義され方に対応する、ということについてはまだ明示的に議論していませんでした。 例として、リスト18-15では、リスト6-2から`Message` enumを使用し、内部の値それぞれを分配するパターンを伴う`match`を書いています。 - -#### 参照を分配する - - -パターンとマッチさせている値に参照が含まれる場合、値から参照を分配する必要があり、 -パターンに`&`を指定することでそうすることができます。そうすることで参照を保持する変数を得るのではなく、 -参照が指している値を保持する変数が得られます。このテクニックは、参照を走査するイテレータがあるクロージャで特に役に立ちますが、 -そのクロージャで参照ではなく、値を使用したいです。 +#### ネストされた構造体と列挙体を分配する - -リスト18-16の例は、ベクタの`Point`インスタンスへの参照を走査し、`x`と`y`値に簡単に計算を行えるように、 -参照と構造体を分配します。 + +今のところ、ここでの例はすべて一階層の深さの構造体または列挙体にマッチしていますが、 +マッチングはネストされた要素に対しても行うことができます!例えばリスト18-15のコードは、 +リスト18-16で示すように、`ChangeColor`メッセージでRGBおよびHSV色をサポートするようにリファクタすることができます。 ```rust -# struct Point { -# x: i32, -# y: i32, -# } -# -let points = vec![ - Point { x: 0, y: 0 }, - Point { x: 1, y: 5 }, - Point { x: 10, y: -3 }, -]; - -let sum_of_squares: i32 = points - .iter() - .map(|&Point { x, y }| x * x + y * y) - .sum(); +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-16/src/main.rs}} ``` - -リスト18-16: 構造体への参照を構造体のフィールド値に分配する - - -このコードは、値135を保持する変数`sum_of_squares`を返してきて、これは、`x`値と`y`値を2乗し、足し合わせ、 -`points`ベクタの`Point`それぞれの結果を足して1つの数値にした結果です。 - - - -`&Point { x, y }`に`&`が含まれていなかったら、型不一致エラーが発生していたでしょう。 -`iter`はそうすると、実際の値ではなく、ベクタの要素への参照を走査するからです。そのエラーはこんな見た目でしょう: - -```text -error[E0308]: mismatched types - --> - | -14 | .map(|Point { x, y }| x * x + y * y) - | ^^^^^^^^^^^^ expected &Point, found struct `Point` - | - = note: expected type `&Point` - found type `Point` -``` +リスト 18-16: ネストされたenumにマッチする -このエラーは、コンパイラがクロージャに`&Point`と一致することを期待しているのに、 -`Point`への参照ではなく、`Point`値に直接一致させようとしたことを示唆しています。 +`match`式の最初のアームのパターンは、`Color::Rgb`列挙子を含む`Message::ChangeColor` enum 列挙子にマッチします; +その後パターンは内側の`i32`値に束縛します。2番目のアームのパターンも`Message::ChangeColor` enum 列挙子にマッチしますが、 +内側のenumは、こちらは`Color::Hsv`にマッチします。2つのenumが関連し合っている場合でも、1つの`match`式内で、 +これらの複合的な条件を指定することができます。 -どんな値にも一致するけれども、値を束縛しないワイルドカードパターンとしてアンダースコア、`_`を使用してきました。 -アンダースコア、`_`パターンは特に`match`式の最後のアームとして役に立ちますが、 +どんな値にも一致するけれども、値を束縛しないワイルドカードパターンとしてアンダースコアを使用してきました。 +これは特に`match`式の最後のアームとして役に立ちますが、 関数の引数も含めてあらゆるパターンで使えます。リスト18-17に示したようにですね。 @@ -781,17 +600,17 @@ and will print `This code only uses the y parameter: 4`. 特定の関数の引数が最早必要ないほとんどの場合、未使用の引数が含まれないようにシグニチャを変更するでしょう。 関数の引数を無視することが特に有用なケースもあり、例えば、トレイトを実装する際、 特定の型シグニチャが必要だけれども、自分の実装の関数本体では引数の1つが必要ない時などです。 -そうすれば、代わりに名前を使った場合のようには、未使用関数引数についてコンパイラが警告することはないでしょう。 +名前を使った場合には未使用関数引数についてのコンパイラ警告が出るでしょうが、こうすればそれをを避けられます。 また、他のパターンの内部で`_`を使用して、値の一部だけを無視することもでき、例えば、 値の一部だけを確認したいけれども、走らせたい対応するコードでは他の部分を使用することがない時などです。 リスト18-18は、設定の値を管理する責任を負ったコードを示しています。業務要件は、 -ユーザが既存の設定の変更を上書きすることはできないべきだけれども、設定を解除し、 -現在設定がされていなければ設定に値を与えられるというものです。 +ユーザが既存の設定の変更を上書きすることはできないべきだけれども、設定を解除することができるべきで、 +現在設定がされていなければそれに値を与えることができるべきというものです。 ```rust -let mut setting_value = Some(5); -let new_setting_value = Some(10); - -match (setting_value, new_setting_value) { - (Some(_), Some(_)) => { - // 既存の値の変更を上書きできません - println!("Can't overwrite an existing customized value"); - } - _ => { - setting_value = new_setting_value; - } -} - -// 設定は{:?}です -println!("setting is {:?}", setting_value); +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-18/src/main.rs:here}} ``` このコードは、`Can't overwrite an existing customized value`、そして`setting is Some(5)`と出力するでしょう。 最初のマッチアームで、どちらの`Some`列挙子内部の値にも合致させたり、使用する必要はありませんが、 `setting_value`と`new_setting_value`が`Some`列挙子の場合を確かに確認する必要があります。 -その場合、何故`setting_value`を変更しないかを出力し、変更しません。 +その場合、`setting_value`を変更しない理由を出力し、変更しません。 -変数を作っているのにどこでも使用していなければ、バグかもしれないのでコンパイラは通常、警告を発します。 -しかし時として、まだ使用しない変数を作るのが有用なこともあります。プロトタイプを開発していたり、 +変数を作っているのにどこでも使用していなければ、未使用変数はバグかもしれないのでコンパイラは通常、警告を発します。 +しかし時として、まだ使用しない変数を作れるほうが有用なこともあります。プロトタイプを開発していたり、 プロジェクトを始めた直後だったりなどです。このような場面では、変数名をアンダースコアで始めることで、 コンパイラに未使用変数について警告しないよう指示することができます。リスト18-20で2つの未使用変数を生成していますが、 -このコードを実行すると、そのうちの1つにしか警告が出ないはずです。 +このコードをコンパイルすると、そのうちの1つにしか警告が出ないはずです。 -ここで、変数`y`を使用していないことに対して警告が出ていますが、アンダースコアが接頭辞になっている変数には、 +ここで、変数`y`を使用していないことに対して警告が出ていますが、`_x`には、 使用していないという警告が出ていません。 -多くの部分がある値では、`..`記法を使用していくつかの部分だけを使用して残りを無視し、 +多くの部分がある値では、`..`記法を使用して特定の部分を使用して残りを無視し、 無視する値それぞれにアンダースコアを列挙する必要性を回避できます。`..`パターンは、 パターンの残りで明示的にマッチさせていない値のどんな部分も無視します。リスト18-23では、 3次元空間で座標を保持する`Point`構造体があります。`match`式で`x`座標のみ処理し、 `y`と`z`フィールドの値は無視したいです。 ```rust -struct Point { - x: i32, - y: i32, - z: i32, -} - -let origin = Point { x: 0, y: 0, z: 0 }; - -match origin { - Point { x, .. } => println!("x is {}", x), -} +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-23/src/main.rs:here}} ``` src/main.rs:5:22 - | -5 | (.., second, ..) => { - | ^^ +```console +{{#include ../listings/ch18-patterns-and-matching/listing-18-25/output.txt}} ``` - -### `ref`と`ref mut`でパターンに参照を生成する - - - -`ref`を使用して値の所有権がパターンの変数にムーブされないように、参照を生成することに目を向けましょう。 -通常、パターンにマッチさせると、パターンで導入された変数は値に束縛されます。Rustの所有権規則は、 -その値が`match`などパターンを使用しているあらゆる場所にムーブされることを意味します。 -リスト18-26は、変数があるパターンとそれから`match`の後に値全体を`println!`文で後ほど使用する`match`の例を示しています。 -このコードはコンパイルに失敗します。`robot_name`値の一部の所有権が、 -最初の`match`アームのパターンの`name`変数に移るからです。 - -```rust,ignore -let robot_name = Some(String::from("Bors")); - -match robot_name { - // 名前が見つかりました: {} - Some(name) => println!("Found a name: {}", name), - None => (), -} - -// robot_nameは: {:?} -println!("robot_name is: {:?}", robot_name); -``` - - - -リスト18-26: `match`アームパターンで変数を生成すると、値の所有権が奪われる - - - -`robot_name`の一部の所有権が`name`にムーブされたので、`robot_name`に最早所有権がないために、 -`match`の後に`println!`で最早`robot_name`を使用することは叶いません。 - - - -このコードを修正するために、`Some(name)`パターンに所有権を奪わせるのではなく、 -`robot_name`のその部分を借用させたいです。パターンの外なら、値を借用する手段は、 -`&`で参照を生成することだと既にご認識でしょうから、解決策は`Some(name)`を`Some(&name)`に変えることだとお考えかもしれませんね。 - - - -しかしながら、「分配して値を分解する」節で見かけたように、パターンにおける`&`記法は参照を*生成*せず、 -値の既存の参照に*マッチ*します。パターンにおいて`&`には既にその意味があるので、 -`&`を使用してパターンで参照を生成することはできません。 - - - -その代わりに、パターンで参照を生成するには、リスト18-27のように、新しい変数の前に`ref`キーワードを使用します。 - -```rust -let robot_name = Some(String::from("Bors")); - -match robot_name { - Some(ref name) => println!("Found a name: {}", name), - None => (), -} - -println!("robot_name is: {:?}", robot_name); -``` - - - -リスト18-27: パターンの変数が値の所有権を奪わないように参照を生成する - - - -`robot_name`の`Some`列挙子の値が`match`にムーブされないので、この例はコンパイルできます; -`match`はムーブするのではなく、`robot_name`のデータへの参照を取っただけなのです。 - - - -パターンで合致した値を可変化できるように可変参照を生成するには、`&mut`の代わりに`ref mut`を使用します。 -理由は今度も、パターンにおいて、前者は既存の可変参照にマッチするためにあり、新しい参照を生成しないからです。 -リスト18-28は、可変参照を生成するパターンの例です。 - -```rust -let mut robot_name = Some(String::from("Bors")); - -match robot_name { - // 別の名前 - Some(ref mut name) => *name = String::from("Another name"), - None => (), -} - -println!("robot_name is: {:?}", robot_name); -``` - - - -リスト18-28: `ref mut`を使用して、パターンの一部として値への可変参照を生成する - - - -この例はコンパイルが通り、`robot_name is: Some("Another name")`と出力するでしょう。 -`name`は可変参照なので、値を可変化するためにマッチアーム内で`*`演算子を使用して参照外しする必要があります。 - @@ -1327,84 +926,79 @@ arm code using the `*` operator to mutate the value. ### マッチガードで追加の条件式 -*マッチガード*は、`match`アームのパターンの後に指定されるパターンマッチングとともに、 +*マッチガード*は、`match`アームのパターンの後に指定される、 そのアームが選択されるのにマッチしなければならない追加の`if`条件です。マッチガードは、 1つのパターン単独でできるよりも複雑な考えを表現するのに役に立ちます。 -この条件は、パターンで生成された変数を使用できます。リスト18-29は、 -最初のアームにパターン`Some(x)`と`if x < 5`というマッチガードもある`match`を示しています。 +この条件は、パターンで生成された変数を使用できます。リスト18-26は、 +最初のアームにパターン`Some(x)`と`if x % 2 == 0` (数が偶数の場合に真)というマッチガードもある`match`を示しています。 ```rust -let num = Some(4); - -match num { - // 5未満です: {} - Some(x) if x < 5 => println!("less than five: {}", x), - Some(x) => println!("{}", x), - None => (), -} +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-26/src/main.rs:here}} ``` -リスト18-29: パターンにマッチガードを追記する +リスト18-26: パターンにマッチガードを追記する -この例は、`less than five: 4`と出力します。`num`が最初のアームのパターンと比較されると、 -`Some(4)`は`Some(x)`に一致するので、マッチします。そして、マッチガードが`x`の値が`5`未満か確認し、 +この例は、`The number 4 is even`と出力します。`num`が最初のアームのパターンと比較されると、 +`Some(4)`は`Some(x)`に一致するので、マッチします。そして、マッチガードが`x`を2で割った余りが0と等しいか確認し、 そうなっているので、最初のアームが選択されます。 -代わりに`num`が`Some(10)`だったなら、最初のアームのマッチガードは偽になったでしょう。 -10は5未満ではないからです。Rustはそうしたら2番目のアームに移動し、マッチするでしょう。 +代わりに`num`が`Some(5)`だったなら、最初のアームのマッチガードは偽になったでしょう。 +5を2で割った余りは1であり、0と等しくないからです。Rustはそうしたら2番目のアームに移動し、マッチするでしょう。 2番目のアームにはマッチガードがなく、それ故にあらゆる`Some`列挙子に一致するからです。 -パターン内で`if x < 5`という条件を表現する方法はありませんので、マッチガードにより、 -この論理を表現する能力が得られるのです。 +パターン内で`if x % 2 == 0`という条件を表現する方法はありませんので、マッチガードにより、 +この論理を表現する能力が得られるのです。この追加の表現力の欠点としては、コンパイラは、 +マッチガード式が関連するときに網羅性をチェックしないという点があります。 リスト18-11において、マッチガードを使用すれば、パターンがシャドーイングする問題を解決できると述べました。 -`match`の外側の変数を使用するのではなく、`match`式のパターン内部では新しい変数が作られることを思い出してください。 -その新しい変数は、外側の変数の値と比較することができないことを意味しました。リスト18-30は、 +`match`の外側の変数を使用するのではなく、`match`式のパターン内部では新しい変数を作成したことを思い出してください。 +その新しい変数は、外側の変数の値と比較することができないことを意味しました。リスト18-27は、 マッチガードを使ってこの問題を修正する方法を表示しています。 -リスト18-30: マッチガードを使用して外側の変数と等しいか確認する +リスト18-27: マッチガードを使用して外側の変数と等しいか確認する また、マッチガードで*or*演算子の`|`を使用して複数のパターンを指定することもできます; -マッチガードの条件は全てのパターンに適用されます。リスト18-31は、 -`|`を使用するパターンとマッチガードを組み合わせる優先度を示しています。この例で重要な部分は、 +マッチガードの条件は全てのパターンに適用されます。リスト18-28は、 +`|`を使用するパターンをマッチガードと組み合わせるときの優先順位を示しています。この例で重要な部分は、 `if y`は`6`にしか適用されないように見えるのに、`if y`マッチガードが`4`、`5`、*そして*`6`に適用されることです。 ```rust -let x = 4; -let y = false; - -match x { - // はい - 4 | 5 | 6 if y => println!("yes"), - // いいえ - _ => println!("no"), -} +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-28/src/main.rs:here}} ``` -リスト18-31: 複数のパターンとマッチガードを組み合わせる +リスト18-28: 複数のパターンとマッチガードを組み合わせる -*at*演算子(`@`)により、値を保持する変数を生成するのと同時にその値がパターンに一致するかを調べることができます。 -リスト18-32は、`Message::Hello`の`id`フィールドが範囲`3..=7`にあるかを確かめたいという例です。 -しかし、アームに紐づいたコードで使用できるように変数`id_variable`に値を束縛もしたいです。この変数をフィールドと同じ、 +*at*演算子`@`により、値のパターンマッチを検査するのと同時に、その値を保持する変数を生成することができます。 +リスト18-29では、`Message::Hello`の`id`フィールドが範囲`3..=7`にあるかを確かめたいです。 +アームに紐づいたコードで使用できるように変数`id_variable`に値を束縛もしたいです。この変数をフィールドと同じ、 `id`と名付けることもできますが、この例では異なる名前にします。 ```rust -enum Message { - Hello { id: i32 }, -} - -let msg = Message::Hello { id: 5 }; - -match msg { - Message::Hello { id: id_variable @ 3..=7 } => { - // 範囲内のidが見つかりました: {} - println!("Found an id in range: {}", id_variable) - }, - Message::Hello { id: 10..=12 } => { - // 別の範囲内のidが見つかりました - println!("Found an id in another range") - }, - Message::Hello { id } => { - // それ以外のidが見つかりました - println!("Found some other id: {}", id) - }, -} +{{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-29/src/main.rs:here}} ``` -`@`を使用してテストしつつ、パターンの値に束縛する +リスト18-29: `@`を使用してテストしつつ、パターンの値に束縛する -Rustのパターンは、異なる種類のデータを区別するのに役立つという点でとても有用です。`match`式で使用されると、 +Rustのパターンは、異なる種類のデータを区別するのにとても有用です。`match`式で使用されると、 コンパイラはパターンが全ての可能性を網羅しているか保証し、そうでなければプログラムはコンパイルできません。 `let`文や関数の引数のパターンは、その構文をより有用にし、値を分配して小さな部品にすると同時に変数に代入できるようにしてくれます。 単純だったり複雑だったりするパターンを生成してニーズに合わせることができます。 From 262987a1e0cc478e30c84f8ea36fc106762c9dea Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 26 May 2024 12:58:08 +0900 Subject: [PATCH 20/22] =?UTF-8?q?ch19=20=E9=AB=98=E5=BA=A6=E3=81=AA?= =?UTF-8?q?=E6=A9=9F=E8=83=BD=E3=81=AE=E5=92=8C=E8=A8=B3=E3=82=92=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=89=88=E3=81=AB=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rust-lang/book@19c40bfd2d57641d962f3119a1c343355f1b3c5e --- .../listing-19-01/Cargo.toml | 3 +- .../listing-19-02/Cargo.toml | 3 +- .../listing-19-03/Cargo.toml | 3 +- .../listing-19-04/Cargo.toml | 3 +- .../listing-19-05/Cargo.toml | 3 +- .../listing-19-05/output.txt | 29 +- .../listing-19-05/src/main.rs | 6 +- .../listing-19-06/Cargo.toml | 3 +- .../listing-19-06/src/main.rs | 6 +- .../listing-19-07/Cargo.toml | 3 +- .../listing-19-07/src/main.rs | 2 +- .../listing-19-08/Cargo.toml | 3 +- .../listing-19-08/src/main.rs | 1 + .../listing-19-09/Cargo.toml | 3 +- .../listing-19-10/Cargo.toml | 3 +- .../listing-19-11/Cargo.toml | 3 +- .../listing-19-11/src/main.rs | 2 + .../listing-19-12/Cargo.toml | 3 +- .../listing-19-13/Cargo.toml | 3 +- .../listing-19-14/Cargo.toml | 3 +- .../listing-19-14/src/main.rs | 2 +- .../listing-19-15/Cargo.toml | 3 +- .../listing-19-16/Cargo.toml | 3 +- .../listing-19-16/src/main.rs | 3 + .../listing-19-17/Cargo.toml | 3 +- .../listing-19-18/Cargo.toml | 3 +- .../listing-19-19/Cargo.toml | 3 +- .../listing-19-19/src/main.rs | 3 + .../listing-19-20/Cargo.toml | 3 +- .../listing-19-20/output.txt | 23 +- .../listing-19-21/Cargo.toml | 3 +- .../listing-19-22/Cargo.toml | 3 +- .../listing-19-23/Cargo.toml | 3 +- .../listing-19-24/Cargo.toml | 3 +- .../listing-19-25/Cargo.toml | 3 +- .../listing-19-27/Cargo.toml | 3 +- .../listing-19-27/src/main.rs | 1 + .../listing-19-28/Cargo.toml | 3 +- .../listing-19-30/Cargo.toml | 3 +- .../listing-19-31/hello_macro/Cargo.toml | 3 +- .../hello_macro/hello_macro_derive/Cargo.toml | 3 +- .../hello_macro/hello_macro_derive/src/lib.rs | 2 - .../hello_macro_derive/src/lib.rs.bak | 17 + .../listing-19-33/hello_macro/Cargo.toml | 3 +- .../hello_macro/hello_macro_derive/Cargo.toml | 3 +- .../hello_macro/hello_macro_derive/src/lib.rs | 2 - .../no-listing-01-unsafe-fn/Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../output.txt | 18 +- .../Cargo.toml | 3 +- .../no-listing-04-kilometers-alias/Cargo.toml | 3 +- .../no-listing-05-write-trait/Cargo.toml | 3 +- .../no-listing-06-result-alias/Cargo.toml | 3 +- .../no-listing-06-result-alias/src/lib.rs | 2 - .../no-listing-07-never-type/Cargo.toml | 3 +- .../no-listing-07-never-type/src/lib.rs | 2 - .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../no-listing-11-cant-create-str/Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../Cargo.toml | 3 +- .../no-listing-15-map-closure/Cargo.toml | 3 +- .../no-listing-16-map-function/Cargo.toml | 3 +- .../no-listing-17-map-initializer/Cargo.toml | 3 +- .../no-listing-18-returns-closure/Cargo.toml | 3 +- .../no-listing-18-returns-closure/output.txt | 30 +- .../Cargo.toml | 3 +- .../hello_macro/Cargo.toml | 3 +- .../pancakes/Cargo.toml | 3 +- .../hello_macro/Cargo.toml | 3 +- .../hello_macro/hello_macro_derive/Cargo.toml | 3 +- .../hello_macro/hello_macro_derive/src/lib.rs | 2 - .../pancakes/Cargo.toml | 3 +- .../Cargo.lock | 0 .../Cargo.toml | 3 +- .../src/lib.rs | 2 - .../output-only-01-missing-unsafe/Cargo.toml | 3 +- .../output-only-01-missing-unsafe/output.txt | 7 +- src/ch19-00-advanced-features.md | 14 +- src/ch19-01-unsafe-rust.md | 465 +++++------- src/ch19-03-advanced-traits.md | 714 +++++++----------- src/ch19-04-advanced-types.md | 352 ++++----- ...ch19-05-advanced-functions-and-closures.md | 181 +++-- src/ch19-06-macros.md | 160 ++-- 86 files changed, 957 insertions(+), 1265 deletions(-) create mode 100644 listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/src/lib.rs.bak rename listings/ch19-advanced-features/{listing-13-21-reproduced => no-listing-22-iterator-on-counter}/Cargo.lock (100%) rename listings/ch19-advanced-features/{listing-13-21-reproduced => no-listing-22-iterator-on-counter}/Cargo.toml (50%) rename listings/ch19-advanced-features/{listing-13-21-reproduced => no-listing-22-iterator-on-counter}/src/lib.rs (96%) diff --git a/listings/ch19-advanced-features/listing-19-01/Cargo.toml b/listings/ch19-advanced-features/listing-19-01/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-01/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-01/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-02/Cargo.toml b/listings/ch19-advanced-features/listing-19-02/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-02/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-02/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-03/Cargo.toml b/listings/ch19-advanced-features/listing-19-03/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-03/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-03/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-04/Cargo.toml b/listings/ch19-advanced-features/listing-19-04/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-04/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-04/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-05/Cargo.toml b/listings/ch19-advanced-features/listing-19-05/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-05/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-05/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-05/output.txt b/listings/ch19-advanced-features/listing-19-05/output.txt index 3df0e2b64..405f779aa 100644 --- a/listings/ch19-advanced-features/listing-19-05/output.txt +++ b/listings/ch19-advanced-features/listing-19-05/output.txt @@ -1,21 +1,22 @@ $ cargo run Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example) -error[E0499]: cannot borrow `*slice` as mutable more than once at a time - --> src/main.rs:6:30 +error[E0499]: cannot borrow `*values` as mutable more than once at a time +(エラー: 一度に2回以上、`*values`を可変で借用できません) + --> src/main.rs:6:31 | -1 | fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { - | - let's call the lifetime of this reference `'1` +1 | fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { + | - let's call the lifetime of this reference `'1` + | (この参照のライフタイムを`'1`とします) ... -6 | (&mut slice[..mid], &mut slice[mid..]) - | -------------------------^^^^^-------- - | | | | - | | | second mutable borrow occurs here +6 | (&mut values[..mid], &mut values[mid..]) + | --------------------------^^^^^^-------- + | | | | + | | | second mutable borrow occurs here + | | | (2回目の可変参照はここで発生します) | | first mutable borrow occurs here - | returning this value requires that `*slice` is borrowed for `'1` - -error: aborting due to previous error + | | (1回目の可変参照はここで発生します) + | returning this value requires that `*values` is borrowed for `'1` + | (この値を返すためには`*values`が`'1`の間借用されていることが必要です) For more information about this error, try `rustc --explain E0499`. -error: could not compile `unsafe-example`. - -To learn more, run the command again with --verbose. +error: could not compile `unsafe-example` (bin "unsafe-example") due to 1 previous error diff --git a/listings/ch19-advanced-features/listing-19-05/src/main.rs b/listings/ch19-advanced-features/listing-19-05/src/main.rs index c4b83effa..dabf63de1 100644 --- a/listings/ch19-advanced-features/listing-19-05/src/main.rs +++ b/listings/ch19-advanced-features/listing-19-05/src/main.rs @@ -1,10 +1,10 @@ // ANCHOR: here -fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { - let len = slice.len(); +fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { + let len = values.len(); assert!(mid <= len); - (&mut slice[..mid], &mut slice[mid..]) + (&mut values[..mid], &mut values[mid..]) } // ANCHOR_END: here diff --git a/listings/ch19-advanced-features/listing-19-06/Cargo.toml b/listings/ch19-advanced-features/listing-19-06/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-06/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-06/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-06/src/main.rs b/listings/ch19-advanced-features/listing-19-06/src/main.rs index f25cbf49d..3af21f761 100644 --- a/listings/ch19-advanced-features/listing-19-06/src/main.rs +++ b/listings/ch19-advanced-features/listing-19-06/src/main.rs @@ -1,9 +1,9 @@ // ANCHOR: here use std::slice; -fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { - let len = slice.len(); - let ptr = slice.as_mut_ptr(); +fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { + let len = values.len(); + let ptr = values.as_mut_ptr(); assert!(mid <= len); diff --git a/listings/ch19-advanced-features/listing-19-07/Cargo.toml b/listings/ch19-advanced-features/listing-19-07/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-07/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-07/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-07/src/main.rs b/listings/ch19-advanced-features/listing-19-07/src/main.rs index 0ab39ae1d..b4d6cdb7c 100644 --- a/listings/ch19-advanced-features/listing-19-07/src/main.rs +++ b/listings/ch19-advanced-features/listing-19-07/src/main.rs @@ -5,6 +5,6 @@ fn main() { let address = 0x01234usize; let r = address as *mut i32; - let slice: &[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) }; + let values: &[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) }; // ANCHOR_END: here } diff --git a/listings/ch19-advanced-features/listing-19-08/Cargo.toml b/listings/ch19-advanced-features/listing-19-08/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-08/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-08/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-08/src/main.rs b/listings/ch19-advanced-features/listing-19-08/src/main.rs index 8b56630c9..d3755040f 100644 --- a/listings/ch19-advanced-features/listing-19-08/src/main.rs +++ b/listings/ch19-advanced-features/listing-19-08/src/main.rs @@ -4,6 +4,7 @@ extern "C" { fn main() { unsafe { + // -3の絶対値は、Cによると{} println!("Absolute value of -3 according to C: {}", abs(-3)); } } diff --git a/listings/ch19-advanced-features/listing-19-09/Cargo.toml b/listings/ch19-advanced-features/listing-19-09/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-09/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-09/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-10/Cargo.toml b/listings/ch19-advanced-features/listing-19-10/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-10/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-10/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-11/Cargo.toml b/listings/ch19-advanced-features/listing-19-11/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/listing-19-11/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-11/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-11/src/main.rs b/listings/ch19-advanced-features/listing-19-11/src/main.rs index 885c1aa1d..ca3bcf171 100644 --- a/listings/ch19-advanced-features/listing-19-11/src/main.rs +++ b/listings/ch19-advanced-features/listing-19-11/src/main.rs @@ -1,9 +1,11 @@ unsafe trait Foo { // methods go here + // メソッドがここに来る } unsafe impl Foo for i32 { // method implementations go here + // メソッドの実装がここに来る } fn main() {} diff --git a/listings/ch19-advanced-features/listing-19-12/Cargo.toml b/listings/ch19-advanced-features/listing-19-12/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-12/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-12/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-13/Cargo.toml b/listings/ch19-advanced-features/listing-19-13/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-13/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-13/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-14/Cargo.toml b/listings/ch19-advanced-features/listing-19-14/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-14/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-14/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-14/src/main.rs b/listings/ch19-advanced-features/listing-19-14/src/main.rs index 7dea568d9..9111fbc55 100644 --- a/listings/ch19-advanced-features/listing-19-14/src/main.rs +++ b/listings/ch19-advanced-features/listing-19-14/src/main.rs @@ -1,6 +1,6 @@ use std::ops::Add; -#[derive(Debug, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] struct Point { x: i32, y: i32, diff --git a/listings/ch19-advanced-features/listing-19-15/Cargo.toml b/listings/ch19-advanced-features/listing-19-15/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-15/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-15/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-16/Cargo.toml b/listings/ch19-advanced-features/listing-19-16/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-16/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-16/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-16/src/main.rs b/listings/ch19-advanced-features/listing-19-16/src/main.rs index d854e287d..64d9b9ba3 100644 --- a/listings/ch19-advanced-features/listing-19-16/src/main.rs +++ b/listings/ch19-advanced-features/listing-19-16/src/main.rs @@ -11,18 +11,21 @@ struct Human; impl Pilot for Human { fn fly(&self) { + // こちら機長です。 println!("This is your captain speaking."); } } impl Wizard for Human { fn fly(&self) { + // 上がれ! println!("Up!"); } } impl Human { fn fly(&self) { + // *激しく腕を振る* println!("*waving arms furiously*"); } } diff --git a/listings/ch19-advanced-features/listing-19-17/Cargo.toml b/listings/ch19-advanced-features/listing-19-17/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-17/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-17/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-18/Cargo.toml b/listings/ch19-advanced-features/listing-19-18/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-18/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-18/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-19/Cargo.toml b/listings/ch19-advanced-features/listing-19-19/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-19/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-19/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-19/src/main.rs b/listings/ch19-advanced-features/listing-19-19/src/main.rs index 44affe0ee..10a011fde 100644 --- a/listings/ch19-advanced-features/listing-19-19/src/main.rs +++ b/listings/ch19-advanced-features/listing-19-19/src/main.rs @@ -6,16 +6,19 @@ struct Dog; impl Dog { fn baby_name() -> String { + // スポット String::from("Spot") } } impl Animal for Dog { fn baby_name() -> String { + // 子犬 String::from("puppy") } } fn main() { + // 赤ちゃん犬は{}と呼ばれる println!("A baby dog is called a {}", Dog::baby_name()); } diff --git a/listings/ch19-advanced-features/listing-19-20/Cargo.toml b/listings/ch19-advanced-features/listing-19-20/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-20/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-20/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-20/output.txt b/listings/ch19-advanced-features/listing-19-20/output.txt index 46c7dafa0..123884626 100644 --- a/listings/ch19-advanced-features/listing-19-20/output.txt +++ b/listings/ch19-advanced-features/listing-19-20/output.txt @@ -1,19 +1,22 @@ $ cargo run Compiling traits-example v0.1.0 (file:///projects/traits-example) -error[E0283]: type annotations needed +error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type +(エラー: 対応する`impl`型を指定せずにトレイト上の関連関数を呼び出すことはできません) --> src/main.rs:20:43 | 2 | fn baby_name() -> String; - | ------------------------- required by `Animal::baby_name` + | ------------------------- `Animal::baby_name` defined here + | (`Animal::baby_name`はここで定義されています) ... 20 | println!("A baby dog is called a {}", Animal::baby_name()); - | ^^^^^^^^^^^^^^^^^ cannot infer type + | ^^^^^^^^^^^^^^^^^ cannot call associated function of trait + | (トレイトの関連関数を呼び出すことができません) | - = note: cannot resolve `_: Animal` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0283`. -error: could not compile `traits-example`. +help: use the fully-qualified path to the only available implementation +(ヘルプ: 利用可能な実装のうち1つを指すフルパスを使用してください) + | +20 | println!("A baby dog is called a {}", ::baby_name()); + | +++++++ + -To learn more, run the command again with --verbose. +For more information about this error, try `rustc --explain E0790`. +error: could not compile `traits-example` (bin "traits-example") due to 1 previous error diff --git a/listings/ch19-advanced-features/listing-19-21/Cargo.toml b/listings/ch19-advanced-features/listing-19-21/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-21/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-21/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-22/Cargo.toml b/listings/ch19-advanced-features/listing-19-22/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-22/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-22/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-23/Cargo.toml b/listings/ch19-advanced-features/listing-19-23/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/listing-19-23/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-23/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-24/Cargo.toml b/listings/ch19-advanced-features/listing-19-24/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/listing-19-24/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-24/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-25/Cargo.toml b/listings/ch19-advanced-features/listing-19-25/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/listing-19-25/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-25/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-27/Cargo.toml b/listings/ch19-advanced-features/listing-19-27/Cargo.toml index 2bed56c36..b196f35b5 100644 --- a/listings/ch19-advanced-features/listing-19-27/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-27/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "functions-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-27/src/main.rs b/listings/ch19-advanced-features/listing-19-27/src/main.rs index 91b2cf04b..20ab62b18 100644 --- a/listings/ch19-advanced-features/listing-19-27/src/main.rs +++ b/listings/ch19-advanced-features/listing-19-27/src/main.rs @@ -9,5 +9,6 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { fn main() { let answer = do_twice(add_one, 5); + // 答えは: {} println!("The answer is: {}", answer); } diff --git a/listings/ch19-advanced-features/listing-19-28/Cargo.toml b/listings/ch19-advanced-features/listing-19-28/Cargo.toml index 1829b0fa6..9218091c8 100644 --- a/listings/ch19-advanced-features/listing-19-28/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-28/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "macros-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-30/Cargo.toml b/listings/ch19-advanced-features/listing-19-30/Cargo.toml index 5a93a685c..c6fb92087 100644 --- a/listings/ch19-advanced-features/listing-19-30/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-30/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "hello_macro" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-31/hello_macro/Cargo.toml b/listings/ch19-advanced-features/listing-19-31/hello_macro/Cargo.toml index 5a93a685c..c6fb92087 100644 --- a/listings/ch19-advanced-features/listing-19-31/hello_macro/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-31/hello_macro/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "hello_macro" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/Cargo.toml b/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/Cargo.toml index 168cbae53..aa076ac48 100644 --- a/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "hello_macro_derive" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [lib] proc-macro = true diff --git a/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/src/lib.rs b/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/src/lib.rs index 8757a2f77..dddbf62c8 100644 --- a/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/src/lib.rs +++ b/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/src/lib.rs @@ -1,5 +1,3 @@ -extern crate proc_macro; - use proc_macro::TokenStream; use quote::quote; use syn; diff --git a/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/src/lib.rs.bak b/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/src/lib.rs.bak new file mode 100644 index 000000000..8757a2f77 --- /dev/null +++ b/listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/src/lib.rs.bak @@ -0,0 +1,17 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::quote; +use syn; + +#[proc_macro_derive(HelloMacro)] +pub fn hello_macro_derive(input: TokenStream) -> TokenStream { + // 操作可能な構文木としてのRustコードの表現を構築する + // Construct a representation of Rust code as a syntax tree + // that we can manipulate + let ast = syn::parse(input).unwrap(); + + // トレイトの実装内容を構築 + // Build the trait implementation + impl_hello_macro(&ast) +} diff --git a/listings/ch19-advanced-features/listing-19-33/hello_macro/Cargo.toml b/listings/ch19-advanced-features/listing-19-33/hello_macro/Cargo.toml index 5a93a685c..c6fb92087 100644 --- a/listings/ch19-advanced-features/listing-19-33/hello_macro/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-33/hello_macro/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "hello_macro" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-19-33/hello_macro/hello_macro_derive/Cargo.toml b/listings/ch19-advanced-features/listing-19-33/hello_macro/hello_macro_derive/Cargo.toml index 168cbae53..aa076ac48 100644 --- a/listings/ch19-advanced-features/listing-19-33/hello_macro/hello_macro_derive/Cargo.toml +++ b/listings/ch19-advanced-features/listing-19-33/hello_macro/hello_macro_derive/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "hello_macro_derive" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [lib] proc-macro = true diff --git a/listings/ch19-advanced-features/listing-19-33/hello_macro/hello_macro_derive/src/lib.rs b/listings/ch19-advanced-features/listing-19-33/hello_macro/hello_macro_derive/src/lib.rs index 591f0c359..dac6c98f6 100644 --- a/listings/ch19-advanced-features/listing-19-33/hello_macro/hello_macro_derive/src/lib.rs +++ b/listings/ch19-advanced-features/listing-19-33/hello_macro/hello_macro_derive/src/lib.rs @@ -1,5 +1,3 @@ -extern crate proc_macro; - use proc_macro::TokenStream; use quote::quote; use syn; diff --git a/listings/ch19-advanced-features/no-listing-01-unsafe-fn/Cargo.toml b/listings/ch19-advanced-features/no-listing-01-unsafe-fn/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/no-listing-01-unsafe-fn/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-01-unsafe-fn/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/Cargo.toml b/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt b/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt index e7a028e35..f1333e875 100644 --- a/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt +++ b/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt @@ -1,17 +1,21 @@ $ cargo run Compiling traits-example v0.1.0 (file:///projects/traits-example) error[E0277]: `Point` doesn't implement `std::fmt::Display` - --> src/main.rs:20:6 +(エラー: `Point`は`std::fmt::Display`を実装していません) + --> src/main.rs:20:23 | 20 | impl OutlinePrint for Point {} - | ^^^^^^^^^^^^ `Point` cannot be formatted with the default formatter + | ^^^^^ `Point` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `Point` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead - -error: aborting due to previous error +note: required by a bound in `OutlinePrint` +(注釈: `OutlinePrint`境界によって要求されています) + --> src/main.rs:3:21 + | +3 | trait OutlinePrint: fmt::Display { + | ^^^^^^^^^^^^ required by this bound in `OutlinePrint` + | (`OutlinePrint`のこの境界によって要求されています) For more information about this error, try `rustc --explain E0277`. -error: could not compile `traits-example`. - -To learn more, run the command again with --verbose. +error: could not compile `traits-example` (bin "traits-example") due to 1 previous error diff --git a/listings/ch19-advanced-features/no-listing-03-impl-display-for-point/Cargo.toml b/listings/ch19-advanced-features/no-listing-03-impl-display-for-point/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/no-listing-03-impl-display-for-point/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-03-impl-display-for-point/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-04-kilometers-alias/Cargo.toml b/listings/ch19-advanced-features/no-listing-04-kilometers-alias/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/no-listing-04-kilometers-alias/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-04-kilometers-alias/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-05-write-trait/Cargo.toml b/listings/ch19-advanced-features/no-listing-05-write-trait/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/no-listing-05-write-trait/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-05-write-trait/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-06-result-alias/Cargo.toml b/listings/ch19-advanced-features/no-listing-06-result-alias/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/no-listing-06-result-alias/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-06-result-alias/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-06-result-alias/src/lib.rs b/listings/ch19-advanced-features/no-listing-06-result-alias/src/lib.rs index c53a927e3..573559934 100644 --- a/listings/ch19-advanced-features/no-listing-06-result-alias/src/lib.rs +++ b/listings/ch19-advanced-features/no-listing-06-result-alias/src/lib.rs @@ -13,5 +13,3 @@ pub trait Write { fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()>; } // ANCHOR_END: there - -fn main() {} diff --git a/listings/ch19-advanced-features/no-listing-07-never-type/Cargo.toml b/listings/ch19-advanced-features/no-listing-07-never-type/Cargo.toml index 1e3df0242..52395a587 100644 --- a/listings/ch19-advanced-features/no-listing-07-never-type/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-07-never-type/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "traits-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-07-never-type/src/lib.rs b/listings/ch19-advanced-features/no-listing-07-never-type/src/lib.rs index 236224186..f0f7acac2 100644 --- a/listings/ch19-advanced-features/no-listing-07-never-type/src/lib.rs +++ b/listings/ch19-advanced-features/no-listing-07-never-type/src/lib.rs @@ -6,5 +6,3 @@ fn bar() -> ! { // ANCHOR: here } // ANCHOR_END: here - -fn main() {} diff --git a/listings/ch19-advanced-features/no-listing-08-match-arms-different-types/Cargo.toml b/listings/ch19-advanced-features/no-listing-08-match-arms-different-types/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/no-listing-08-match-arms-different-types/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-08-match-arms-different-types/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-09-unwrap-definition/Cargo.toml b/listings/ch19-advanced-features/no-listing-09-unwrap-definition/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/no-listing-09-unwrap-definition/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-09-unwrap-definition/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-10-loop-returns-never/Cargo.toml b/listings/ch19-advanced-features/no-listing-10-loop-returns-never/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/no-listing-10-loop-returns-never/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-10-loop-returns-never/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-11-cant-create-str/Cargo.toml b/listings/ch19-advanced-features/no-listing-11-cant-create-str/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/no-listing-11-cant-create-str/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-11-cant-create-str/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-12-generic-fn-definition/Cargo.toml b/listings/ch19-advanced-features/no-listing-12-generic-fn-definition/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/no-listing-12-generic-fn-definition/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-12-generic-fn-definition/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-13-generic-implicit-sized-bound/Cargo.toml b/listings/ch19-advanced-features/no-listing-13-generic-implicit-sized-bound/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/no-listing-13-generic-implicit-sized-bound/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-13-generic-implicit-sized-bound/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-14-generic-maybe-sized/Cargo.toml b/listings/ch19-advanced-features/no-listing-14-generic-maybe-sized/Cargo.toml index 9b4ee689b..a2ae20c77 100644 --- a/listings/ch19-advanced-features/no-listing-14-generic-maybe-sized/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-14-generic-maybe-sized/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "types-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-15-map-closure/Cargo.toml b/listings/ch19-advanced-features/no-listing-15-map-closure/Cargo.toml index 2bed56c36..b196f35b5 100644 --- a/listings/ch19-advanced-features/no-listing-15-map-closure/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-15-map-closure/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "functions-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-16-map-function/Cargo.toml b/listings/ch19-advanced-features/no-listing-16-map-function/Cargo.toml index 2bed56c36..b196f35b5 100644 --- a/listings/ch19-advanced-features/no-listing-16-map-function/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-16-map-function/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "functions-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-17-map-initializer/Cargo.toml b/listings/ch19-advanced-features/no-listing-17-map-initializer/Cargo.toml index 2bed56c36..b196f35b5 100644 --- a/listings/ch19-advanced-features/no-listing-17-map-initializer/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-17-map-initializer/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "functions-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-18-returns-closure/Cargo.toml b/listings/ch19-advanced-features/no-listing-18-returns-closure/Cargo.toml index 2bed56c36..b196f35b5 100644 --- a/listings/ch19-advanced-features/no-listing-18-returns-closure/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-18-returns-closure/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "functions-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-18-returns-closure/output.txt b/listings/ch19-advanced-features/no-listing-18-returns-closure/output.txt index 2d4be9b0a..bc736bd68 100644 --- a/listings/ch19-advanced-features/no-listing-18-returns-closure/output.txt +++ b/listings/ch19-advanced-features/no-listing-18-returns-closure/output.txt @@ -1,30 +1,20 @@ $ cargo build Compiling functions-example v0.1.0 (file:///projects/functions-example) -error[E0277]: the size for values of type `(dyn std::ops::Fn(i32) -> i32 + 'static)` cannot be known at compilation time +error[E0746]: return type cannot have an unboxed trait object --> src/lib.rs:1:25 | 1 | fn returns_closure() -> dyn Fn(i32) -> i32 { | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn(i32) -> i32 + 'static)` - = note: to learn more, visit - = note: the return type of a function must have a statically known size - -error[E0308]: mismatched types - --> src/lib.rs:2:5 +help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type | -1 | fn returns_closure() -> dyn Fn(i32) -> i32 { - | ------------------ expected `(dyn std::ops::Fn(i32) -> i32 + 'static)` because of return type -2 | |x| x + 1 - | ^^^^^^^^^ expected trait `std::ops::Fn`, found closure +1 | fn returns_closure() -> impl Fn(i32) -> i32 { + | ~~~~ +help: box the return type, and wrap all of the returned values in `Box::new` + | +1 ~ fn returns_closure() -> Box i32> { +2 ~ Box::new(|x| x + 1) | - = note: expected trait object `(dyn std::ops::Fn(i32) -> i32 + 'static)` - found closure `[closure@src/lib.rs:2:5: 2:14]` - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. -error: could not compile `functions-example`. -To learn more, run the command again with --verbose. +For more information about this error, try `rustc --explain E0746`. +error: could not compile `functions-example` (lib) due to 1 previous error diff --git a/listings/ch19-advanced-features/no-listing-19-returns-closure-trait-object/Cargo.toml b/listings/ch19-advanced-features/no-listing-19-returns-closure-trait-object/Cargo.toml index 2bed56c36..b196f35b5 100644 --- a/listings/ch19-advanced-features/no-listing-19-returns-closure-trait-object/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-19-returns-closure-trait-object/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "functions-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/hello_macro/Cargo.toml b/listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/hello_macro/Cargo.toml index 5a93a685c..c6fb92087 100644 --- a/listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/hello_macro/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/hello_macro/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "hello_macro" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/pancakes/Cargo.toml b/listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/pancakes/Cargo.toml index 4b6c267b4..3ad910862 100644 --- a/listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/pancakes/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/pancakes/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "pancakes" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] hello_macro = { path = "../hello_macro" } \ No newline at end of file diff --git a/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/Cargo.toml b/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/Cargo.toml index 5a93a685c..c6fb92087 100644 --- a/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "hello_macro" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/hello_macro_derive/Cargo.toml b/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/hello_macro_derive/Cargo.toml index 168cbae53..aa076ac48 100644 --- a/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/hello_macro_derive/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/hello_macro_derive/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "hello_macro_derive" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [lib] proc-macro = true diff --git a/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/hello_macro_derive/src/lib.rs b/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/hello_macro_derive/src/lib.rs index 7a3279d86..5e0b96c27 100644 --- a/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/hello_macro_derive/src/lib.rs +++ b/listings/ch19-advanced-features/no-listing-21-pancakes/hello_macro/hello_macro_derive/src/lib.rs @@ -1,5 +1,3 @@ -extern crate proc_macro; - use proc_macro::TokenStream; use quote::quote; use syn; diff --git a/listings/ch19-advanced-features/no-listing-21-pancakes/pancakes/Cargo.toml b/listings/ch19-advanced-features/no-listing-21-pancakes/pancakes/Cargo.toml index cc0addaa4..cb3a98c3a 100644 --- a/listings/ch19-advanced-features/no-listing-21-pancakes/pancakes/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-21-pancakes/pancakes/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "pancakes" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] hello_macro = { path = "../hello_macro" } diff --git a/listings/ch19-advanced-features/listing-13-21-reproduced/Cargo.lock b/listings/ch19-advanced-features/no-listing-22-iterator-on-counter/Cargo.lock similarity index 100% rename from listings/ch19-advanced-features/listing-13-21-reproduced/Cargo.lock rename to listings/ch19-advanced-features/no-listing-22-iterator-on-counter/Cargo.lock diff --git a/listings/ch19-advanced-features/listing-13-21-reproduced/Cargo.toml b/listings/ch19-advanced-features/no-listing-22-iterator-on-counter/Cargo.toml similarity index 50% rename from listings/ch19-advanced-features/listing-13-21-reproduced/Cargo.toml rename to listings/ch19-advanced-features/no-listing-22-iterator-on-counter/Cargo.toml index 4eb29e80c..9e103f3eb 100644 --- a/listings/ch19-advanced-features/listing-13-21-reproduced/Cargo.toml +++ b/listings/ch19-advanced-features/no-listing-22-iterator-on-counter/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "counter" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/listing-13-21-reproduced/src/lib.rs b/listings/ch19-advanced-features/no-listing-22-iterator-on-counter/src/lib.rs similarity index 96% rename from listings/ch19-advanced-features/listing-13-21-reproduced/src/lib.rs rename to listings/ch19-advanced-features/no-listing-22-iterator-on-counter/src/lib.rs index b71b54fbc..04c7f38f5 100644 --- a/listings/ch19-advanced-features/listing-13-21-reproduced/src/lib.rs +++ b/listings/ch19-advanced-features/no-listing-22-iterator-on-counter/src/lib.rs @@ -23,5 +23,3 @@ impl Iterator for Counter { } } } - -fn main() {} diff --git a/listings/ch19-advanced-features/output-only-01-missing-unsafe/Cargo.toml b/listings/ch19-advanced-features/output-only-01-missing-unsafe/Cargo.toml index aabe3bdf5..3e8a29201 100644 --- a/listings/ch19-advanced-features/output-only-01-missing-unsafe/Cargo.toml +++ b/listings/ch19-advanced-features/output-only-01-missing-unsafe/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "unsafe-example" version = "0.1.0" -authors = ["Your Name "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/listings/ch19-advanced-features/output-only-01-missing-unsafe/output.txt b/listings/ch19-advanced-features/output-only-01-missing-unsafe/output.txt index bfe082a8b..36e1175bb 100644 --- a/listings/ch19-advanced-features/output-only-01-missing-unsafe/output.txt +++ b/listings/ch19-advanced-features/output-only-01-missing-unsafe/output.txt @@ -1,6 +1,7 @@ $ cargo run Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example) error[E0133]: call to unsafe function is unsafe and requires unsafe function or block +(エラー: unsafe関数の呼び出しはunsafeであり、unsafeな関数かブロックが必要です) --> src/main.rs:4:5 | 4 | dangerous(); @@ -8,9 +9,5 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to previous error - For more information about this error, try `rustc --explain E0133`. -error: could not compile `unsafe-example`. - -To learn more, run the command again with --verbose. +error: could not compile `unsafe-example` (bin "unsafe-example") due to 1 previous error diff --git a/src/ch19-00-advanced-features.md b/src/ch19-00-advanced-features.md index 48190a7a7..ce33baa36 100644 --- a/src/ch19-00-advanced-features.md +++ b/src/ch19-00-advanced-features.md @@ -7,16 +7,16 @@ 今までに、Rustプログラミング言語の最もよく使われる部分を学んできました。第20章でもう1つ別のプロジェクトを行う前に、 -時折遭遇する言語の側面をいくつか見ましょう。この章は、Rustを使用する際に知らないことに遭遇した時に参考にすることができます。 -この章で使用することを学ぶ機能は、かなり限定的な場面でしか役に立ちません。あまり頻繁には手を伸ばすことがない可能性はありますが、 +時折遭遇するが、毎日は使わないような言語の側面をいくつか見ましょう。この章は、知らないことに遭遇した時に参考にすることができます。 +ここで扱う機能は、かなり限定的な場面でしか役に立ちません。あまり頻繁には手を伸ばすことがない可能性はありますが、 Rustが提供しなければならない機能全ての概要を確かに把握してもらいたいのです。 静的解析は原理的に保守的なので、unsafe Rustが存在します。コードが保証を保持しているかコンパイラが決定しようとする際、 -なんらかの不正なプログラムを受け入れるよりも合法なプログラムを拒否したほうがいいのです。コードは大丈夫かもしれないけれど、 -コンパイラにわかる範囲ではダメなのです!このような場合、unsafeコードを使用してコンパイラに「信じて!何をしているかわかってるよ」と教えられます。 -欠点は、自らのリスクで使用することです: unsafeコードを誤って使用したら、 +なんらかの不正なプログラムを受け入れるよりも合法なプログラムを拒否したほうがいいのです。コードは大丈夫*かもしれない*けれど、 +Rustコンパイラが大丈夫と確信するために十分な情報を持っていなければ、コンパイラはそのコードを拒否するでしょう。 +このような場合、unsafeコードを使用してコンパイラに「信じて!何をしているかわかってるよ」と教えられます。 +しかし注意してください、unsafe Rustは自己責任で使用するものです: unsafeコードを誤って使用したら、 nullポインタ参照外しなどのメモリ非安全に起因する問題が起こることもあるのです。 unsafe Rustに切り替えるには、`unsafe`キーワードを使用し、それからunsafeコードを保持する新しいブロックを開始してください。 -safe Rustでは行えない4つの行動をunsafe Rustでは行え、これは*unsafe superpowers*と呼ばれます。 +safe Rustでは行えない5つの行動をunsafe Rustでは行うことができ、これは*unsafe superpowers*と呼ばれます。 そのsuperpowerには、以下の能力が含まれています: * 生ポインタを参照外しすること * unsafeな関数やメソッドを呼ぶこと * 可変で静的な変数にアクセスしたり変更すること * unsafeなトレイトを実装すること +* `union`のフィールドにアクセスすること `unsafe`は、借用チェッカーや他のRustの安全性チェックを無効にしないことを理解するのは重要なことです: -unsafeコードで参照を使用しても、チェックはされます。`unsafe`キーワードにより、これら4つの機能にアクセスできるようになり、 +unsafeコードで参照を使用しても、チェックはされます。`unsafe`キーワードにより、これら5つの機能にアクセスできるようになり、 その場合、コンパイラによってこれらのメモリ安全性は確認されないのです。unsafeブロック内でも、ある程度の安全性は得られます。 -人間は失敗をするもので、間違いも起きますが、これら4つのunsafeな処理を`unsafe`で注釈されたブロックに入れる必要があることで、 +人間は失敗をするもので、間違いも起きますが、これら5つのunsafeな処理を`unsafe`で注釈されたブロックに入れる必要があることで、 メモリ安全性に関するどんなエラーも`unsafe`ブロック内にあるに違いないと知ります。`unsafe`ブロックは小さくしてください; メモリのバグを調査するときに感謝することになるでしょう。 @@ -128,11 +132,11 @@ unsafeなコードをできるだけ分離するために、unsafeなコード 安全な抽象を使用することは、安全だからです。 -4つのunsafeなsuperpowerを順に見ていきましょう。unsafeなコードへの安全なインターフェイスを提供する一部の抽象化にも目を向けます。 +5つのunsafeなsuperpowerを順に見ていきましょう。unsafeなコードへの安全なインターフェイスを提供する一部の抽象化にも目を向けます。 -第4章の「ダングリング参照」節で、コンパイラは、参照が常に有効であることを保証することに触れました。 +第4章の[「宙に浮いた参照」][dangling-references]節で、コンパイラは、参照が常に有効であることを保証することに触れました。 unsafe Rustには参照に類似した*生ポインタ*と呼ばれる2つの新しい型があります。参照同様、 生ポインタも不変や可変になり得て、それぞれ`*const T`と`*mut T`と表記されます。このアスタリスクは、参照外し演算子ではありません; 型名の一部です。生ポインタの文脈では、*不変*は、参照外し後に直接ポインタに代入できないことを意味します。 @@ -163,7 +168,7 @@ Different from references and smart pointers, raw pointers: @@ -191,10 +196,7 @@ references. リスト19-1は、参照から不変と可変な生ポインタを生成する方法を示しています。 ```rust -let mut num = 5; - -let r1 = &num as *const i32; -let r2 = &mut num as *mut i32; +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-01/src/main.rs:here}} ``` -次に、有効であることが確信できない生ポインタを生成します。リスト19-2は、メモリの任意の箇所を指す生ポインタの生成法を示しています。 +これを示すために、次は、有効であることが確信できない生ポインタを生成します。リスト19-2は、メモリの任意の箇所を指す生ポインタの生成法を示しています。 任意のメモリを使用しようとすることは未定義です: そのアドレスにデータがある可能性もあるし、ない可能性もあり、 コンパイラがコードを最適化してメモリアクセスがなくなる可能性もあるし、プログラムがセグメンテーションフォールトでエラーになる可能性もあります。 通常、このようなコードを書くいい理由はありませんが、可能ではあります。 ```rust -let address = 0x012345usize; -let r = address as *const i32; +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-02/src/main.rs:here}} ``` -これらの危険がありながら、一体何故生ポインタを使うのでしょうか?主なユースケースの1つは、次の節「unsafeな関数やメソッドを呼ぶ」で見るように、 +これらの危険がありながら、一体何故生ポインタを使うのでしょうか?主なユースケースの1つは、 +次の節[「unsafeな関数やメソッドを呼ぶ」](#unsafeな関数やメソッドを呼ぶ)で見るように、 Cコードとのインターフェイスです。別のユースケースは、借用チェッカーには理解できない安全な抽象を構成する時です。 unsafeな関数を導入し、それからunsafeコードを使用する安全な抽象の例に目を向けます。 @@ -323,17 +319,17 @@ unsafeな関数を導入し、それからunsafeコードを使用する安全 ### unsafeな関数やメソッドを呼ぶ -unsafeブロックが必要になる2番目の処理は、unsafe関数の呼び出しです。unsafeな関数やメソッドも見た目は、 +unsafeブロック内で行うことができる2番目の処理は、unsafe関数の呼び出しです。unsafeな関数やメソッドも見た目は、 普通の関数やメソッドと全く同じですが、残りの定義の前に追加の`unsafe`があります。この文脈での`unsafe`キーワードは、 この関数を呼ぶ際に保持しておく必要のある要求が関数にあることを示唆します。コンパイラには、 この要求を満たしているか保証できないからです。`unsafe`ブロックでunsafeな関数を呼び出すことで、 @@ -347,11 +343,7 @@ body: こちらは、本体で何もしない`dangerous`というunsafeな関数です: ```rust -unsafe fn dangerous() {} - -unsafe { - dangerous(); -} +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-01-unsafe-fn/src/main.rs:here}} ``` - | -4 | dangerous(); - | ^^^^^^^^^^^ call to unsafe function +```console +{{#include ../listings/ch19-advanced-features/output-only-01-missing-unsafe/output.txt}} ``` -`dangerous`への呼び出しの周りに`unsafe`ブロックを挿入することで、コンパイラに関数のドキュメンテーションを読み、 +`unsafe`ブロックを使うことで、コンパイラに関数のドキュメンテーションを読み、 適切に使用する方法を理解したことをアサートし、関数の契約を満たしていると実証しました。 関数がunsafeなコードを含んでいるだけで関数全体をunsafeでマークする必要があることにはなりません。 事実、安全な関数でunsafeなコードをラップすることは一般的な抽象化です。例として、 -なんらかのunsafeコードが必要になる標準ライブラリの関数`split_at_mut`を学び、その実装方法を探究しましょう。 +なんらかのunsafeコードが必要になる標準ライブラリの`split_at_mut`関数を学びましょう。 +どのように実装することができるのかを探究します。 この安全なメソッドは、可変なスライスに定義されています: スライスを1つ取り、引数で与えられた添え字でスライスを分割して2つにします。 リスト19-4は、`split_at_mut`の使用法を示しています。 ```rust -let mut v = vec![1, 2, 3, 4, 5, 6]; - -let r = &mut v[..]; - -let (a, b) = r.split_at_mut(3); - -assert_eq!(a, &mut [1, 2, 3]); -assert_eq!(b, &mut [4, 5, 6]); +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-04/src/main.rs:here}} ``` この関数はまず、スライスの全体の長さを得ます。それから引数で与えられた添え字が長さ以下であるかを確認してスライス内にあることをアサートします。 -このアサートは、スライスを分割する添え字よりも大きい添え字を渡したら、その添え字を使用しようとする前に関数がパニックすることを意味します。 +このアサートは、スライスを分割するために長さよりも大きい添え字を渡したら、その添え字を使用しようとする前に関数がパニックすることを意味します。 - | -6 | (&mut slice[..mid], - | ----- first mutable borrow occurs here -7 | &mut slice[mid..]) - | ^^^^^ second mutable borrow occurs here -8 | } - | - first borrow ends here +```console +{{#include ../listings/ch19-advanced-features/listing-19-05/output.txt}} ``` -第4章の「スライス型」節から、スライスはなんらかのデータへのポインタとスライスの長さであることを思い出してください。 +第4章の[「スライス型」][the-slice-type]節から、スライスはなんらかのデータへのポインタとスライスの長さであることを思い出してください。 `len`メソッドを使用してスライスの長さを得て、`as_mut_ptr`メソッドを使用してスライスの生ポインタにアクセスしています。 この場合、`i32`値の可変スライスがあるので、`as_mut_ptr`は型`*mut i32`の生ポインタを返し、これを変数`ptr`に格納しました。 @@ -557,7 +509,7 @@ in the variable `ptr`. We keep the assertion that the `mid` index is within the slice. Then we get to the unsafe code: the `slice::from_raw_parts_mut` function takes a raw pointer and a length, and it creates a slice. We use this function to create a slice -that starts from `ptr` and is `mid` items long. Then we call the `offset` +that starts from `ptr` and is `mid` items long. Then we call the `add` method on `ptr` with `mid` as an argument to get a raw pointer that starts at `mid`, and we create a slice using that pointer and the remaining number of items after `mid` as the length. @@ -565,15 +517,15 @@ items after `mid` as the length. `mid`添え字がスライス内にあるかというアサートを残しています。そして、unsafeコードに到達します: `slice::from_raw_parts_mut`関数は、生ポインタと長さを取り、スライスを生成します。この関数を使って、 -`ptr`から始まり、`mid`の長さのスライスを生成しています。それから`ptr`に`mid`を引数として`offset`メソッドを呼び出し、 +`ptr`から始まり、`mid`の長さのスライスを生成しています。それから`ptr`に`mid`を引数として`add`メソッドを呼び出し、 `mid`で始まる生ポインタを得て、そのポインタと`mid`の後の残りの要素数を長さとして使用してスライスを生成しています。 関数`slice::from_raw_parts_mut`は、unsafeです。何故なら、生ポインタを取り、このポインタが有効であることを信用しなければならないからです。 -生ポインタの`offset`メソッドもunsafeです。オフセット位置もまた有効なポインタであることを信用しなければならないからです。 -故に、`slice::from_raw_parts_mut`と`offset`を呼べるように、その呼び出しの周りに`unsafe`ブロックを置かなければならなかったのです。 +生ポインタの`add`メソッドもunsafeです。オフセット位置もまた有効なポインタであることを信用しなければならないからです。 +故に、`slice::from_raw_parts_mut`と`add`を呼べるように、その呼び出しの周りに`unsafe`ブロックを置かなければならなかったのです。 コードを眺めて`mid`が`len`以下でなければならないとするアサートを追加することで、 `unsafe`ブロック内で使用されている生ポインタが全てスライス内のデータへの有効なポインタであることがわかります。 これは、受け入れられ、適切な`unsafe`の使用法です。 @@ -602,21 +554,14 @@ data this function has access to. 対照的に、リスト19-7の`slice::from_raw_parts_mut`の使用は、スライスが使用されるとクラッシュする可能性が高いでしょう。 -このコードは任意のメモリアドレスを取り、10,000要素の長さのスライスを生成します: +このコードは任意のメモリアドレスを取り、10,000要素の長さのスライスを生成します。 ```rust -use std::slice; - -let address = 0x012345usize; -let r = address as *mut i32; - -let slice = unsafe { - slice::from_raw_parts_mut(r, 10000) -}; +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-07/src/main.rs:here}} ``` この任意の場所のメモリは所有していなく、このコードが生成するスライスに有効な`i32`値が含まれる保証もありません。 -`slice`を有効なスライスであるかのように使用しようとすると、未定義動作に陥ります。 +`values`を有効なスライスであるかのように使用しようとすると、未定義動作に陥ります。 -今までずっと、*グローバル変数*について語りませんでした。グローバル変数をRustは確かにサポートしていますが、 +この本では、まだ*グローバル変数*について語っていませんでした。グローバル変数をRustは確かにサポートしていますが、 Rustの所有権規則で問題になることもあります。2つのスレッドが同じ可変なグローバル変数にアクセスしていたら、 データ競合を起こすこともあります。 @@ -785,12 +721,7 @@ Rustでは、グローバル変数は、*static*(静的)変数と呼ばれます ファイル名: src/main.rs ```rust -static HELLO_WORLD: &str = "Hello, world!"; - -fn main() { - // 名前は: {} - println!("name is: {}", HELLO_WORLD); -} +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-09/src/main.rs}} ``` - -静的変数は、定数に似ています。定数については、第3章の「変数と定数の違い」節で議論しました。 -静的変数の名前は慣習で`SCREAMING_SNAKE_CASE`(`直訳`: 叫ぶスネークケース)になり、変数の型を注釈し*なければなりません*。 -この例では`&'static str`です。静的変数は、`'static`ライフタイムの参照のみ格納でき、 -これは、Rustコンパイラがライフタイムを推量できることを意味します; 明示的に注釈する必要はありません。 +[“Differences Between Variables and +Constants”][differences-between-variables-and-constants] section +in Chapter 3. The names of static variables are in `SCREAMING_SNAKE_CASE` by +convention. Static variables can only store references with the `'static` +lifetime, which means the Rust compiler can figure out the lifetime and we +aren’t required to annotate it explicitly. Accessing an immutable static +variable is safe. +--> + +静的変数は、定数に似ています。定数については、第3章の[「変数と定数の違い」][differences-between-variables-and-constants]節で議論しました。 +静的変数の名前は慣習で`SCREAMING_SNAKE_CASE`(`直訳`: 叫ぶスネークケース)になります。 +静的変数は`'static`ライフタイムの参照のみ格納でき、 +これは、Rustコンパイラがライフタイムを推量でき、明示的に注釈する必要はないことを意味します。 不変で静的な変数にアクセスすることは安全です。 - -定数と不変で静的な変数は、類似して見える可能性がありますが、微妙な差異は、 -静的変数の値は固定されたメモリアドレスになることです。値を使用すると、常に同じデータにアクセスします。 -一方、定数は使用される度にデータを複製させることができます。 - - -定数と静的変数の別の違いは、静的変数は可変にもなることです。可変で静的な変数にアクセスし変更することは、unsafeです。 +定数と不変で静的な変数との微妙な差異は、 +静的変数の値は固定されたメモリアドレスになることです。値を使用すると、常に同じデータにアクセスします。 +一方、定数は使用される度にデータを複製させることができます。 +別の違いは、静的変数は可変にもなることです。可変で静的な変数にアクセスし変更することは、unsafeです。 リスト19-10は、`COUNTER`という可変で静的な変数を宣言し、アクセスし、変更する方法を表示しています。 -`unsafe`でのみ動く最後の行動は、unsafeなトレイトを実装することです。少なくとも、1つのメソッドにコンパイラが確かめられないなんらかの不変条件があると、 -トレイトはunsafeになります。`trait`の前に`unsafe`キーワードを追加し、トレイトの実装も`unsafe`でマークすることで、 -トレイトが`unsafe`であると宣言できます。リスト19-11のようにですね。 +`unsafe`を使用することで、unsafeなトレイトを実装することができます。トレイトは、 +そのメソッドのうち少なくとも1つにコンパイラが確かめられないなんらかの不変条件があると、 +unsafeになります。`trait`の前に`unsafe`キーワードを追加し、トレイトの実装も`unsafe`でマークすることで、 +トレイトが`unsafe`であると宣言します。リスト19-11のようにですね。 ```rust -unsafe trait Foo { - // methods go here - // メソッドがここに来る -} - -unsafe impl Foo for i32 { - // method implementations go here - // メソッドの実装がここに来る -} +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-11/src/main.rs}} ``` - -例として、第16章の「`Sync`と`Send`トレイトで拡張可能な並行性」節で議論した`Sync`と`Send`マーカートレイトを思い出してください: +[“Extensible Concurrency with the `Sync` and `Send` +Traits”][extensible-concurrency-with-the-sync-and-send-traits] +section in Chapter 16: the compiler implements these traits automatically if +our types are composed entirely of `Send` and `Sync` types. If we implement a +type that contains a type that is not `Send` or `Sync`, such as raw pointers, +and we want to mark that type as `Send` or `Sync`, we must use `unsafe`. Rust +can’t verify that our type upholds the guarantees that it can be safely sent +across threads or accessed from multiple threads; therefore, we need to do +those checks manually and indicate as such with `unsafe`. +--> + +例として、第16章の[「`Sync`と`Send`トレイトで拡張可能な並行性」][extensible-concurrency-with-the-sync-and-send-traits]節で議論した`Sync`と`Send`マーカートレイトを思い出してください: 型が完全に`Send`と`Sync`型だけで構成されていたら、コンパイラはこれらのトレイトを自動的に実装します。 生ポインタなどの`Send`や`Sync`でない型を含む型を実装し、その型を`Send`や`Sync`でマークしたいなら、 `unsafe`を使用しなければなりません。コンパイラは、型がスレッド間を安全に送信できたり、 複数のスレッドから安全にアクセスできるという保証を保持しているか確かめられません; 故に、そのチェックを手動で行い、 `unsafe`でそのように示唆する必要があります。 + + +### 共用体のフィールドにアクセスする + + + +`unsafe`でのみ動く最後の行動は、*共用体*のフィールドへのアクセスです。 +`union`は`struct`と似ていますが、宣言されたフィールドのうち、特定のインスタンスに対しては1つだけが同時に使用されます。 +共用体は主に、Cコードの共用体とのインターフェースとして使用されます。 +Rustは共用体インスタンスに現在保管されているデータの型を保証することができないので、 +共用体フィールドへのアクセスはunsafeになっています。 +共用体については[Rust Reference][reference]でさらに深く学ぶことができます。 + @@ -962,14 +891,34 @@ manually and indicate as such with `unsafe`. ### いつunsafeコードを使用するべきか -`unsafe`を使って議論したばかりの4つの行動(強大な力)のうちの1つを行うのは間違っていたり、認められさえもしないものではありません。 +`unsafe`を使って議論したばかりの5つの行動(強大な力)のうちの1つを行うのは間違っていたり、認められさえもしないものではありません。 ですが、`unsafe`コードを正しくするのは、より巧妙なことでしょう。コンパイラがメモリ安全性を保持する手助けをできないからです。 -`unsafe`コードを使用する理由があるなら、そうすることができ、明示的に`unsafe`注釈をすることで問題が起きたら、 +`unsafe`コードを使用する理由があるなら、そうすることができ、明示的に`unsafe`注釈をすることで問題が起きたときに、 その原因を追求するのが容易になります。 + + + +[dangling-references]: +ch04-02-references-and-borrowing.html#宙に浮いた参照 +[differences-between-variables-and-constants]: +ch03-01-variables-and-mutability.html#定数 +[extensible-concurrency-with-the-sync-and-send-traits]: +ch16-04-extensible-concurrency-sync-and-send.html#syncとsendトレイトで拡張可能な並行性 +[the-slice-type]: ch04-03-slices.html#スライス型 +[reference]: https://doc.rust-lang.org/reference/items/unions.html diff --git a/src/ch19-03-advanced-traits.md b/src/ch19-03-advanced-traits.md index 5c82711af..437afa856 100644 --- a/src/ch19-03-advanced-traits.md +++ b/src/ch19-03-advanced-traits.md @@ -5,13 +5,14 @@ ## 高度なトレイト -最初にトレイトについて講義したのは、第10章の「トレイト: 共通の振る舞いを定義する」節でしたが、 -ライフタイム同様、より高度な詳細は議論しませんでした。今や、Rustに詳しくなったので、核心に迫れるでしょう。 +最初にトレイトについて講義したのは、第10章の[「トレイト: 共通の振る舞いを定義する」][traits-defining-shared-behavior]節でしたが、 +より高度な詳細は議論しませんでした。今や、Rustに詳しくなったので、核心に迫れるでしょう。 *関連型*は、トレイトのメソッド定義がシグニチャでプレースホルダーの型を使用できるように、トレイトと型のプレースホルダーを結び付けます。 -トレイトを実装するものがこの特定の実装で型の位置に使用される具体的な型を指定します。そうすることで、 +トレイトを実装するものがこの特定の実装でプレースホルダー型の代わりに使用される具体的な型を指定します。そうすることで、 なんらかの型を使用するトレイトをトレイトを実装するまでその型が一体なんであるかを知る必要なく定義できます。 関連型があるトレイトの一例は、標準ライブラリが提供する`Iterator`トレイトです。その関連型は`Item`と名付けられ、 -`Iterator`トレイトを実装している型が走査している値の型の代役を務めます。第13章の「`Iterator`トレイトと`next`メソッド」節で、 -`Iterator`トレイトの定義は、リスト19-20に示したようなものであることに触れました。 +`Iterator`トレイトを実装している型が走査している値の型の代役を務めます。 +`Iterator`トレイトの定義は、リスト19-12に示したようなものです。 -```rust -pub trait Iterator { - type Item; - - fn next(&mut self) -> Option; -} +```rust,noplayground +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-12/src/lib.rs}} ``` -リスト19-20: 関連型`Item`がある`Iterator`トレイトの定義 +リスト19-12: 関連型`Item`がある`Iterator`トレイトの定義 -型`Item`はプレースホルダー型で`next`メソッドの定義は、型`Option`の値を返すことを示しています。 +型`Item`はプレースホルダーで、`next`メソッドの定義は、型`Option`の値を返すことを示しています。 `Iterator`トレイトを実装するものは、`Item`の具体的な型を指定し、`next`メソッドは、 その具体的な型の値を含む`Option`を返します。 @@ -93,20 +89,13 @@ method will return an `Option` containing a value of that concrete type. 関連型は、ジェネリクスにより扱う型を指定せずに関数を定義できるという点でジェネリクスに似た概念のように思える可能性があります。 -では、何故関連型を使用するのでしょうか? - - - -2つの概念の違いを第13章から`Counter`構造体に`Iterator`トレイトを実装する例で調査しましょう。 -リスト13-21で、`Item`型は`u32`だと指定しました: +2つの概念の違いを調査するために、`Counter`という型に対する、`Item`型を`u32`と指定する、`Iterator`トレイトの実装を見てみましょう: -この記法は、ジェネリクスと比較可能に思えます。では、何故単純にリスト19-21のように、 +この記法は、ジェネリクスと比較可能に思えます。では、何故単純にリスト19-13のように、 `Iterator`トレイトをジェネリクスで定義しないのでしょうか? -```rust -pub trait Iterator { - fn next(&mut self) -> Option; -} +```rust,noplayground +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-13/src/lib.rs}} ``` -リスト19-21: ジェネリクスを使用した架空の`Iterator`トレイトの定義 +リスト19-13: ジェネリクスを使用した架空の`Iterator`トレイトの定義 -差異は、リスト19-21のようにジェネリクスを使用すると、各実装で型を注釈しなければならないことです; +差異は、リスト19-13のようにジェネリクスを使用すると、各実装で型を注釈しなければならないことです; `Iterator for Counter`や他のどんな型にも実装することができるので、 `Counter`の`Iterator`の実装が複数できるでしょう。換言すれば、トレイトにジェネリックな引数があると、 毎回ジェネリックな型引数の具体的な型を変更してある型に対して複数回実装できるということです。 @@ -162,7 +145,7 @@ indicate which implementation of `Iterator` we want to use. 関連型なら、同じ型に対してトレイトを複数回実装できないので、型を注釈する必要はありません。 -関連型を使用する定義があるリスト19-20では、`Item`の型は1回しか選択できませんでした。 +関連型を使用する定義があるリスト19-12では、`Item`の型は1回しか選択できませんでした。 1つしか`impl Iterator for Counter`がないからです。`Counter`に`next`を呼び出す度に、 `u32`値のイテレータが欲しいと指定しなくてもよいわけです。 + + +関連型もトレイトの契約の一部になります: トレイトの実装者は、関連型プレースホルダーの代わりとなる型を提供しなくてはなりません。 +関連型は、その型がどのように使われることになるかの説明となる名前を持つことが多く、 +APIドキュメンテーションで関連型をドキュメント化するのは良い取り組みです。 + @@ -183,36 +177,35 @@ that we call `next` on `Counter`. ジェネリックな型引数を使用する際、ジェネリックな型に対して既定の具体的な型を指定できます。これにより、 -既定の型が動くのなら、トレイトを実装する側が具体的な型を指定する必要を排除します。ジェネリックな型に既定の型を指定する記法は、 -ジェネリックな型を宣言する際に``です。 +既定の型が動くのなら、トレイトを実装する側が具体的な型を指定する必要を排除します。 +ジェネリックな型を宣言する際に、``記法で既定の型を指定します。 -このテクニックが有用になる場面の好例が、演算子オーバーロードです。*演算子オーバーロード*とは、 -特定の状況で演算子(`+`など)の振る舞いをカスタマイズすることです。 +このテクニックが有用になる場面の好例が*演算子オーバーロード*で、 +これにより特定の状況で演算子(`+`など)の振る舞いをカスタマイズします。 Rustでは、独自の演算子を作ったり、任意の演算子をオーバーロードすることはできません。しかし、 演算子に紐づいたトレイトを実装することで`std::ops`に列挙された処理と対応するトレイトをオーバーロードできます。 -例えば、リスト19-22で`+`演算子をオーバーロードして2つの`Point`インスタンスを足し合わせています。 +例えば、リスト19-14で`+`演算子をオーバーロードして2つの`Point`インスタンスを足し合わせています。 `Point`構造体に`Add`トレイトを実装することでこれを行なっています。 -リスト19-22: `Add`トレイトを実装して`Point`インスタンス用に`+`演算子をオーバーロードする +リスト19-14: `Add`トレイトを実装して`Point`インスタンス用に`+`演算子をオーバーロードする このコードは一般的に馴染みがあるはずです: 1つのメソッドと関連型が1つあるトレイトです。 -新しい部分は、`RHS=Self`です: この記法は、*デフォルト型引数*と呼ばれます。 -RHSというジェネリックな型引数("right hand side": 右辺の省略形)が、`add`メソッドの`rhs`引数の型を定義しています。 -`Add`トレイトを実装する際に`RHS`の具体的な型を指定しなければ、`RHS`の型は標準で`Self`になり、 +新しい部分は、`Rhs=Self`です: この記法は、*デフォルト型引数*と呼ばれます。 +`Rhs`というジェネリックな型引数("right hand side": 右辺の省略形)が、`add`メソッドの`rhs`引数の型を定義しています。 +`Add`トレイトを実装する際に`Rhs`の具体的な型を指定しなければ、`Rhs`の型は標準で`Self`になり、 これは`Add`を実装している型になります。 -`Point`に`Add`を実装する際、2つの`Point`インスタンスを足したかったので、`RHS`の規定を使用しました。 -既定を使用するのではなく、`RHS`の型をカスタマイズしたくなる`Add`トレイトの実装例に目を向けましょう。 +`Point`に`Add`を実装する際、2つの`Point`インスタンスを足したかったので、`Rhs`の規定を使用しました。 +既定を使用するのではなく、`Rhs`の型をカスタマイズしたくなる`Add`トレイトの実装例に目を向けましょう。 異なる単位で値を保持する構造体、`Millimeters`と`Meters`(それぞれ`ミリメートル`と`メートル`)が2つあります。 +このように既存の型を別の構造体で薄くラップすることは*ニュータイプパターン*として知られ、 +これについては[「ニュータイプパターンを使用して外部の型に外部のトレイトを実装する」][newtype]節でより詳しく説明します。 ミリメートルの値をメートルの値に足し、`Add`の実装に変換を正しくしてほしいです。 -`Add`を`RHS`に`Meters`のある`Millimeters`に実装することができます。リスト19-23のように: +`Add`を`Rhs`に`Meters`のある`Millimeters`に実装することができます。リスト19-23のように: -リスト19-23: `Millimeters`に`Add`トレイトを実装して、`Meters`に`Millimeters`を足す +リスト19-15: `Millimeters`に`Add`トレイトを実装して、`Meters`に`Millimeters`を足す `Millimeters`を`Meters`に足すため、`Self`という既定を使う代わりに`impl Add`を指定して、 -`RHS`型引数の値をセットしています。 +`Rhs`型引数の値をセットしています。 主に2通りの方法でデフォルト型引数を使用します: @@ -407,15 +372,15 @@ Rustにおいて、別のトレイトのメソッドと同じ名前のメソッ トレイトのメソッドと同じ名前のメソッドを直接型に実装することも可能です。 同じ名前のメソッドを呼ぶ際、コンパイラにどれを使用したいのか教える必要があるでしょう。両方とも`fly`というメソッドがある2つのトレイト、 -`Pilot`と`Wizard`(`訳注`: パイロットと魔法使い)を定義したリスト19-24のコードを考えてください。 +`Pilot`と`Wizard`(`訳注`: パイロットと魔法使い)を定義したリスト19-16のコードを考えてください。 それから両方のトレイトを既に`fly`というメソッドが実装されている型`Human`(`訳注`: 人間)に実装します。 各`fly`メソッドは異なることをします。 @@ -426,54 +391,25 @@ on it. Each `fly` method does something different. ファイル名: src/main.rs ```rust -trait Pilot { - fn fly(&self); -} - -trait Wizard { - fn fly(&self); -} - -struct Human; - -impl Pilot for Human { - fn fly(&self) { - // キャプテンのお言葉 - println!("This is your captain speaking."); - } -} - -impl Wizard for Human { - fn fly(&self) { - // 上がれ! - println!("Up!"); - } -} - -impl Human { - fn fly(&self) { - // *激しく腕を振る* - println!("*waving arms furiously*"); - } -} +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-16/src/main.rs:here}} ``` -リスト19-24: 2つのトレイトに`fly`があるように定義され、`Human`に実装されつつ、 +リスト19-16: 2つのトレイトに`fly`があるように定義され、`Human`に実装されつつ、 `fly`メソッドは`Human`に直接にも実装されている `Human`のインスタンスに対して`fly`を呼び出すと、コンパイラは型に直接実装されたメソッドを標準で呼び出します。 -リスト19-25のようにですね: +リスト19-17のようにですね: -リスト19-25: `Human`のインスタンスに対して`fly`を呼び出す +リスト19-17: `Human`のインスタンスに対して`fly`を呼び出す `Pilot`トレイトか、`Wizard`トレイトの`fly`メソッドを呼ぶためには、 より明示的な記法を使用して、どの`fly`メソッドを意図しているか指定する必要があります。 -リスト19-26は、この記法をデモしています。 +リスト19-18は、この記法をデモしています。 -リスト19-26: どのトレイトの`fly`メソッドを呼び出したいか指定する +リスト19-18: どのトレイトの`fly`メソッドを呼び出したいか指定する メソッド名の前にトレイト名を指定すると、コンパイラにどの`fly`の実装を呼び出したいか明確化できます。 -また、`Human::fly(&person)`と書くこともでき、リスト19-26で使用した`person.fly()`と等価ですが、 +また、`Human::fly(&person)`と書くこともでき、リスト19-18で使用した`person.fly()`と等価ですが、 こちらの方は明確化する必要がないなら、ちょっと記述量が増えます。 -しかしながら、トレイトの一部になる関連関数には`self`引数がありません。同じスコープの2つの型がそのトレイトを実装する場合、 -*フルパス記法*(fully qualified syntax)を使用しない限り、どの型を意図しているかコンパイラは推論できません。例えば、 -リスト19-27の`Animal`トレイトには、関連関数`baby_name`、構造体`Dog`の`Animal`の実装、 -`Dog`に直接定義された関連関数`baby_name`があります。 +しかしながら、メソッドではない関連関数には`self`引数がありません。同じ関数名で非メソッド関数を定義する型またはトレイトが複数ある場合、 +*フルパス記法*(fully qualified syntax)を使用しない限り、どの型を意図しているかコンパイラが常に理解するとは限りません。例えば、 +リスト19-19では、全ての赤ちゃん犬を*スポット*(`訳注`: Wikipediaによると、飼い主の事故死後もその人の帰りを待つ忠犬の名前の模様) +と名付けたいアニマル・シェルター(`訳注`: 身寄りのないペットを保護する保健所みたいなところ)のためのトレイトを作成します。 +関連非メソッド関数`baby_name`を持つ、`Animal`トレイトを作成します。 +`Animal`トレイトは構造体`Dog`に対して実装され、さらに`Dog`はその上に直接定義された関連非メソッド関数`baby_name`を提供します。 -リスト19-27: 関連関数のあるトレイトとそのトレイトも実装し、同じ名前の関連関数がある型 +リスト19-19: 関連関数のあるトレイトとそのトレイトも実装し、同じ名前の関連関数がある型 -このコードは、全ての子犬をスポットと名付けたいアニマル・シェルター(`訳注`: 身寄りのないペットを保護する保健所みたいなところ)用で、 -`Dog`に定義された`baby_name`関連関数で実装されています。`Dog`型は、トレイト`Animal`も実装し、 -このトレイトは全ての動物が持つ特徴を記述します。赤ちゃん犬は子犬と呼ばれ、 +`Dog`に定義された`baby_name`関連関数で、すべての子犬にスポットと名付けるためのコードを実装しています。 +`Dog`型は、トレイト`Animal`も実装し、このトレイトは全ての動物が持つ特徴を記述します。赤ちゃん犬は子犬と呼ばれ、 それが`Dog`の`Animal`トレイトの実装の`Animal`トレイトと紐づいた`base_name`関数で表現されています。 この出力は、欲しかったものではありません。`Dog`に実装した`Animal`トレイトの一部の`baby_name`関数を呼び出したいので、 -コードは`A baby dog is called a puppy`と出力します。リスト19-26で使用したトレイト名を指定するテクニックは、 -ここでは役に立ちません; `main`をリスト19-28のようなコードに変更したら、コンパイルエラーになるでしょう。 +コードは`A baby dog is called a puppy`と出力します。リスト19-18で使用したトレイト名を指定するテクニックは、 +ここでは役に立ちません; `main`をリスト19-20のようなコードに変更したら、コンパイルエラーになるでしょう。 -リスト19-28: `Animal`トレイトの`baby_name`関数を呼び出そうとするも、コンパイラにはどの実装を使うべきかわからない +リスト19-20: `Animal`トレイトの`baby_name`関数を呼び出そうとするも、コンパイラにはどの実装を使うべきかわからない -`Animal::baby_name`はメソッドではなく関連関数であり、故に`self`引数がないので、どの`Animal::baby_name`が欲しいのか、 -コンパイラには推論できません。こんなコンパイルエラーが出るでしょう: +`Animal::baby_name`は`self`引数を持たず、`Animal`トレイトを実装する他の型があるかもしれないので、 +どの`Animal::baby_name`が欲しいのか、コンパイラには推論できません。こんなコンパイルエラーが出るでしょう: -```text -error[E0283]: type annotations required: cannot resolve `_: Animal` -(エラー: 型注釈が必要です: `_: Animal`を解決できません) - --> src/main.rs:20:43 - | -20 | println!("A baby dog is called a {}", Animal::baby_name()); - | ^^^^^^^^^^^^^^^^^ - | - = note: required by `Animal::baby_name` - (注釈: `Animal::baby_name`に必要です) +```console +{{#include ../listings/ch19-advanced-features/listing-19-20/output.txt}} ``` -`Dog`に対して`Animal`実装を使用したいと明確化し、コンパイラに指示するには、フルパス記法を使う必要があります。 -リスト19-29は、フルパス記法を使用する方法をデモしています。 +何らかの他の型に対する`Animalの実装ではなく`Dog`に対する`Animal`実装を使用したいことを、 +コンパイラに明確化して指示するには、フルパス記法を使う必要があります。 +リスト19-21は、フルパス記法を使用する方法をデモしています。 -リスト19-29: フルパス記法を使って`Dog`に実装されているように、 - `Animal`トレイトからの`baby_name`関数を呼び出したいと指定する +リスト19-21: フルパス記法を使って`Dog`に実装されているように、 +`Animal`トレイトからの`baby_name`関数を呼び出したいと指定する -関連関数では、`receiver`がないでしょう: 他の引数のリストがあるだけでしょう。関数やメソッドを呼び出す箇所全部で、 +メソッドでない関連関数には、`receiver`がないでしょう: 他の引数のリストがあるだけでしょう。関数やメソッドを呼び出す箇所全部で、 フルパス記法を使用することもできるでしょうが、プログラムの他の情報からコンパイラが推論できるこの記法のどの部分も省略することが許容されています。 同じ名前を使用する実装が複数あり、どの実装を呼び出したいかコンパイラが特定するのに助けが必要な場合だけにこのより冗長な記法を使用する必要があるのです。 @@ -851,24 +672,29 @@ implementation you want to call. ### スーパートレイトを使用して別のトレイト内で、あるトレイトの機能を必要とする -時として、あるトレイトに別のトレイトの機能を使用させる必要がある可能性があります。この場合、 -依存するトレイトも実装されることを信用する必要があります。信用するトレイトは、実装しているトレイトの*スーパートレイト*です。 +時として、別のトレイトに依存するトレイト定義を書くことがあるかもしれません: +型がそのトレイトを実装するためには、別のトレイトも実装していることを要求したいということです。 +前者のトレイト定義が後者のトレイトの要素を利用できるように、これを行うことになるでしょう。 +トレイト定義が依存するトレイトは、そのトレイトの*スーパートレイト*と呼ばれます。 -例えば、アスタリスクをフレームにする値を出力する`outline_print`メソッドがある`OutlinePrint`トレイトを作りたくなったとしましょう。 -つまり、`Display`を実装し、`(x, y)`という結果になる`Point`構造体が与えられて、 +例えば、与えられた値をアスタリスクの枠で囲うように整形して出力する、`outline_print`メソッドを持つ`OutlinePrint`トレイトを作りたくなったとしましょう。 +つまり、標準ライブラリトレイトの`Display`を実装し、`(x, y)`という結果になる`Point`構造体が与えられて、 `x`が`1`、`y`が`3`の`Point`インスタンスに対して`outline_print`を呼び出すと、以下のような出力をするはずです: ```text @@ -880,18 +706,19 @@ call `outline_print` on a `Point` instance that has `1` for `x` and `3` for ``` -`outline_print`の実装では、`Display`トレイトの機能を使用したいです。故に、`Display`も実装する型に対してだけ`OutlinePrint`が動くと指定し、 +`outline_print`メソッドの実装では、`Display`トレイトの機能を使用したいです。故に、`Display`も実装する型に対してだけ`OutlinePrint`が動くと指定し、 `OutlinePrint`が必要とする機能を提供する必要があるわけです。トレイト定義で`OutlinePrint: Display`と指定することで、 そうすることができます。このテクニックは、トレイトにトレイト境界を追加することに似ています。 -リスト19-30は、`OutlinePrint`トレイトの実装を示しています。 +リスト19-22は、`OutlinePrint`トレイトの実装を示しています。 -リスト19-30: `Display`からの機能を必要とする`OutlinePrint`トレイトを実装する +リスト19-22: `Display`からの機能を必要とする`OutlinePrint`トレイトを実装する @@ -948,14 +763,8 @@ doesn’t implement `Display`, such as the `Point` struct: ファイル名: src/main.rs -```rust -# trait OutlinePrint {} -struct Point { - x: i32, - y: i32, -} - -impl OutlinePrint for Point {} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/src/main.rs:here}} ``` src/main.rs:20:6 - | -20 | impl OutlinePrint for Point {} - | ^^^^^^^^^^^^ `Point` cannot be formatted with the default formatter; -try using `:?` instead if you are using a format string - | - = help: the trait `std::fmt::Display` is not implemented for `Point` +```console +{{#include ../listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt}} ``` - -第10章の「型にトレイトを実装する」節で、トレイトか型がクレートにローカルな限り、型にトレイトを実装できると述べるオーファンルールについて触れました。 +new type in a tuple struct. (We covered tuple structs in the [“Using Tuple +Structs without Named Fields to Create Different Types”][tuple-structs] +section of Chapter 5.) The tuple struct will have one field and be a +thin wrapper around the type we want to implement a trait for. Then the wrapper +type is local to our crate, and we can implement the trait on the wrapper. +*Newtype* is a term that originates from the Haskell programming language. +There is no runtime performance penalty for using this pattern, and the wrapper +type is elided at compile time. +--> + +第10章の[「トレイトを型に実装する」][implementing-a-trait-on-a-type]節で、 +トレイトか型がクレートにローカルな場合に限り型にトレイトを実装できるとする、オーファンルールについて触れました。 *ニュータイプパターン*を使用してこの制限を回避することができ、タプル構造体に新しい型を作成することになります。 -(タプル構造体については、第5章の「異なる型を生成する名前付きフィールドのないタプル構造体を使用する」節で講義しました。) +(タプル構造体については、第5章の[「異なる型を生成する名前付きフィールドのないタプル構造体を使用する」][tuple-structs]節で講義しました。) タプル構造体は1つのフィールドを持ち、トレイトを実装したい型の薄いラッパになるでしょう。そして、 ラッパの型はクレートにローカルなので、トレイトをラッパに実装できます。*ニュータイプ*という用語は、 Haskellプログラミング言語に端を発しています。このパターンを使用するのに実行時のパフォーマンスを犠牲にすることはなく、 @@ -1046,12 +840,12 @@ As an example, let’s say we want to implement `Display` on `Vec`, which the orphan rule prevents us from doing directly because the `Display` trait and the `Vec` type are defined outside our crate. We can make a `Wrapper` struct that holds an instance of `Vec`; then we can implement `Display` on -`Wrapper` and use the `Vec` value, as shown in Listing 19-31. +`Wrapper` and use the `Vec` value, as shown in Listing 19-23. --> 例として、`Vec`に`Display`を実装したいとしましょう。`Display`トレイトも`Vec`型もクレートの外で定義されているので、 直接それを行うことはオーファンルールにより妨げられます。`Vec`のインスタンスを保持する`Wrapper`構造体を作成できます; -そして、`Wrapper`に`Display`を実装し、`Vec`値を使用できます。リスト19-31のように。 +そして、`Wrapper`に`Display`を実装し、`Vec`値を使用できます。リスト19-23のように。 -リスト19-31: `Vec`の周りに`Wrapper`を作成して`Display`を実装する +リスト19-23: `Vec`の周りに`Wrapper`を作成して`Display`を実装する このテクニックを使用する欠点は、`Wrapper`が新しい型なので、保持している値のメソッドがないことです。 `self.0`に委譲して、`Wrapper`を`Vec`と全く同様に扱えるように、`Wrapper`に直接`Vec`の全てのメソッドを実装しなければならないでしょう。 内部の型が持つ全てのメソッドを新しい型に持たせたいなら、 -`Deref`トレイト(第15章の「`Deref`トレイトでスマートポインタを普通の参照のように扱う」節で議論しました)を`Wrapper`に実装して、 +`Deref`トレイト(第15章の[「`Deref`トレイトでスマートポインタを普通の参照のように扱う」][smart-pointer-deref]節で議論しました)を`Wrapper`に実装して、 内部の型を返すことは解決策の1つでしょう。内部の型のメソッド全部を`Wrapper`型に持たせたくない(例えば、`Wrapper`型の機能を制限するなど)なら、 本当に欲しいメソッドだけを手動で実装しなければならないでしょう。 + +このニュータイプパターンは、トレイトが絡まなくても有用です。 +焦点を変更して、Rustの型システムと相互作用する一部の高度な方法を見ましょう。 + + -もう、トレイトに関してニュータイプパターンが使用される方法を知りました; トレイトが関連しなくても、 -有用なパターンでもあります。焦点を変更して、Rustの型システムと相互作用する一部の高度な方法を見ましょう。 +[newtype]: ch19-03-advanced-traits.html#ニュータイプパターンを使用して外部の型に外部のトレイトを実装する +[implementing-a-trait-on-a-type]: +ch10-02-traits.html#トレイトを型に実装する +[traits-defining-shared-behavior]: +ch10-02-traits.html#トレイト-共通の振る舞いを定義する +[smart-pointer-deref]: ch15-02-deref.html#derefトレイトでスマートポインタを普通の参照のように扱う +[tuple-structs]: ch05-01-defining-structs.html#異なる型を生成する名前付きフィールドのないタプル構造体を使用する diff --git a/src/ch19-04-advanced-types.md b/src/ch19-04-advanced-types.md index 8f57369ff..b05091457 100644 --- a/src/ch19-04-advanced-types.md +++ b/src/ch19-04-advanced-types.md @@ -5,54 +5,55 @@ ## 高度な型 -Rustの型システムには、この本で触れたけれども、まだ議論していない機能があります。ニュータイプが何故型として有用なのかを調査するため、 +Rustの型システムには、ここまで触れたけれども、まだ議論していない機能があります。ニュータイプが何故型として有用なのかを調査するため、 一般化してニュータイプを議論することから始めます。そして、型エイリアスに移ります。ニュータイプに類似しているけれども、 多少異なる意味を持つ機能です。また、`!`型と動的サイズ決定型も議論します。 -> 注釈: 次の節は、前節「外部の型に外部のトレイトを実装するニュータイプパターン」を読了済みであることを前提にしています。 +### 型安全性と抽象化を求めてニュータイプパターンを使用する -### 型安全性と抽象化を求めてニュータイプパターンを使用する +> 注釈: この節は、以前の節[「ニュータイプパターンを使用して外部の型に外部のトレイトを実装する」][using-the-newtype-pattern]を読了済みであることを前提にしています。 ここまでに議論した以上の作業についてもニュータイプパターンは有用で、静的に絶対に値を混同しないことを強制したり、 -値の単位を示すことを含みます。ニュータイプを使用して単位を示す例をリスト19-23で見かけました: +値の単位を示すことを含みます。ニュータイプを使用して単位を示す例をリスト19-15で見かけました: `Millimeters`と`Meters`構造体は、`u32`値をニュータイプにラップしていたことを思い出してください。 型`Millimeters`を引数にする関数を書いたら、誤ってその関数を型`Meters`や普通の`u32`で呼び出そうとするプログラムはコンパイルできないでしょう。 -型の実装の詳細を抽象化する際にニュータイプパターンを使用するでしょう: 例えば、新しい型を直接使用して、 -利用可能な機能を制限したら、非公開の内部の型のAPIとは異なる公開APIを新しい型は露出できます。 +ニュータイプパターンは、型の実装の詳細を抽象化するためにも使用することができます: +非公開の内部の型のAPIとは異なる公開APIを新しい型は露出できます。 ニュータイプはまた、内部の実装を隠匿(いんとく)することもできます。例を挙げれば、`People`型を提供して、 @@ -70,7 +73,7 @@ Hides Implementation Details” section of Chapter 17. `People`を使用するコードは、名前の文字列を`People`コレクションに追加するメソッドなど、 提供している公開APIとだけ相互作用するでしょう; そのコードは、内部で`i32`IDを名前に代入していることを知る必要はないでしょう。 ニュータイプパターンは、カプセル化を実現して実装の詳細を隠匿する軽い方法であり、 -実装の詳細を隠匿することは、第17章の「カプセル化は実装詳細を隠蔽する」節で議論しましたね。 +実装の詳細を隠匿することは、第17章の[「カプセル化は、実装詳細を隠蔽する」][encapsulation-that-hides-implementation-details]節で議論しましたね。 -ニュータイプパターンに付随して、Rustでは、既存の型に別の名前を与える*型エイリアス*(type alias: 型別名)を宣言する能力が提供されています。 +Rustでは、既存の型に別の名前を与える*型エイリアス*(type alias: 型別名)を宣言する能力が提供されています。 このために、`type`キーワードを使用します。例えば、以下のように`i32`に対して`Kilometers`というエイリアスを作れます。 ```rust -type Kilometers = i32; +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-04-kilometers-alias/src/main.rs:here}} ``` -これで、別名の`Kilometers`は`i32`と*同義語*になりました; リスト19-23で生成した`Millimeters`と`Meters`とは異なり、 +これで、別名の`Kilometers`は`i32`と*同義語*になりました; リスト19-15で生成した`Millimeters`と`Meters`とは異なり、 `Kilometers`は個別の新しい型ではありません。型`Kilometers`の値は、型`i32`の値と同等に扱われます。 ```rust -type Kilometers = i32; - -let x: i32 = 5; -let y: Kilometers = 5; - -println!("x + y = {}", x + y); +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-04-kilometers-alias/src/main.rs:there}} ``` `Kilometers`と`i32`が同じ型なので、両方の型の値を足し合わせたり、`Kilometers`の値を`i32`引数を取る関数に渡せたりします。 ですが、この方策を使用すると、先ほど議論したニュータイプパターンで得られる型チェックの利便性は得られません。 +つまり、`Kilometers`と`i32`の値をどこかでごちゃ混ぜにしてしまっても、コンパイラはエラーを出してくれないでしょう。 この長ったらしい型を関数シグニチャや型注釈としてコードのあちこちで記述するのは、面倒で間違いも起きやすいです。 -リスト19-32のそのようなコードで溢れかえったプロジェクトがあることを想像してください。 +リスト19-24のそのようなコードで溢れかえったプロジェクトがあることを想像してください。 ```rust -let f: Box = Box::new(|| println!("hi")); - -fn takes_long_type(f: Box) { - // --snip-- -} - -fn returns_long_type() -> Box { - // --snip-- -# Box::new(|| ()) -} +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-24/src/main.rs:here}} ``` -リスト19-32: 長い型を多くの場所で使用する +リスト19-24: 長い型を多くの場所で使用する -型エイリアスは、繰り返しを減らすことでこのコードをより管理しやすくしてくれます。リスト19-33で、 +型エイリアスは、繰り返しを減らすことでこのコードをより管理しやすくしてくれます。リスト19-25で、 冗長な型に`Thunk`(`注釈`: 塊)を導入し、その型の使用全部をより短い別名の`Thunk`で置き換えることができます。 ```rust -type Thunk = Box; - -let f: Thunk = Box::new(|| println!("hi")); - -fn takes_long_type(f: Thunk) { - // --snip-- -} - -fn returns_long_type() -> Thunk { - // --snip-- -# Box::new(|| ()) -} +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-25/src/main.rs:here}} ``` -リスト19-33: 型エイリアスの`Thunk`を導入して繰り返しを減らす +リスト19-25: 型エイリアスの`Thunk`を導入して繰り返しを減らす -`Result<..., Error>`が何度も繰り返されてます。そんな状態なので、`std::io`にはこんな類のエイリアス宣言があります: +`Result<..., Error>`が何度も繰り返されてます。そんな状態なので、`std::io`にはこんな型エイリアス宣言があります: -```rust,ignore -type Result = Result; +```rust,noplayground +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-06-result-alias/src/lib.rs:here}} ``` @@ -251,14 +223,8 @@ looking like this: つまり、`E`が`std::io::Error`で埋められた`Result`です。その結果、`Write`トレイトの関数シグニチャは、 以下のような見た目になります: -```rust,ignore -pub trait Write { - fn write(&mut self, buf: &[u8]) -> Result; - fn flush(&mut self) -> Result<()>; - - fn write_all(&mut self, buf: &[u8]) -> Result<()>; - fn write_fmt(&mut self, fmt: Arguments) -> Result<()>; -} +```rust,noplayground +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-06-result-alias/src/lib.rs:there}} ``` -ですが、値を絶対に生成できない型をどう使用するのでしょうか?リスト2-5のコードを思い出してください; -リスト19-34に一部を再掲します。 +ですが、値を絶対に生成できない型をどう使用するのでしょうか?数当てゲームの一部である、 +リスト2-5のコードを思い出してください; リスト19-26にその一部を再掲します。 -```rust -# let guess = "3"; -# loop { -let guess: u32 = match guess.trim().parse() { - Ok(num) => num, - Err(_) => continue, -}; -# break; -# } + +```rust,ignore +{{#rustdoc_include ../listings/ch02-guessing-game-tutorial/listing-02-05/src/main.rs:ch19}} ``` -リスト19-34: `continue`になるアームがある`match` +リスト19-26: `continue`になるアームがある`match` -この時点では、このコードの詳細の一部を飛ばしました。第6章の「`match`制御フロー演算子」節で、 +この時点では、このコードの詳細の一部を飛ばしました。第6章の[「`match`制御フロー演算子」][the-match-control-flow-operator]節で、 `match`アームは全て同じ型を返さなければならないと議論しました。従って、例えば以下のコードは動きません: -```rust,ignore -let guess = match guess.trim().parse() { - Ok(_) => 5, - Err(_) => "hello", -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-08-match-arms-different-types/src/main.rs:here}} ``` このコードの`guess`は整数*かつ*文字列にならなければならないでしょうが、Rustでは、`guess`は1つの型にしかならないことを要求されます。 -では、`continue`は何を返すのでしょうか?どうやってリスト19-34で1つのアームからは`u32`を返し、別のアームでは、 +では、`continue`は何を返すのでしょうか?どうやってリスト19-26で1つのアームからは`u32`を返し、別のアームでは、 `continue`で終わっていたのでしょうか? -never型は、`panic!`マクロとも有用です。`Option`値に対して呼び出して、値かパニックを生成した`unwrap`関数を覚えていますか? -こちらがその定義です: +never型は、`panic!`マクロとも有用です。`Option`値に対して呼び出して、 +値かパニックを生成する`unwrap`関数を思い出してください。こちらがその定義です: ```rust,ignore -impl Option { - pub fn unwrap(self) -> T { - match self { - Some(val) => val, - None => panic!("called `Option::unwrap()` on a `None` value"), - } - } -} +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-09-unwrap-definition/src/lib.rs:here}} ``` -このコードにおいて、リスト19-34の`match`と同じことが起きています: コンパイラは、`val`の型は`T`で、 +このコードにおいて、リスト19-26の`match`と同じことが起きています: コンパイラは、`val`の型は`T`で、 `panic!`の型は`!`なので、`match`式全体の結果は`T`と確認します。`panic!`は値を生成しないので、 このコードは動きます。つまり、プログラムを終了するのです。`None`の場合、`unwrap`から値は返さないので、 このコードは合法なのです。 @@ -424,13 +374,7 @@ One final expression that has the type `!` is a `loop`: 型が`!`の最後の式は、`loop`です: ```rust,ignore -// 永遠に -print!("forever "); - -loop { - // さらに永遠に - print!("and ever "); -} +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-10-loop-returns-never/src/main.rs:here}} ``` -コンパイラが特定の型の値1つにどれくらいのスペースのメモリを確保するのかなどの特定の詳細を知る必要があるために、 -Rustの型システムには混乱を招きやすい細かな仕様があります: *動的サイズ決定型*の概念です。時として*DST*や*サイズなし型*とも称され、 +コンパイラは、特定の型の値1つにどれくらいのスペースのメモリを確保するのかなど、 +その型についての特定の詳細を知る必要があります。ただしこれには、 +最初は少し混乱しやすい型システムのコーナーケースがあります: +*動的サイズ決定型*の概念です。時として*DST*や*サイズなし型*とも称され、 これらの型により、実行時にしかサイズを知ることのできない値を使用するコードを書かせてくれます。 - -では、どうすればいいのでしょうか?この場合、もう答えはご存知です: `s1`と`s2`の型を`str`ではなく、 -`&str`にすればいいのです。第4章の「文字列スライス」節でスライスデータ構造は、 -開始地点とスライスの長さを格納していると述べたことを思い出してください。 - - +では、どうすればいいのでしょうか?この場合、もう答えはご存知です: `s1`と`s2`の型を`str`ではなく、 +`&str`にすればいいのです。第4章の[「文字列スライス」][string-slices]節で学んだように、 +スライスデータ構造は単に開始地点とスライスの長さを格納したものだということを思い出してください。 従って、`&T`は、`T`がどこにあるかのメモリアドレスを格納する単独の値だけれども、`&str`は*2つ*の値なのです: `str`のアドレスとその長さです。そのため、コンパイル時に`&str`のサイズを知ることができます: `usize`の長さの2倍です。要するに、参照している文字列の長さによらず、常に`&str`のサイズがわかります。 @@ -527,34 +466,34 @@ types behind a pointer of some kind. We can combine `str` with all kinds of pointers: for example, `Box` or `Rc`. In fact, you’ve seen this before but with a different dynamically sized type: traits. Every trait is a dynamically sized type we can refer to by -using the name of the trait. In Chapter 17 in the “Using Trait Objects that -Allow for Values of Different Types” section, we mentioned that to use traits -as trait objects, we must put them behind a pointer, such as `&Trait` or -`Box` (`Rc` would work too). +using the name of the trait. In Chapter 17 in the [“Using Trait Objects That +Allow for Values of Different +Types”][using-trait-objects-that-allow-for-values-of-different-types] +section, we mentioned that to use traits as trait objects, we must +put them behind a pointer, such as `&dyn Trait` or `Box` (`Rc` would work too). --> `str`を全ての種類のポインタと組み合わせられます: 例を挙げれば、`Box`や`Rc`などです。 実際、これまでに見かけましたが、異なる動的サイズ決定型でした: トレイトです。全てのトレイトは、 -トレイト名を使用して参照できる動的サイズ決定型です。第17章の「トレイトオブジェクトで異なる型の値を許容する」節で、 -トレイトをトレイトオブジェクトとして使用するには、`&Trait`や`Box`(`Rc`も動くでしょう)など、 +トレイト名を使用して参照できる動的サイズ決定型です。第17章の[「トレイトオブジェクトで異なる型の値を許容する」][using-trait-objects-that-allow-for-values-of-different-types]節で、 +トレイトをトレイトオブジェクトとして使用するには、`&dyn Trait`や`Box`(`Rc`も動くでしょう)など、 ポインタの背後に配置しなければならないことに触れました。 -DSTを扱うために、Rustには`Sized`トレイトと呼ばれる特定のトレイトがあり、型のサイズがコンパイル時にわかるかどうかを決定します。 +DSTを扱うために、Rustは`Sized`トレイトを提供しており、型のサイズがコンパイル時にわかるかどうかを決定します。 このトレイトは、コンパイル時にサイズの判明する全てのものに自動的に実装されます。加えて、 コンパイラは暗黙的に全てのジェネリックな関数に`Sized`の境界を追加します。つまり、こんな感じのジェネリック関数定義は: ```rust,ignore -fn generic(t: T) { - // --snip-- -} +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-12-generic-fn-definition/src/lib.rs}} ``` -`?Sized`のトレイト境界は、`Sized`のトレイト境界の逆になります: これを「`T`は`Sized`かもしれないし、違うかもしれない」と解読するでしょう。 -この記法は、`Sized`にのみ利用可能で、他のトレイトにはありません。 +`?Sized`のトレイト境界は「`T`は`Sized`かもしれないし、違うかもしれない」という意味であり、 +この記法は、ジェネリック型はコンパイル時に既知のサイズを持たなくてはならないという、 +デフォルトの制約を無効化します。この意味を持つ`?Trait`記法は、`Sized`にのみ利用可能で、 +他のトレイトに対しては利用できません。 次は、関数とクロージャについて語ります! + + + +[encapsulation-that-hides-implementation-details]: +ch17-01-what-is-oo.html#カプセル化は実装詳細を隠蔽する +[string-slices]: ch04-03-slices.html#文字列スライス +[the-match-control-flow-operator]: +ch06-02-match.html#match制御フロー構造 +[using-trait-objects-that-allow-for-values-of-different-types]: +ch17-02-trait-objects.html#トレイトオブジェクトで異なる型の値を許容する +[using-the-newtype-pattern]: ch19-03-advanced-traits.html#ニュータイプパターンを使用して外部の型に外部のトレイトを実装する diff --git a/src/ch19-05-advanced-functions-and-closures.md b/src/ch19-05-advanced-functions-and-closures.md index 8b7eab5cc..da9314b8d 100644 --- a/src/ch19-05-advanced-functions-and-closures.md +++ b/src/ch19-05-advanced-functions-and-closures.md @@ -5,11 +5,12 @@ ## 高度な関数とクロージャ -最後に関数とクロージャに関連する高度な機能の一部を探究し、これには関数ポインタとクロージャの返却が含まれます。 +この節では関数とクロージャに関連する高度な機能の一部を探究し、 +これには関数ポインタとクロージャの返却が含まれます。 クロージャを関数に渡す方法について語りました; 普通の関数を関数に渡すこともできるのです! 新しいクロージャを定義するのではなく、既に定義した関数を渡したい時にこのテクニックは有用です。 -これを関数ポインタで行うと、関数を引数として他の関数に渡して使用できます。関数は、型`fn`(小文字のfです)に型強制されます。 +関数は、型`fn`(小文字のfです)に型強制されます。 `Fn`クロージャトレイトと混同すべきではありません。`fn`型は、*関数ポインタ*と呼ばれます。 -引数が関数ポインタであると指定する記法は、クロージャのものと似ています。リスト19-35のように。 +関数ポインタで関数を渡すことで、関数を引数として他の関数に渡して使用できます。 -ファイル名: src/main.rs -```rust -fn add_one(x: i32) -> i32 { - x + 1 -} +引数が関数ポインタであると指定する記法は、リスト19-27に示すように、クロージャのものと似ています。 +ここでは引数に1を足す関数`add_one`を定義しています。関数`do_twice`は2個の引数を取ります: +`i32`引数を取り`i32`を返す任意の関数への関数ポインタと、1個の`i32`値です。 +`do_twice`関数は、関数`f`に`arg`値を渡して2度呼び出し、その後2回の関数呼び出しの結果を足し合わせます。 +`main`関数は`do_twice`を引数`add_one`と`5`で呼び出します。 -fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { - f(arg) + f(arg) -} + -fn main() { - let answer = do_twice(add_one, 5); +ファイル名: src/main.rs - // 答えは{} - println!("The answer is: {}", answer); -} +```rust +{{#rustdoc_include ../listings/ch19-advanced-features/listing-19-27/src/main.rs}} ``` -リスト19-35: `fn`型を使用して引数として関数ポインタを受け入れる +リスト19-27: `fn`型を使用して引数として関数ポインタを受け入れる -関数ポインタは、クロージャトレイト3つ全て(`Fn`、`FnMut`、`FnOnce`)を実装するので、常に関数ポインタを引数として、 -クロージャを期待する関数に渡すことができます。関数が関数とクロージャどちらも受け入れられるように、 +関数ポインタはクロージャトレイト3つ全て(`Fn`、`FnMut`、`FnOnce`)を実装するので、 +つまり、クロージャを期待する関数には常に関数ポインタを引数として渡すことができます。 +関数が関数とクロージャどちらも受け入れられるように、 ジェネリックな型とクロージャトレイトの1つを使用して関数を書くのが最善です。 -クロージャではなく`fn`だけを受け入れたくなる箇所の一例は、クロージャのない外部コードとのインターフェイスです: +とはいえ、クロージャではなく`fn`だけを受け入れたくなる箇所の一例は、 +クロージャのない外部コードとのインターフェイスです: C関数は引数として関数を受け入れられますが、Cにはクロージャがありません。 -インラインでクロージャが定義されるか、名前付きの関数を使用できるであろう箇所の例として、`map`の使用に目を向けましょう。 +インラインでクロージャが定義されるか、名前付きの関数を使用できるであろう箇所の例として、 +標準ライブラリの`Iterator`トレイトによって提供される`map`メソッドの使用に目を向けましょう。 `map`関数を使用して数字のベクタを文字列のベクタに変換するには、このようにクロージャを使用できるでしょう: ```rust -let list_of_numbers = vec![1, 2, 3]; -let list_of_strings: Vec = list_of_numbers - .iter() - .map(|i| i.to_string()) - .collect(); +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-15-map-closure/src/main.rs:here}} ``` -先ほど「高度なトレイト」節で語ったフルパス記法を使わなければならないことに注意してください。 +先ほど[「高度なトレイト」][advanced-traits]節で語ったフルパス記法を使わなければならないことに注意してください。 というのも、`to_string`という利用可能な関数は複数あるからです。ここでは、 `ToString`トレイトで定義された`to_string`関数を使用していて、このトレイトは標準ライブラリが、 `Display`を実装するあらゆる型に実装しています。 + +第6章の[「Enumの値」][enum-values]節で学んだように、 +各enum列挙子の名前は初期化子関数にもなることを思い出してください。 +これらの初期化子関数は、クロージャトレイトを実装する関数ポインタとして使用することができます。 +つまり、次のように、クロージャを取るメソッドの引数として初期化子関数を指定することができるのです: + +```rust +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-17-map-initializer/src/main.rs:here}} +``` + + -このスタイルを好む方もいますし、クロージャを使うのを好む方もいます。どちらも結果的に同じコードにコンパイルされるので、 -どちらでも、自分にとって明確な方を使用してください。 +ここでは、`map`が呼ばれる範囲内の各`u32`値を使用して、 +`Status::Value`の初期化子関数を使用することで、`Status::Value`インスタンスを作成しています。 +このスタイルを好む方もいますし、クロージャを使うのを好む方もいます。 +どちらも結果的に同じコードにコンパイルされるので、どちらでも、自分にとって明確な方を使用してください。 @@ -188,10 +210,8 @@ The following code tries to return a closure directly, but it won’t compile: 以下のコードは、クロージャを直接返そうとしていますが、コンパイルできません: -```rust,ignore -fn returns_closure() -> Fn(i32) -> i32 { - |x| x + 1 -} +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch19-advanced-features/no-listing-18-returns-closure/src/lib.rs}} ``` - | -1 | fn returns_closure() -> Fn(i32) -> i32 { - | ^^^^^^^^^^^^^^ `std::ops::Fn(i32) -> i32 + 'static` - does not have a constant size known at compile-time - | - = help: the trait `std::marker::Sized` is not implemented for - `std::ops::Fn(i32) -> i32 + 'static` - = note: the return type of a function must have a statically known size +```console +{{#include ../listings/ch19-advanced-features/no-listing-18-returns-closure/output.txt}} ``` このコードは、問題なくコンパイルできます。トレイトオブジェクトについて詳しくは、 -第17章の「トレイトオブジェクトで異なる型の値を許容する」節を参照してください。 +第17章の[「トレイトオブジェクトで異なる型の値を許容する」][using-trait-objects-that-allow-for-values-of-different-types]節を参照してください。 次は、マクロを見てみましょう! + + + +[advanced-traits]: +ch19-03-advanced-traits.html#高度なトレイト +[enum-values]: ch06-01-defining-an-enum.html#enumの値 +[using-trait-objects-that-allow-for-values-of-different-types]: +ch17-02-trait-objects.html#トレイトオブジェクトで異なる型の値を許容する diff --git a/src/ch19-06-macros.md b/src/ch19-06-macros.md index 6e6279568..e010bd0f8 100644 --- a/src/ch19-06-macros.md +++ b/src/ch19-06-macros.md @@ -104,9 +104,9 @@ opposed to functions you can define anywhere and call anywhere. ### 一般的なメタプログラミングのために`macro_rules!`で宣言的なマクロ ファイル名: src/lib.rs -```rust +```rust,noplayground {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-28/src/lib.rs}} ``` @@ -217,28 +217,28 @@ one arm. Valid pattern syntax in macro definitions is different than the pattern syntax covered in Chapter 18 because macro patterns are matched against Rust code structure rather than values. Let’s walk through what the pattern pieces in -Listing 19-28 mean; for the full macro pattern syntax, see [the reference]. +Listing 19-28 mean; for the full macro pattern syntax, see the [Rust +Reference][ref]. --> マクロ定義で合法なパターン記法は、第18章で講義したパターン記法とは異なります。というのも、 マクロのパターンは値ではなく、Rustコードの構造に対してマッチされるからです。リスト19-28のパターンの部品がどんな意味か見ていきましょう; -マクロパターン記法全ては[参考文献]をご覧ください。 - - - -[参考文献]: https://doc.rust-lang.org/reference/macros.html +マクロパターン記法全ては[Rust Reference][ref]をご覧ください。 -まず、1組のカッコがパターン全体を囲んでいます。次にドル記号(`$`)、そして1組のカッコが続き、 +まず、パターン全体を囲む1組の丸かっこを使用しています。次に、 +パターンにマッチするRustコードを含むマクロシステム内の変数を宣言するために、 +ドル記号(`$`)を使用しています。このドル記号は、 +これが通常のRust変数ではなくマクロ変数であることを明確にしています。次に1組のカッコが続き、 このかっこは、置き換えるコードで使用するためにかっこ内でパターンにマッチする値をキャプチャします。 `$()`の内部には、`$x:expr`があり、これは任意のRust式にマッチし、その式に`$x`という名前を与えます。 @@ -295,17 +295,21 @@ have a second kind of declarative macro that will work in a similar fashion but fix some of these edge cases. After that update, `macro_rules!` will be effectively deprecated. With this in mind, as well as the fact that most Rust programmers will *use* macros more than *write* macros, we won’t discuss -`macro_rules!` any further. To learn more about how to write macros, consult -the online documentation or other resources, such as [“The Little Book of Rust -Macros”][tlborm]. +`macro_rules!` any further. --> `macro_rules!`には、いくつかの奇妙なコーナーケースがあります。 将来、Rustには別種の宣言的マクロが登場する予定です。これは、同じように働くけれども、それらのコーナーケースのうちいくらかを修正します。 そのアップデート以降、`macro_rules!`は事実上非推奨 (deprecated) となる予定です。 この事実と、ほとんどのRustプログラマーはマクロを*書く*よりも*使う*ことが多いということを考えて、`macro_rules!`についてはこれ以上語らないことにします。 -もしマクロの書き方についてもっと知りたければ、オンラインのドキュメントや、[“The Little Book of Rust Macros”][tlborm]のようなその他のリソースを参照してください。 -[tlborm]: https://danielkeep.github.io/tlborm/book/index.html + +もしマクロの書き方についてもっと知りたければ、オンラインのドキュメントや、 +Daniel Keepによって開始されLukas Wirthによって継続されている[“The Little Book of Rust Macros”][tlborm]のような、 +その他のリソースを参照してください。 2つ目のマクロの形は、*手続き的マクロ*と呼ばれ、より関数のように働きます(そして一種の手続きです)。 宣言的マクロがパターンマッチングを行い、マッチしたコードを他のコードで置き換えていたのとは違い、 手続き的マクロは、コードを入力として受け取り、そのコードに対して作用し、出力としてコードを生成します。 - - -3種の手続き的マクロ (カスタムのderiveマクロ, 属性風マクロ、関数風マクロ)はみな同じような挙動をします。 +カスタムのderiveマクロ、属性風マクロ、関数風マクロの、3種の手続き的マクロがあり、 +これらはみな同じように機能します。 手続き的マクロを作る際は、その定義はそれ専用の特殊なクレート内に置かれる必要があります。 これは複雑な技術的理由によるものであり、将来的には解消したいです。 -手続き的マクロを使うとListing 19-29のコードのようになります。`some_attribute`がそのマクロを使うためのプレースホールダーです。 +リスト19-29では、手続き的マクロを定義する方法を示しています。 +`some_attribute`がそのマクロを使うためのプレースホールダーです。 -Listing 19-29: 手続き的マクロの使用例 +リスト19-29: 手続き的マクロの定義例 `hello_macro_derive`関数は、ライブラリの使用者が型に`#[derive(HelloMacro)]`を指定した時に呼び出されます。 @@ -636,7 +635,7 @@ struct we get from parsing the `struct Pancakes;` string: この関数はまず、`TokenStream`からの`input`をデータ構造に変換し、解釈したり操作したりできるようにします。 ここで`syn`が登場します。 `syn`の`parse`関数は`TokenStream`を受け取り、パースされたRustのコードを表現する`DeriveInput`構造体を返します。 -Listing 19-32は`struct Pancakes;`という文字列をパースすることで得られる`DeriveInput`構造体の関係ある部分を表しています。 +リスト19-32は`struct Pancakes;`という文字列をパースすることで得られる`DeriveInput`構造体の関係ある部分を表しています。 ```rust,ignore DeriveInput { @@ -662,7 +661,7 @@ DeriveInput { Listing 19-32: The `DeriveInput` instance we get when parsing the code that has the macro’s attribute in Listing 19-30 --> -Listing 19-32: このマクロを使った属性を持つListing 19-30のコードをパースしたときに得られる`DeriveInput`インスタンス +リスト19-32: このマクロを使った属性を持つリスト19-30のコードをパースしたときに得られる`DeriveInput`インスタンス -[syn-docs]: https://docs.rs/syn/1.0/syn/struct.DeriveInput.html - この構造体のフィールドは、構文解析したRustコードが`Pancakes`という`ident`(識別子、つまり名前)のユニット構造体であることを示しています。 この構造体にはRustコードのあらゆる部分を記述するフィールドがもっと多くあります; [`DeriveInput`の`syn`ドキュメンテーション][syn-docs]で詳細を確認してください。 @@ -715,7 +712,7 @@ into a `DeriveInput` instance, let’s generate the code that implements the --> 今や、`TokenStream`からの注釈されたRustコードを`DeriveInput`インスタンスに変換するコードができたので、 -Listing 19-33のように、注釈された型に`HelloMacro`トレイトを実装するコードを生成しましょう: +リスト19-33のように、注釈された型に`HelloMacro`トレイトを実装するコードを生成しましょう: -Listing 19-33: パースされたRustコードを用いて`HelloMacro`トレイトを実装する +リスト19-33: パースされたRustコードを用いて`HelloMacro`トレイトを実装する `ast.ident`を使って、注釈された型の名前(識別子)を含む`Ident`構造体インスタンスを得ています。 -Listing 19-32の構造体を見ると、`impl_hello_macro`関数をListing 19-30のコードに実行したときに私達の得る`ident`は、フィールド`ident`の値として`"Pancakes"`を持つだろうとわかります。 -従って、Listing 19-33における変数`name`は構造体`Ident`のインスタンスをもちます。このインスタンスは、printされた時は文字列`"Pancakes"`、即ちListing 19-30の構造体の名前となります。 +リスト19-32の構造体を見ると、`impl_hello_macro`関数をリスト19-30のコードに実行したときに私達の得る`ident`は、フィールド`ident`の値として`"Pancakes"`を持つだろうとわかります。 +従って、リスト19-33における変数`name`は構造体`Ident`のインスタンスをもちます。このインスタンスは、printされた時は文字列`"Pancakes"`、即ちリスト19-30の構造体の名前となります。 @@ -901,11 +896,11 @@ Function-like macros define macros that look like function calls. Similarly to `macro_rules!` macros, they’re more flexible than functions; for example, they can take an unknown number of arguments. However, `macro_rules!` macros can be defined only using the match-like syntax we discussed in the section -[“Declarative Macros with `macro_rules!` for General Metaprogramming”][decl] -earlier. Function-like macros take a `TokenStream` parameter and their -definition manipulates that `TokenStream` using Rust code as the other two -types of procedural macros do. An example of a function-like macro is an `sql!` -macro that might be called like so: +[“Declarative Macros with `macro_rules!` for General +Metaprogramming”][decl] earlier. Function-like macros take a +`TokenStream` parameter and their definition manipulates that `TokenStream` +using Rust code as the other two types of procedural macros do. An example of a +function-like macro is an `sql!` macro that might be called like so: [decl]: #declarative-macros-with-macro_rules-for-general-metaprogramming --> @@ -916,8 +911,6 @@ macro that might be called like so: 関数風マクロは引数として`TokenStream`をとり、その`TokenStream`を定義に従って操作します。操作には、他の2つの手続き的マクロと同じように、Rustコードが使われます。 例えば、`sql!`マクロという関数風マクロで、以下のように呼び出されるものを考えてみましょう: -[decl]: #%E4%B8%80%E8%88%AC%E7%9A%84%E3%81%AA%E3%83%A1%E3%82%BF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E3%81%9F%E3%82%81%E3%81%ABmacro_rules%E3%81%A7%E5%AE%A3%E8%A8%80%E7%9A%84%E3%81%AA%E3%83%9E%E3%82%AF%E3%83%AD - ```rust,ignore let sql = sql!(SELECT * FROM posts WHERE id=1); ``` @@ -948,15 +941,16 @@ generate. ## まとめ ふう! -あなたがいま手にしたRustの機能はあまり頻繁に使うものではありませんが、非常に特殊な状況ではその存在を思い出すことになるでしょう。 +あなたがいま手にしたRustの機能はおそらくあまり頻繁に使うものではありませんが、 +非常に特殊な状況ではその存在を思い出すことになるでしょう。 たくさんの難しいトピックを紹介しましたが、これは、もしあなたがエラー時の推奨メッセージや他の人のコードでそれらに遭遇した時、その概念と文法を理解できるようになっていてほしいからです。 この章を、解決策にたどり着くためのリファレンスとして活用してください。 @@ -965,3 +959,21 @@ Next, we’ll put everything we’ve discussed throughout the book into practice and do one more project! --> 次は、この本で話してきたすべてのことを実際に使って、もう一つプロジェクトをやってみましょう! + + + +[ref]: https://docs.rust-lang.org/reference/macros-by-example.html +[tlborm]: https://veykril.github.io/tlborm/ +[`syn`]: https://crates.io/crates/syn +[`quote`]: https://crates.io/crates/quote +[syn-docs]: https://docs.rs/syn/1.0/syn/struct.DeriveInput.html +[quote-docs]: https://docs.rs/quote +[decl]: #一般的なメタプログラミングのためにmacro_rulesで宣言的なマクロ From e9aa0c64b0fac3659fa563fc2fcc50abc3ecaada Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 8 Dec 2024 12:20:12 +0900 Subject: [PATCH 21/22] =?UTF-8?q?markdown=20=E3=81=AE=E8=AA=A4=E3=82=8A?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ch19-03-advanced-traits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch19-03-advanced-traits.md b/src/ch19-03-advanced-traits.md index 437afa856..74fa5ba4d 100644 --- a/src/ch19-03-advanced-traits.md +++ b/src/ch19-03-advanced-traits.md @@ -603,7 +603,7 @@ type, we need to use fully qualified syntax. Listing 19-21 demonstrates how to use fully qualified syntax. --> -何らかの他の型に対する`Animalの実装ではなく`Dog`に対する`Animal`実装を使用したいことを、 +何らかの他の型に対する`Animal`の実装ではなく`Dog`に対する`Animal`実装を使用したいことを、 コンパイラに明確化して指示するには、フルパス記法を使う必要があります。 リスト19-21は、フルパス記法を使用する方法をデモしています。 From 717c501286a1e2e10ad3fbf4bc164954cf75c3dd Mon Sep 17 00:00:00 2001 From: shinmili Date: Sun, 8 Dec 2024 12:20:33 +0900 Subject: [PATCH 22/22] =?UTF-8?q?=E6=B6=88=E3=81=97=E5=BF=98=E3=82=8C?= =?UTF-8?q?=E3=81=9F=E6=AE=B5=E8=90=BD=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ch19-06-macros.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/ch19-06-macros.md b/src/ch19-06-macros.md index e010bd0f8..61baad623 100644 --- a/src/ch19-06-macros.md +++ b/src/ch19-06-macros.md @@ -289,19 +289,6 @@ generate code to create a vector containing the specified elements. 任意の型のあらゆる数の引数を取り、指定した要素を含むベクタを生成するコードを生成できるマクロを定義しました。 - -`macro_rules!`には、いくつかの奇妙なコーナーケースがあります。 -将来、Rustには別種の宣言的マクロが登場する予定です。これは、同じように働くけれども、それらのコーナーケースのうちいくらかを修正します。 -そのアップデート以降、`macro_rules!`は事実上非推奨 (deprecated) となる予定です。 -この事実と、ほとんどのRustプログラマーはマクロを*書く*よりも*使う*ことが多いということを考えて、`macro_rules!`についてはこれ以上語らないことにします。 -