From 511238e2908b00079353f46c26235dca36cd4b1b Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 12 Jul 2017 19:03:57 +0900 Subject: [PATCH 001/428] First drafts of chapter 2 and chapter 3-0 --- .../src/ch02-00-guessing-game-tutorial.md | 867 ++++++++---------- .../ch03-00-common-programming-concepts.md | 31 +- 2 files changed, 406 insertions(+), 492 deletions(-) diff --git a/second-edition/src/ch02-00-guessing-game-tutorial.md b/second-edition/src/ch02-00-guessing-game-tutorial.md index 51bfceef6..472803279 100644 --- a/second-edition/src/ch02-00-guessing-game-tutorial.md +++ b/second-edition/src/ch02-00-guessing-game-tutorial.md @@ -1,33 +1,31 @@ -# Guessing Game +# 数当てゲーム -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! The following chapters will explore -these ideas in more detail. In this chapter, you’ll practice the fundamentals. +実物のプロジェクトに一緒に取り組むことで、Rustの世界へ飛び込みましょう! +この章では、実際のプログラム内で使用する方法を通じて、いくつかの一般的なRustの概念に触れます。 +let文、match式、メソッド、関連関数、外部クレートの使用などについて学ぶでしょう! +後ほどの章でこれらの概念について深く知ることになります。この章では、基礎部分だけにしましょう。 -We’ll implement a classic beginner programming problem: a guessing game. Here’s -how it works: the program will generate a random integer between 1 and 100. It -will then prompt the player to enter a guess. After entering a guess, it will -indicate whether the guess is too low or too high. If the guess is correct, the -game will print congratulations and exit. +古典的な初心者向けのプログラミング問題を実装してみましょう: 数当てゲームです。 +これは以下のように動作します: プログラムは1から100までの乱数整数を生成します。 +さらにプレーヤーに予想を入力するよう促します。予想を入力し終わったら、プログラムは、 +その予想が少なすぎたか多すぎたかを出力します。予想が当たっていれば、ゲームが祝福してくれ、 +そのまま終了します。 -## Setting Up a New Project +## 新規プロジェクトの立ち上げ -To set up a new project, go to the *projects* directory that you created in -Chapter 1, and make a new project using Cargo, like so: +新規プロジェクトを立ち上げるには、第1章で作成した*projects*ディレクトリに行き、 +Cargoを使って新規プロジェクトを作成します。そう、以下のように: ```text $ cargo new guessing_game --bin $ cd guessing_game ``` -The first command, `cargo new`, takes the name of the project (`guessing_game`) -as the first argument. The `--bin` flag tells Cargo to make a binary project, -similar to the one in Chapter 1. The second command changes to the new -project’s directory. +最初のコマンド`cargo new`は、プロジェクト名を第1引数に取ります(`guessing_game`ですね)。 +`--bin`というフラグは、Cargoにバイナリ生成プロジェクトを作成させます。第1章のものと似ていますね。 +2番目のコマンドで新規プロジェクトのディレクトリに移動します。 -Look at the generated *Cargo.toml* file: +生成された*Cargo.toml*ファイルを見てみましょう: Filename: Cargo.toml @@ -35,16 +33,16 @@ Look at the generated *Cargo.toml* file: [package] name = "guessing_game" version = "0.1.0" -authors = ["Your Name "] +authors = ["名前 "] [dependencies] ``` -If the author information that Cargo obtained from your environment is not -correct, fix that in the file and save it again. +もし、Cargoがあなたの環境から自動取得した書き手情報が間違っていたら、 +ファイルを編集して保存し直してください。 -As you saw in Chapter 1, `cargo new` generates a “Hello, world!” program for -you. Check out the *src/main.rs* file: +第1章でも見かけたように、`cargo new`コマンドは、"Hello, world!"プログラムを生成してくれます。 +*src/main.rs*ファイルをチェックしてみましょう: Filename: src/main.rs @@ -54,8 +52,8 @@ fn main() { } ``` -Now let’s compile this “Hello, world!” program and run it in the same step -using the `cargo run` command: +さて、この"Hello, world!"プログラムをコンパイルし、`cargo run`コマンドを使用して、 +以前と同じように動かしてみましょう: ```text $ cargo run @@ -64,17 +62,17 @@ $ cargo run Hello, world! ``` -The `run` command comes in handy when you need to rapidly iterate on a project, -and this game is such a project: we want to quickly test each iteration -before moving on to the next one. +`run`コマンドは、プロジェクトに段階を踏んで取り掛かる必要がある場合に有用であり、 +このゲームはその類のプロジェクトになります。 +つまり、次のステップに進む前に各段階を急速にテストする必要があるわけです。 -Reopen the *src/main.rs* file. You’ll be writing all the code in this file. +*src/main.rs*ファイルを開き直しましょう。ここにすべてのコードを書いてきます。 -## Processing a Guess +## 予想を処理する -The first part of the program will ask for user input, process that input, and -check that the input is in the expected form. To start, we’ll allow the player -to input a guess. Enter the code in Listing 2-1 into *src/main.rs*. +プログラムの最初のパートは、ユーザに入力を求め、その入力を処理し、予期した形態になっていることを確認します。 +手始めにプレーヤーが予想を入力できるようにしましょう。 +リスト2-1のコードを*src/main.rs*に入力してください。 Filename: src/main.rs @@ -82,50 +80,49 @@ to input a guess. Enter the code in Listing 2-1 into *src/main.rs*. use std::io; fn main() { - println!("Guess the number!"); + println!("Guess the number!"); // 数を当ててごらん - println!("Please input your guess."); + println!("Please input your guess."); // ほら、予想を入力してね let mut guess = String::new(); io::stdin().read_line(&mut guess) - .expect("Failed to read line"); + .expect("Failed to read line"); // 行の読み込みに失敗しました - println!("You guessed: {}", guess); + println!("You guessed: {}", guess); // 次のように予想しました: {} } ``` -Listing 2-1: Code to get a guess from the user and print it out +リスト2-1: ユーザに予想を入力してもらい、それを出力するコード + +> 注釈: The programming language Rust第1版の翻訳者によると、ソースコードのコメント中以外に +> 日本語文字があるとコンパイルに失敗することがあるそうなので、文字列の英語は、コメントに和訳を載せます。 +> また、重複する内容の場合には、最初の1回だけ掲載するようにします。 -This code contains a lot of information, so let’s go over it bit by bit. To -obtain user input and then print the result as output, we need to bring the -`io` (input/output) library into scope. The `io` library comes from the -standard library (which is known as `std`): +このコードには、たくさんの情報が詰め込まれてますね。なので、少しずつ噛み砕いていきましょう。 +ユーザ入力を受け付け、結果を出力するためには、`io`(入/出力)ライブラリをスコープに導入する必要があります。 +`io`ライブラリは、標準ライブラリ(`std`として知られています)に存在します。: ```rust,ignore use std::io; ``` -By default, Rust brings only a few types into the scope of every program in -[the *prelude*][prelude]. If a type you want to use isn’t in the -prelude, you have to bring that type into scope explicitly with a `use` -statement. Using the `std::io` library provides you with a number of useful -`io`-related features, including the functionality to accept user input. +標準では、コンパイラは、[*prelude*][prelude]に存在するいくつかの型しかプログラムで使用させてくれません。 +もし、使用したい型がpreludeにない場合は、`use`文で明示的にその型をスコープに導入する必要があります。 +`std::io`ライブラリを使用することで、実用的な`入出力`関連の機能を使用することができます。 +ユーザ入力を受け付ける機能も含めてね。 [prelude]: ../../std/prelude/index.html -As you saw in Chapter 1, the `main` function is the entry point into the -program: +第1章で示した通り、`main`関数がプログラムへのエントリーポイント(スタート地点)になります: ```rust,ignore fn main() { ``` -The `fn` syntax declares a new function, the `()` indicate there are no -parameters, and `{` starts the body of the function. +`fn`記法が関数を新しく定義し、`()`は引数がないことを示し、`{`が関数本体のスタート地点になります。 -As you also learned in Chapter 1, `println!` is a macro that prints a string to -the screen: +また、第1章で学んだように、`println!`マクロは、文字列を画面に表示するマクロになります: ```rust,ignore println!("Guess the number!"); @@ -133,182 +130,163 @@ println!("Guess the number!"); println!("Please input your guess."); ``` -This code is just printing a prompt stating what the game is and requesting -input from the user. +このコードは、このゲームが何かを出力し、ユーザに入力を求めるだけです。 -### Storing Values with Variables +### 値を変数に保持する -Next, we’ll create a place to store the user input, like this: +次に、ユーザ入力を保持する場所を作りましょう。こんな感じに: ```rust,ignore let mut guess = String::new(); ``` -Now the program is getting interesting! There’s a lot going on in this little -line. Notice that this is a `let` statement, which is used to create -*variables*. Here’s another example: +さあ、プログラムが面白くなってきましたね。このたった1行でいろんなことが起きています。 +これが`let`文であることに注目してください。これを使用して*変数*を生成しています。 +こちらは、別の例です: ```rust,ignore let foo = bar; ``` -This line will create a new variable named `foo` and bind it to the value -`bar`. In Rust, variables are immutable by default. The following example shows -how to use `mut` before the variable name to make a variable mutable: +この行では、`foo`という名前の新しい変数を作成し、`bar`の値に束縛しています。 +Rustでは、変数は標準で不変(immutable)です。以下の例には、変数名の前に`mut`修飾子をつけて +変数を可変にする方法が示されています: ```rust let foo = 5; // immutable let mut bar = 5; // mutable ``` -> Note: The `//` syntax starts a comment that continues until the end of the -> line. Rust ignores everything in comments. +> 注釈: `//`という記法は、行末まで続くコメントを記述します。 +> コンパイラは、コメントを一切無視します。 -Now you know that `let mut guess` will introduce a mutable variable named -`guess`. On the other side of the equal sign (`=`) is the value that `guess` is -bound to, which is the result of calling `String::new`, a function that returns -a new instance of a `String`. [`String`][string] is a string -type provided by the standard library that is a growable, UTF-8 encoded bit of -text. +さあ、`let mut guess`が`guess`という名前の可変変数を導入するとわかりましたね。 +イコール記号(`=`)の逆側には、変数`guess`が束縛される値があります。この値は、今回の場合、 +`String::new`関数の呼び出し結果であり、この関数は、`String`型のオブジェクトを返します。 +[`String`][string]型は、標準ライブラリによって提供される文字列型で、 +サイズ可変、UTF-8エンコードされたテキスト破片になります。 [string]: ../../std/string/struct.String.html -The `::` syntax in the `::new` line indicates that `new` is an *associated -function* of the `String` type. An associated function is implemented on a type, -in this case `String`, rather than on a particular instance of a `String`. Some -languages call this a *static method*. +`::new`行にある`::`という記法は、`new`が`String`型の*関連付け関数*であることを表しています。 +関連付け関数とは、`String`型の特定のオブジェクトよりも型(この場合は`String`)に対して +実装された関数のことであり、*静的メソッド*と呼ばれる言語もあります。 -This `new` function creates a new, empty `String`. You’ll find a `new` function -on many types, because it’s a common name for a function that makes a new value -of some kind. +この`new`関数は、新しく空の`String`オブジェクトを生成します。`new`関数は、いろんな型に見られます。 +なぜなら、何らかの新規値を生成する関数にとってありふれた名前だからです。 -To summarize, the `let mut guess = String::new();` line has created a mutable -variable that is currently bound to a new, empty instance of a `String`. Whew! +まとめると、`let mut guess = String::new();`という行は、現在、新規で空の`String`オブジェクトに束縛されている +可変変数を作っているわけです。ふう! -Recall that we included the input/output functionality from the standard -library with `use std::io;` on the first line of the program. Now we’ll call an -associated function, `stdin`, on `io`: +プログラムの1行目で、`use std::io`として、標準ライブラリから入/出力機能を取り込んだことを思い出してください。 +今度は、`io`型の`stdin`関連付け関数を呼び出しましょう: ```rust,ignore io::stdin().read_line(&mut guess) .expect("Failed to read line"); ``` -If we didn’t have the `use std::io` line at the beginning of the program, we -could have written this function call as `std::io::stdin`. The `stdin` function -returns an instance of [`std::io::Stdin`][iostdin], which is a -type that represents a handle to the standard input for your terminal. +仮に、プログラムの冒頭で`use std::io`としていなければ、この関数呼び出しは、`std::io::stdin`と記述していたでしょう。 +この`stdin`関数は、 [`std::io::Stdin`][iostdin]オブジェクトを返し、この型は、 +ターミナルの標準入力へのハンドルを表す型になります。 [iostdin]: ../../std/io/struct.Stdin.html -The next part of the code, `.read_line(&mut guess)`, calls the -[`read_line`][read_line] method on the standard input handle to -get input from the user. We’re also passing one argument to `read_line`: `&mut +その次のコード破片、`.read_line(&mut guess)`は、標準入力ハンドルの[`read_line`][read_line] +メソッドを呼び出して、ユーザから入力を受け付けます。また、`read_line`メソッドに対して、引数を一つ渡していますね: `&mut guess`. [read_line]: ../../std/io/struct.Stdin.html#method.read_line -The job of `read_line` is to take whatever the user types into standard input -and place that into a string, so it takes that string as an argument. The -string argument needs to be mutable so the method can change the string’s -content by adding the user input. +`read_line`メソッドの仕事は、ユーザが標準入力したものすべてを取り出し、文字列に格納することなので、 +格納する文字列を引数として取ります。この文字列引数は、可変である必要があります。 +メソッドがユーザ入力を追記して、文字列の中身を変えられるようにってことですね。 -The `&` indicates that this argument is a *reference*, which gives you a way to -let multiple parts of your code access one piece of data without needing to -copy that data into memory multiple times. References are a complex feature, -and one of Rust’s major advantages is how safe and easy it is to use -references. You don’t need to know a lot of those details to finish this -program: Chapter 4 will explain references more thoroughly. For now, all you -need to know is that like variables, references are immutable by default. -Hence, we need to write `&mut guess` rather than `&guess` to make it mutable. +`&`という記号は、この引数が*参照*であることを表し、これのおかげで、データを複数回メモリにコピーせずとも、 +コードの複数箇所で同じデータにアクセスできるようになるわけです。参照は複雑な機能であり、 +とても安全かつ簡単に参照を使うことができることは、Rustの主要な利点の一つでもあります。 +そのような詳細は知らなくても、このプログラムを完成させることはできます: +第4章で参照について詳しく見ることにしましょう。現時点では、変数のように、参照も標準で不変であることを +知っておけばいいでしょう。故に、`&guess`と書くのではなく、`&mut guess`と書いて、可変にする必要があるのです。 -We’re not quite done with this line of code. Although it’s a single line of -text, it’s only the first part of the single logical line of code. The second -part is this method: +まだ、この行は終わりではありませんよ。テキストでは1行ですが、コードとしての論理行としては、 +まだ所詮最初の部分でしかないのです。2番目の部分はこのメソッドです。: ```rust,ignore .expect("Failed to read line"); ``` -When you call a method with the `.foo()` syntax, it’s often wise to introduce a -newline and other whitespace to help break up long lines. We could have -written this code as: +`.foo()`という記法で、メソッドを呼び出す時、改行と空白で長い行を分割するのは賢いことです。 +今回の場合、こう書くこともできますよね: ```rust,ignore io::stdin().read_line(&mut guess).expect("Failed to read line"); ``` -However, one long line is difficult to read, so it’s best to divide it, two -lines for two method calls. Now let’s discuss what this line does. +しかし、長い行は読みづらいものです。なので、分割しましょう。2回のメソッド呼び出しに、2行です。 +さて、この行が何をしているのかについて議論しましょうか。 -### Handling Potential Failure with the `Result` Type +### `Result`型で、失敗する可能性について対処する -As mentioned earlier, `read_line` puts what the user types into the string we’re -passing it, but it also returns a value—in this case, an -[`io::Result`][ioresult]. Rust has a number of types named -`Result` in its standard library: a generic [`Result`][result] as -well as specific versions for submodules, such as `io::Result`. +以前にも述べたように、`read_line`メソッドは、渡された文字列にユーザが入力したものを入れ込むだけでなく、 +値も返します(今回は[`io::Result`][ioresult]です)。 Rustには`Result`と名のついた型が +標準ライブラリにたくさんあります: ジェネリクスバージョンの[`Result`][result]の他、 +サブモジュール用の`io::Result`などの特別版まで。 [ioresult]: ../../std/io/type.Result.html [result]: ../../std/result/enum.Result.html -The `Result` types are [*enumerations*][enums], often referred -to as *enums*. An enumeration is a type that can have a fixed set of values, -and those values are called the enum’s *variants*. Chapter 6 will cover enums -in more detail. +この`Result`型は、[*列挙型*][enums]であり、普通、*enum*(イーナム)と呼ばれます。 +列挙型とは、固定された種類の値を持つ型のことであり、それらの値は、enumの*バリアント*(variant)と呼ばれます。 +enumについては、第6章で詳しく解説します。 [enums]: ch06-00-enums.html -For `Result`, the variants are `Ok` or `Err`. `Ok` indicates the operation was -successful, and inside the `Ok` variant is the successfully generated value. -`Err` means the operation failed, and `Err` contains information about how or -why the operation failed. - -The purpose of these `Result` types is to encode error handling information. -Values of the `Result` type, like any type, have methods defined on them. An -instance of `io::Result` has an [`expect` method][expect] that -you can call. If this instance of `io::Result` is an `Err` value, `expect` will -cause the program to crash and display the message that you passed as an -argument to `expect`. If the `read_line` method returns an `Err`, it would -likely be the result of an error coming from the underlying operating system. -If this instance of `io::Result` is an `Ok` value, `expect` will take the -return value that `Ok` is holding and return just that value to you so you -could use it. In this case, that value is the number of bytes in what the user -entered into standard input. +`Result`型に関しては、取りうる型の値(variant)は`Ok`か`Err`です。値`Ok`は、処理が成功したことを表し、 +中に生成された値を保持します。`Err`は、処理が失敗したことを意味し、`Err`は、処理が失敗した過程や、 +理由などの情報を含有します。 + +これら`Result`型の目的は、エラー処理の情報をエンコードすることです。`Result`型の値も、他の型同様、 +メソッドが定義されています。`io::Result`オブジェクトには、呼び出し可能な +[`expect`メソッド][expect]があります。 +この`io::Result`オブジェクトが`Err`値の場合、`expect`メソッドはプロラグムをクラッシュさせ、 +引数として渡されたメッセージを表示します。`read_line`メソッドが`Err`を返したら、 +根底にあるOSによるエラーに起因する可能性が高くなります。 +この`io::Result`オブジェクトが`Ok`値の場合、`expect`メソッドは、`Ok`バリアントが保持する +返り値を取り出して、ただその値を返すので、これを使用することができるかもしれません。 +今回の場合、その返り値とは、ユーザが標準入力に入力したバイト数になります。 [expect]: ../../std/result/enum.Result.html#method.expect -If we don’t call `expect`, the program will compile, but we’ll get a warning: +もし、`expect`メソッドを呼び出さなかったら、コンパイルは通るものの、警告が出るでしょう: ```text $ cargo build Compiling guessing_game v0.1.0 (file:///projects/guessing_game) -src/main.rs:10:5: 10:39 warning: unused result which must be used, +src/main.rs:10:5: 10:39 warning: unused result which must be used + (警告: 使用するべき結果が使用されていません), #[warn(unused_must_use)] on by default src/main.rs:10 io::stdin().read_line(&mut guess); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` -Rust warns that we haven’t used the `Result` value returned from `read_line`, -indicating that the program hasn’t handled a possible error. The right way to -suppress the warning is to actually write error handling, but since we just -want to crash this program when a problem occurs, we can use `expect`. You’ll -learn about recovering from errors in Chapter 9. +コンパイラは、私たちが`read_line`メソッドから返ってきた`Result`値を使用していないと警告してきており、 +これは、プログラムがエラーの可能性に対処していないことを示します。警告を抑制する正しい手段は、実際にエラー対処 +コードを書くことですが、今は、問題が起きた時にプロラグムをただ単にクラッシュさせたいので、`expect`を使用できるわけです。 +エラーから復旧する方法については、第9章で学ぶでしょう。 -### Printing Values with `println!` Placeholders +### `println!`マクロのプレースホルダーで値を出力する -Aside from the closing curly brace, there’s only one more line to discuss in -the code added so far, which is the following: +閉じ波かっこを除けば、ここまでに追加されたコードのうち議論すべきものは、残り1行であり、それは以下の通りです: ```rust,ignore println!("You guessed: {}", guess); ``` -This line prints out the string we saved the user’s input in. The set of `{}` -is a placeholder that holds a value in place. You can print more than one value -using `{}`: the first set of `{}` holds the first value listed after the format -string, the second set holds the second value, and so on. Printing out multiple -values in one call to `println!` would look like this: +この行は、ユーザ入力を保存した文字列の中身を出力する。1組の`{}`は、値を保持しておくプレースホルダーの役目を果たします。 +`{}`記法を使って一つ以上の値を出力できます: 最初の`{}`の組は、フォーマット文字列の後に列挙された最初の値に対応し、 +2組目は、2つ目の値、とそんな感じで続いていきます。1回の`println!`マクロの呼び出しで複数値を出力するコードは、 +以下のような感じになります。: ```rust let x = 5; @@ -317,48 +295,44 @@ let y = 10; println!("x = {} and y = {}", x, y); ``` -This code would print out `x = 5 and y = 10`. +このコードは、`x = 5 and y = 10`と出力するでしょう. -### Testing the First Part +### 最初の部分をテストする -Let’s test the first part of the guessing game. You can run it using `cargo run`: +数当てゲームの最初の部分をテストしてみましょう。`cargo run`コマンドでプログラムを走らせることができます: ```text $ cargo run Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Running `target/debug/guessing_game` -Guess the number! -Please input your guess. +Guess the number! (数を当ててごらん) +Please input your guess. (ほら、予想を入力して) 6 -You guessed: 6 +You guessed(次のように予想したよ): 6 ``` -At this point, the first part of the game is done: we’re getting input from the -keyboard and then printing it. +ここまでで、ゲームの最初の部分は完成になります: キーボードからの入力を受け付け、出力できるようになりました。 -## Generating a Secret Number +## 秘密の数字を生成する -Next, we need to generate a secret number that the user will try to guess. The -secret number should be different every time so the game is fun to play more -than once. Let’s use a random number between 1 and 100 so the game isn’t too -difficult. Rust doesn’t yet include random number functionality in its standard -library. However, the Rust team does provide a [`rand` crate][randcrate]. +次に、ユーザが数当てに挑戦する秘密の数字を生成する必要があります。毎回この秘密の数字は、変わるべきです。 +ゲームが何回も楽しめるようにですね。ゲームが難しくなりすぎないように、1から100までの乱数を使用しましょう。 +Rustの標準ライブラリには、乱数機能はまだ含まれていません。ですが、Rustチームが[`rand`クレート][randcrate]を +用意してくれています。 [randcrate]: https://crates.io/crates/rand -### Using a Crate to Get More Functionality +### クレートを使用して機能を追加する -Remember that a *crate* is a package of Rust code. The project we’ve been -building is a *binary crate*, which is an executable. The `rand` crate is a -*library crate*, which contains code intended to be used in other programs. +*クレート*はRustコードのパッケージであることを思い出してください。私たちがここまで作ってきたプロジェクトは、 +*バイナリークレート*であり、これは実行可能形式になります。`rand`クレートは*ライブラリクレート*であり、 +他のプロラグムで使用する用のコードが含まれています。 -Cargo’s use of external crates is where it 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 Cargo created for -you: +Cargoを使って外部クレートを使用すると、Cargoがとても輝きます。`rand`を使ったコードを書くためには、 +*Cargo.toml*ファイルを編集して、`rand`クレートを依存ファイルとして取り込む必要があります。 +このファイルを開いて、以下の行をCargoが自動生成した`[dependencies]`セクションヘッダーの一番下に追記しましょう: -Filename: Cargo.toml +ファイル名: Cargo.toml ```toml [dependencies] @@ -366,112 +340,97 @@ you: rand = "0.3.14" ``` -In the *Cargo.toml* file, everything that follows a header is part of a section -that continues until another section starts. The `[dependencies]` section is -where you tell Cargo which external crates your project depends on and which -versions of those crates you require. In this case, we’ll specify the `rand` -crate with the semantic version specifier `0.3.14`. Cargo understands [Semantic -Versioning][semver] (sometimes called *SemVer*), which is a -standard for writing version numbers. The number `0.3.14` is actually shorthand -for `^0.3.14`, which means “any version that has a public API compatible with -version 0.3.14.” +*Cargo.toml*ファイルにおいて、ヘッダーに続くものは全て、他のセクションが始まるまで続くセクションの一部になります。 +`[dependecies]`セクションは、プロジェクトが依存する外部クレートと必要とするバージョンを記述するところです。 +今は、`rand`クレートで、意味論的バージョンには`0.3.14`を指定します。Cargoは[意味論的バージョン付け][semver] +(時に*SemVer*と呼ばれる)を理解し、 意味論的バージョン付けは、バージョンナンバー記述の標準規格です。 +`0.3.14`という数字は、実際には`^0.3.14`の省略記法で、これは、「バージョン0.3.14と互換性のある公開APIを持つ +バージョンならなんでも」を意味します。 [semver]: http://semver.org -Now, without changing any of the code, let’s build the project, as shown in -Listing 2-2: +さて、コードは一切変えずに、プロジェクトをビルドしましょう。リスト2-2に示したようにね: ```text $ cargo build - Updating registry `https://github.com/rust-lang/crates.io-index` - Downloading rand v0.3.14 - Downloading libc v0.2.14 - Compiling libc v0.2.14 - Compiling rand v0.3.14 - Compiling guessing_game v0.1.0 (file:///projects/guessing_game) + Updating registry `https://github.com/rust-lang/crates.io-index` (レジストリを更新しています) + Downloading rand v0.3.14 (rand v0.3.14をダウンロードしています) + Downloading libc v0.2.14 (libc v0.2.14をダウンロードしています) + Compiling libc v0.2.14 (libc v0.2.14をコンパイルしています) + Compiling rand v0.3.14 (rand v0.3.14をコンパイルしています) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) (guessing_game v0.1.0をコンパイルしています) ``` -Listing 2-2: The output from running `cargo build` after -adding the rand crate as a dependency +リスト2-2: randクレートを依存ファイルとして追加した後の`cargo build`コマンドの出力 -You may see different version numbers (but they will all be compatible with -the code, thanks to SemVer!), and the lines may be in a different order. +もしかしたら、バージョンナンバーは違うかもしれません(でも、互換性はあります、SemVerのおかげでね!) +そして、行の出力順序も違うかもしれません。 -Now that we have an external dependency, Cargo fetches the latest versions of -everything from the *registry*, which is a copy of data from -[Crates.io][cratesio]. Crates.io is where people in the Rust ecosystem post -their open source Rust projects for others to use. +今や、外部依存ファイルを持つようになったので、Cargoは*registry*(登録所)から最新バージョンを拾ってきます。 +*レジストリ*とは、[Crates.io][cratesio]のデータのコピーです. Crates.ioとは、Rustのエコシステムにいる人間が +他の人も使えるように自分のオープンソースのRustプロジェクトを投稿する場所です。 [cratesio]: https://crates.io -After updating the registry, Cargo checks the `[dependencies]` section and -downloads any you don’t have yet. In this case, although we only listed `rand` -as a dependency, Cargo also grabbed a copy of `libc`, because `rand` depends on -`libc` to work. After downloading them, Rust compiles them and then compiles -the project with the dependencies available. +レジストリの更新後、Cargoは`[dependencies]`セクションをチェックし、まだ取得していないものを全部ダウンロードします。 +今回の場合、`rand`しか依存ファイルには列挙していませんが、Cargoは`libc`のコピーも拾ってきます。 +`rand`クレートが`libc`に依存しているからですね。ダウンロード完了後、コンパイラは依存ファイル、 +そして、依存ファイルが利用可能な状態でプロジェクトをコンパイルします。 -If you immediately run `cargo build` again without making any changes, you won’t -get any output. Cargo knows it has already downloaded and compiled the -dependencies, and you haven't changed anything about them in your *Cargo.toml* -file. Cargo also knows that you haven't changed anything about your code, so it -doesn't recompile that either. With nothing to do, it simply exits. If you open -up the *src/main.rs* file, make a trivial change, then save it and build again, -you’ll only see one line of output: +何も変更せず即座に`cargo build`コマンドを走らせたら、何も出力されないでしょう。 +Cargoは、すでに依存ファイルをダウンロードしてコンパイル済みであることを検知し、プログラマが +*Cargo.toml*ファイルを弄ってないからです。さらに、Cargoはプログラマがコードを変更していないことも +検知するので、再度コンパイルすることもありません。することがないので、ただ単に終了します。 +*src/main.rs*ファイルを開き、些細な変更をし、保存して再度ビルドを行えば、1行だけ出力があるでしょう: ```text $ cargo build Compiling guessing_game v0.1.0 (file:///projects/guessing_game) ``` -This line shows Cargo only updates the build with your tiny change to the -*src/main.rs* file. Your dependencies haven't changed, so Cargo knows it can -reuse what it has already downloaded and compiled for those. It just rebuilds -your part of the code. +この行は、Cargoが*src/main.rs*ファイルへの取るに足らない変更に対してビルドを更新していることを示しています。 +依存ファイルは変更していないので、Cargoは、すでにダウンロードし、コンパイル済みの依存ファイルを使用できると +検知します。自分で書いたコードのみ再ビルドをかけるわけです。 -#### The *Cargo.lock* File Ensures Reproducible Builds +#### *Cargo.lock*ファイルで再生成可能なビルドを保証する -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, what -happens if next week version `v0.3.15` of the `rand` crate comes out and -contains an important bug fix but also contains a regression that will break -your code? +Cargoには、プログラマが自分のコードを更新するたびに同じ生成物を再構成することを保証してくれるメカニズムを +備えています: Cargoは、プログラマが明示するまで、指定したバージョンの依存ファイルのみを使用してくれるでしょう。 +例として、`rand`クレートの次週のバージョン`v0.3.15`が登場し、重要なバグ修正がなされているけれども、 +自分のコードを破壊してしまう互換性破壊があった場合はどうなるでしょう? -The answer to this problem is the *Cargo.lock* file, which was created the -first time you ran `cargo build` and is now in your *guessing_game* directory. -When you build a project for the first time, Cargo figures out all the -versions of the dependencies that fit the criteria and then writes them to -the *Cargo.lock* file. When you build your project in the future, Cargo will -see that the *Cargo.lock* file exists and use the versions specified there -rather than doing all the work of figuring out versions again. This lets you -have a reproducible build automatically. In other words, your project will -remain at `0.3.14` until you explicitly upgrade, thanks to the *Cargo.lock* -file. +この問題に対する回答は、*Cargo.lock*ファイルであり、このファイルは、初めて`cargo build`コマンドを +走らせた時に生成され、*guessing_game*ディレクトリに存在しています。プロジェクトを始めてビルドする際に、 +Cargoは判断基準(criteria)に合致する依存ファイルのバージョンを割り出し、*Cargo.lock*ファイルに記述します。 +次にプロジェクトをビルドする際には、Cargoは*Cargo.lock*ファイルが存在することを確かめ、 +再度バージョン割り出しの作業を行うのではなく、そこに指定されているバージョンを使用するでしょう。 +このことにより、自動的に再生成可能なビルドを構成できるのです。つまり、明示的にアップグレードしない限り、 +プロジェクトが使用するバージョンは`0.3.14`に保たれるのです。*Cargo.lock*ファイルのおかげでね。 -#### Updating a Crate to Get a New Version +#### クレートを更新して新バージョンを取得する -When you *do* want to update a crate, Cargo provides another command, `update`, -which will: +クレートを*本当に*アップグレードする必要が出てきたら、Cargoの別のコマンド(`update`)を使用しましょう。これは: -1. Ignore the *Cargo.lock* file and figure out all the latest versions that fit -your specifications in *Cargo.toml*. -1. If that works, Cargo will write those versions to the *Cargo.lock* file. +1. *Cargo.lock*ファイルを無視して*Cargo.toml*ファイルに指定された通りの最新バージョンを全て割り出します。 +1. それがうまくいったら、Cargoはそれらのバージョンを*Cargo.lock*ファイルに記述します。 -But by default, Cargo will only look for versions larger than `0.3.0` and -smaller than `0.4.0`. If the `rand` crate has released two new versions, -`0.3.15` and `0.4.0`, you would see the following if you ran `cargo update`: +しかし標準でCargoは、`0.3.0`以上、`0.4.0`未満のバージョンのみを検索します。`rand`クレートの新バージョンが +2つリリースされていたら(`0.3.15`と`0.4.0`ですね)、`cargo update`コマンドを走らせた時に以下のような +メッセージを目の当たりにするでしょう: ```text $ cargo update Updating registry `https://github.com/rust-lang/crates.io-index` + (レジストリ`https://github.com/rust-lang/crates-io-index`を更新しています) Updating rand v0.3.14 -> v0.3.15 + (randクレートをv0.3.14 -> v0.3.15に更新しています) ``` -At this point, you would also notice a change in your *Cargo.lock* file noting -that the version of the `rand` crate you are now using is `0.3.15`. +ここで、プログラマはさらに*Cargo.lock*ファイルの中身が、現在使用している`rand`クレートのバージョンは、 +`0.3.15`になっていることに気付くでしょう。 -If you wanted to use `rand` version `0.4.0` or any version in the `0.4.x` -series, you’d have to update the *Cargo.toml* file to look like this instead: +`rand`のバージョン`0.4.0`または、`0.4.x`シリーズのどれかを使用したかったら、 +代わりに*Cargo.toml*ファイルを以下のように更新しなければならないでしょう: ```toml [dependencies] @@ -479,25 +438,22 @@ series, you’d have to update the *Cargo.toml* file to look like this instead: rand = "0.4.0" ``` -The next time you run `cargo build`, Cargo will update the registry of crates -available and reevaluate your `rand` requirements according to the new version -you specified. +次回、`cargo build`コマンドを走らせたら、Cargoは利用可能なクレート登録所を更新し、`rand`クレートの +必要条件を指定した新しいバージョンに再評価します。 -There’s a lot more to say about [Cargo][doccargo] and [its -ecosystem][doccratesio] that Chapter 14 will discuss, but for -now, that’s all you need to know. Cargo makes it very easy to reuse libraries, -so Rustaceans are able to write smaller projects that are assembled from a -number of packages. +まだ第14章で議論する[Cargo][doccargo]と[そのエコシステム][doccratesio] +については述べたいことが山ほどありますが、とりあえずは、これで知っておくべきことは全てです。 +Cargoのおかげでライブラリはとても簡単に再利用ができるので、Rust市民(Rustaceans)は数多くのパッケージから +構成された小規模のプロジェクトを書くことができるのです。 [doccargo]: http://doc.crates.io [doccratesio]: http://doc.crates.io/crates-io.html -### Generating a Random Number +### 乱数を生成する -Let’s start *using* `rand`. The next step is to update *src/main.rs*, as shown -in Listing 2-3: +`rand`クレートを*使用*開始しましょう。次のステップは、*src/main.rs*ファイルを更新することです。リスト2-3みたいにね: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore extern crate rand; @@ -510,61 +466,52 @@ fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); - println!("The secret number is: {}", secret_number); + println!("The secret number is: {}", secret_number); //秘密の数字は次の通り println!("Please input your guess."); let mut guess = String::new(); io::stdin().read_line(&mut guess) - .expect("Failed to read line"); + .expect("Failed to read line"); //行の読み込みに失敗しました println!("You guessed: {}", guess); } ``` -Listing 2-3: Code changes needed in order to generate a -random number - -We’re adding a `extern crate rand;` line to the top that lets Rust know we’ll be -using that external dependency. This also does the equivalent of calling `use -rand`, so now we can call anything in the `rand` crate by prefixing it with -`rand::`. - -Next, we’re adding another `use` line: `use rand::Rng`. `Rng` is a trait that -defines methods that random number generators implement, and this trait must be -in scope for us to use those methods. Chapter 10 will cover traits in detail. - -Also, we’re adding two more lines in the middle. The `rand::thread_rng` function -will give us the particular random number generator that we’re going to use: -one that is local to the current thread of execution and seeded by the -operating system. Next, we call the `gen_range` method on the random number -generator. This method is defined by the `Rng` trait that we brought into -scope with the `use rand::Rng` statement. The `gen_range` method takes two -numbers as arguments and generates a random number between them. It’s inclusive -on the lower bound but exclusive on the upper bound, so we need to specify `1` -and `101` to request a number between 1 and 100. - -Knowing which traits to use and which functions and methods to call from a -crate isn’t something that you’ll just *know*. Instructions for using a crate -are in each crate’s documentation. Another neat feature of Cargo is that you -can run the `cargo doc --open` command that will build documentation provided -by all of your dependencies locally and open it in your browser. If you’re -interested in other functionality in the `rand` crate, for example, run `cargo -doc --open` and click `rand` in the sidebar on the left. - -The second line that we added to the code prints the secret number. This is -useful while we’re developing the program to be able to test it, but we’ll -delete it from the final version. It’s not much of a game if the program prints -the answer as soon as it starts! - -Try running the program a few times: +リスト2-3: 乱数を生成するのに必要なコードの変更 + +冒頭に`extern crate rand;`行を追加して、コンパイラにこの外部依存ファイルを使用することを知らせています。 +これにより、`use rand`を呼ぶのと同じ効果が得られるので、`rand`クレートのものを`rand::` +という接頭辞をつけて呼び出せるようになりました。 + +次に、別の`use`行を追加しています: `use rand::Rng`ですね。`Rng`とは乱数生成器が実装するメソッドを定義した +トレイトであり、このトレイトがスコープにないと、メソッドを使用できないのです。トレイトについて詳しくは、 +第10章を参照されたし。 + +また、途中に2行追加もしています。`rand::thread_rng`関数は、私たちが使う特定の乱数生成器を +返してくれます: この乱数生成器は、実行スレッドに特有で、OSにより、シード値を与えられています。 +次に、この乱数生成器の`gen_range`メソッドを呼び出しています。このメソッドは、`use rand::Rng`文で +スコープに導入した`Rng`トレイトで定義されています。`gen_range`メソッドは二つの数字を引数に取り、 +それらの間の乱数を生成してくれます。最低値は含むものの、最高値は含まないため、`1`と`101`と指定しないと +1から100の範囲の数字は得られません。 + +使用すべきトレイトとクレートから呼び出すべき関数とメソッドを知ることが、単純に*知っている*ことではないでしょう。 +クレートの使用方法は、各クレートのドキュメントにある。Cargoの別の巧妙な機能は、`cargo doc --open`コマンドを +走らせてローカルに存在する依存ファィルすべてのドキュメントをビルドし、Webブラウザで閲覧できる機能です。例えば、 +`rand`クレートの他の機能に興味があるなら、`cargo doc --open`コマンドを走らせて、左側のサイドバーから +`rand`をクリックすればいいわけです。 + +コードに追加した2行目は、秘密の数字を出力してくれます。これは、プログラムをテストする構築中には便利であるが、 +最終版からは削除する予定です。プログラムがスタートと同時に答えを出力しちゃったら、ゲームにならないからですね! + +何回かプログラムを走らせてみてください: ```text $ cargo run Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Running `target/debug/guessing_game` -Guess the number! +Guess the number! (何回も出ているので、ここでは和訳は省略します) The secret number is: 7 Please input your guess. 4 @@ -578,15 +525,14 @@ Please input your guess. You guessed: 5 ``` -You should get different random numbers, and they should all be numbers between -1 and 100. Great job! +毎回異なる乱数が出、その数字はすべて1から100の範囲になるはずです。よくやりました! -## Comparing the Guess to the Secret Number +## 予想と秘密の数字を比較する -Now that we have user input and a random number, we can compare them. That -step is shown in Listing 2-4: +今や、ユーザ入力と乱数生成ができるようになったので、比較することができますね。 +このステップはリスト2-4に示されています: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore extern crate rand; @@ -612,23 +558,20 @@ fn main() { println!("You guessed: {}", guess); match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), + Ordering::Less => println!("Too small!"), //小さすぎ! + Ordering::Greater => println!("Too big!"), //大きすぎ! + Ordering::Equal => println!("You win!"), //やったね! } } ``` -Listing 2-4: Handling the possible return values of -comparing two numbers +リスト2-4: 2値比較の返り値を処理する -The first new bit here is another `use`, bringing a type called -`std::cmp::Ordering` into scope from the standard library. `Ordering` is -another enum, like `Result`, but the variants for `Ordering` are `Less`, -`Greater`, and `Equal`. These are the three outcomes that are possible when you -compare two values. +最初の新しい点は、別の`use`文です。これで、`std::cmp::Ordering`という型を標準ライブラリから +スコープに導入しています。`Ordering`もenumです。`Result`のようにね。ただ、`Ordering`が取りうる値は、 +`Less`、`Greater`そして、`Equal`です。これらは、2値比較した時に発生しうる3種類の結果です。 -Then we add five new lines at the bottom that use the `Ordering` type: +それから、一番下に5行追加して`Ordering`型を使用しています: ```rust,ignore match guess.cmp(&secret_number) { @@ -638,70 +581,60 @@ match guess.cmp(&secret_number) { } ``` -The `cmp` method compares two values and can be called on anything that can be -compared. It takes a reference to whatever you want to compare with: here it’s -comparing the `guess` to the `secret_number`. `cmp` returns a variant of the -`Ordering` enum we brought into scope with the `use` statement. We use a -[`match`][match] expression to decide what to do next based on -which variant of `Ordering` was returned from the call to `cmp` with the values -in `guess` and `secret_number`. +`cmp`メソッドは、2値を比較し、比較できるものに対してならなんに対しても呼び出せます。このメソッドは、 +比較したいものへの参照を取ります: ここでは、`guess`変数と`secret_number`変数を比較しています。 +`cmp`メソッドは`use`文でスコープに導入した`Ordering`列挙型の値を返します。 +[`match`][match]式を使用して、`guess`変数と`secret_number`を`cmp`に渡して +返ってきた`Ordering`の値に基づき、次の動作を決定しています。 [match]: ch06-02-match.html -A `match` expression is made up of *arms*. An arm consists of a *pattern* and -the code that should be run if the value given to the beginning of the `match` -expression fits that arm’s pattern. Rust takes the value given to `match` and -looks through each arm’s pattern in turn. The `match` construct and patterns -are powerful features in Rust that let you express a variety of situations your -code might encounter and helps ensure that you handle them all. These features -will be covered in detail in Chapter 6 and Chapter 18, respectively. - -Let’s walk through an example of what would happen with the `match` expression -used here. Say that the user has guessed 50, and the randomly generated secret -number this time is 38. When the code compares 50 to 38, the `cmp` method will -return `Ordering::Greater`, because 50 is greater than 38. `Ordering::Greater` -is the value that the `match` expression gets. It looks at the first arm’s -pattern, `Ordering::Less`, but the value `Ordering::Greater` does not match -`Ordering::Less`, so it ignores the code in that arm and moves to the next arm. -The next arm’s pattern, `Ordering::Greater`, *does* match -`Ordering::Greater`! The associated code in that arm will execute and print -`Too big!` to the screen. The `match` expression ends because it has no need to -look at the last arm in this particular scenario. - -However, the code in Listing 2-4 won’t compile yet. Let’s try it: +`match`式は、複数の*アーム*(腕)からできています。一つのアームは、パターンとそのパターンに +`match`式の冒頭で与えた値がマッチした時に走るコードから構成されています。Rustは、`match`に与えられた +値を取り、各アームのパターンを順番に吟味していきます。`match`式とパターンは、コードを書く際に +目の当たりにする様々なシチュエーションを表現させてくれ、すべてのシチュエーションに対処する手助けをしてくれる +Rustの強力な機能です。これらの機能は、それぞれ、第6章と第18章で詳しく解説することにします。 + +ここで使われている`match`式でどんなことが起こるかの例をじっくり観察してみましょう!例えば、 +ユーザは50と予想し、ランダム生成された秘密の数字は今回、38だったとしましょう。コードが50と38を比較すると、 +`cmp`メソッドは`Ordering::Greater`を返します。50は38よりも大きいからですね。`Ordering::Greater`が、 +`match`式に渡される値になります。まず、最初のアームのパターンを吟味します(`Ordering::Less`ですね)。しかし、 +値の`Ordering::Greater`と`Ordering::Less`はマッチしないため、このアームのコードは無視され、 +次のアームに移ります。次のアームのパターン、`Ordering::Greater`は*見事に*`Ordering::Greater`とマッチします! +このアームに紐づけられたコードが実行され、画面に`Too big!`が表示されます。 +これで`match`式の実行は終わりになります。この筋書きでは、最後のアームを吟味する必要はもうないからですね。 + +ところが、リスト2-4のコードは、まだコンパイルが通りません。試してみましょう: ```text $ cargo build Compiling guessing_game v0.1.0 (file:///projects/guessing_game) -error[E0308]: mismatched types +error[E0308]: mismatched types (型が合いません) --> src/main.rs:23:21 | 23 | match guess.cmp(&secret_number) { | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found integral variable + | (構造体`std::string::String`を予期したけど、整数型変数が見つかりました) | = note: expected type `&std::string::String` = note: found type `&{integer}` -error: aborting due to previous error -Could not compile `guessing_game`. +error: aborting due to previous error (先のエラーのため、処理を中断します) +Could not compile `guessing_game`. (`guessing_game`をコンパイルできませんでした) ``` -The core of the error states that there are *mismatched types*. Rust has a -strong, static type system. However, it also has type inference. When we wrote -`let guess = String::new()`, Rust was able to infer that `guess` should be a -`String` and didn’t make us write the type. The `secret_number`, on the other -hand, is a number type. A few number types can have a value between 1 and 100: -`i32`, a 32-bit number; `u32`, an unsigned 32-bit number; `i64`, a 64-bit -number; as well as others. Rust defaults to an `i32`, which is the type of -`secret_number` unless we add type information elsewhere that would cause Rust -to infer a different numerical type. The reason for the error is that Rust will -not compare a string and a number type. - -Ultimately, we want to convert the `String` the program reads as input into a -real number type so we can compare it to the guess numerically. We can do -that by adding the following two lines to the `main` function body: +このエラーの核は、*型の不一致*があると言っています。Rustは、強力な静的型付けシステムを持っています。 +しかし、型推論にも対応しています。`let guess = String::new()`と書いた時、コンパイラは、 +`guess`が`String`型であるべきと推論してくれ、その型を明示させられることはありませんでした。 +一方で、`secret_number`変数は、数値型です。少数の数値型しか1から100を表すことはできません: +`i32`は32ビットの数字; `u32`は32ビットの非負数字; `i64`は64ビットの数字;などです。 +Rustでの標準は、`i32`型であり、型情報をどこかに追加して、コンパイラに異なる数値型だと推論させない限り、 +`secret_number`の型はこれになります。エラーの原因は、Rustでは、文字列と数値型を比較できないことです。 -Filename: src/main.rs +究極的には、プログラムが入力として読み込む`String`型を現実の数値型に変換し、予想と数値として比較できるように +したいわけです。これは、以下の2行を`main`関数の本体に追記することでできます: + +ファイル名: src/main.rs ```rust,ignore extern crate rand; @@ -725,7 +658,7 @@ fn main() { .expect("Failed to read line"); let guess: u32 = guess.trim().parse() - .expect("Please type a number!"); + .expect("Please type a number!"); //数値を入力してください! println!("You guessed: {}", guess); @@ -737,56 +670,48 @@ fn main() { } ``` -The two new lines are: +その2行とは以下のようなものです: ```rust,ignore let guess: u32 = guess.trim().parse() .expect("Please type a number!"); ``` -We create a variable named `guess`. But wait, doesn’t the program -already have a variable named `guess`? It does, but Rust allows us to -*shadow* the previous value of `guess` with a new one. This feature is often -used in similar situations in which you want to convert a value from one type -to another type. Shadowing lets us reuse the `guess` variable name rather than -forcing us to create two unique variables, like `guess_str` and `guess` for -example. (Chapter 3 covers shadowing in more detail.) - -We bind `guess` to the expression `guess.trim().parse()`. The `guess` in the -expression refers to the original `guess` that was a `String` with the input in -it. The `trim` method on a `String` instance will eliminate any whitespace at -the beginning and end. `u32` can only contain numerical characters, but the -user must press the Return key to satisfy `read_line`. When the user presses -Return, a newline character is added to the string. For example, if the user -types 5 and presses return, `guess` looks like this: `5\n`. The `\n` represents -“newline,” the return key. The `trim` method eliminates `\n`, resulting in just -`5`. - -The [`parse` method on strings][parse] parses a string into some -kind of number. Because this method can parse a variety of number types, we -need to tell Rust the exact number type we want by using `let guess: u32`. The -colon (`:`) after `guess` tells Rust we’ll annotate the variable’s type. Rust -has a few built-in number types; the `u32` seen here is an unsigned, 32-bit -integer. It’s a good default choice for a small positive number. You’ll learn -about other number types in Chapter 3. Additionally, the `u32` annotation in -this example program and the comparison with `secret_number` means that Rust -will infer that `secret_number` should be a `u32` as well. So now the -comparison will be between two values of the same type! +`guess`という名前の変数を生成しています。あれ、でも待って。もうプログラムには`guess`という名前の変数が +ありませんでしたっけ?確かにありますが、Rustでは、新しい値で`guess`の値を*多重定義*(shadow)することが +許されているのです。この機能は、今回のような、値を別の型に変換したいシチュエーションでよく使われます。 +多重定義のおかげで別々の変数を2つ作らされることなく、`guess`という変数名を再利用することができるのです。 +`guess_str`と`guess`みたいなね(多重定義については、第3章でもっと掘り下げます)。 + +`guess`を`guess.trim().parse()`という式に束縛しています。この式中の`guess`は、入力が入った +`String`型の元々の`guess`を指しています。`String`オブジェクトの`trim`メソッドは、 +両端の空白をすべて除去します。`u32`型は、数字しか含むことができませんが、ユーザは、`read_line`の +処理を終えるためにリターンキーを押さなければなりません。ユーザがリターンキーを押したら、改行文字が +文字列に追加されます。具体例として、ユーザが5を入力して、リターンキーを押せば、`guess`変数は +次のようになります: `5\n`。この`\n`が改行、つまりリターンキーを表しているわけです。 +`trim`メソッドは、`\n`を削除するので、ただの`5`になります。 + +[文字列の`parse`メソッド][parse]は、文字列を解析して何らかの数値にします。 +このメソッドは、いろんな数値型を解析できるので、`let guess: u32`としてコンパイラに私たちが +求めている型をズバリ示唆する必要があるのです。`guess`の後のコロン(`:`)がコンパイラに変数の型を +注釈する合図になります。Rustには、組み込みの数値型がいくつかあります; ここで見られる`u32`型は、 +32ビットの非負整数です。小さな非負整数は、良い基準になります。他の数値型については、第3章で学ぶでしょう。 +付け加えると、このサンプルプログラムの`u32`という注釈と`secret_number`変数との比較は、 +`secret_number`変数も`u32`型であるとコンパイラが推論することを意味します。さて、従って、比較が同じ型の +2つの値で行われることになります。 [parse]: ../../std/primitive.str.html#method.parse -The call to `parse` could easily cause an error. If, for example, the string -contained `A👍%`, there would be no way to convert that to a number. Because it -might fail, the `parse` method returns a `Result` type, much like the -`read_line` method does as discussed earlier in “Handling Potential Failure -with the Result Type”. We’ll treat this `Result` the same way by -using the `expect` method again. If `parse` returns an `Err` `Result` variant -because it couldn’t create a number from the string, the `expect` call will -crash the game and print the message we give it. If `parse` can successfully -convert the string to a number, it will return the `Ok` variant of `Result`, -and `expect` will return the number that we want from the `Ok` value. +`parse`メソッドの呼び出しは、エラーになりやすいです。例としては、文字列が`A👍%`を含んでいたら、 +数値に変換できるわけがないわけです。失敗する可能性があるので、`parse`メソッドは、`Result`型を +返すわけです。ちょうど、「Result型で失敗する可能性に対処する」節で先ほど議論した`read_line`メソッドが +するようにというわけですね。今回も、`expect`メソッドを使用して`Result`型を同じように扱います。 +もし、文字列から数値を生成できなかったために、`parse`メソッドが`Result`型の`Err`値を返したら、 +`expect`メソッドの呼び出しは、ゲームをクラッシュさせ、与えたメッセージを表示します。 +もし、`parse`メソッドが文字列の数値への変換に成功したら、`Result`型の`Ok`値を返し、 +`expect`メソッドは、`Ok`値から必要な数値を返してくれます。 -Let’s run the program now! +さあ、プログラムを走らせましょう! ```text $ cargo run @@ -800,20 +725,18 @@ You guessed: 76 Too big! ``` -Nice! Even though spaces were added before the guess, the program still figured -out that the user guessed 76. Run the program a few times to verify the -different behavior with different kinds of input: guess the number correctly, -guess a number that is too high, and guess a number that is too low. +いいですね!予想の前にスペースを追加したにもかかわらず、プログラムはちゃんとユーザが76と予想したことを +導き出しました。プログラムを何回か走らせて、異なる入力の異なる振る舞いを確認してください: つまり、 +数字を正しく言い当てたり、大きすぎる値を予想したり、低すぎる数字を入力したりということです。 -We have most of the game working now, but the user can make only one guess. -Let’s change that by adding a loop! +ここまでで大方ゲームはうまく動くようになりましたが、まだユーザは1回しか予想できません。 +ループを追加して、その部分を変更しましょう! -## Allowing Multiple Guesses with Looping +## ループで複数回の予想を可能にする -The `loop` keyword gives us an infinite loop. Add that now to give users more -chances at guessing the number: +`loop`キーワードは、無限ループを作り出します。これを追加して、ユーザが何回も予想できるようにしましょう: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore extern crate rand; @@ -851,17 +774,14 @@ fn main() { } ``` -As you can see, we’ve moved everything into a loop from the guess input prompt -onward. Be sure to indent those lines another four spaces each, and run the -program again. Notice that there is a new problem because the program is doing -exactly what we told it to do: ask for another guess forever! It doesn’t seem -like the user can quit! +見てわかる通り、予想入力部分以降をループに入れ込みました。変更した行にインデントを追加するのを忘れないようにして、 +またプログラムを走らせてみましょう。新たな問題が発生したことに気をつけてください。 +プログラムが教えた通りに動作しているからですね: 永遠に予想入力を求めるわけです!これでは、終了できません! -The user could always halt the program by using the keyboard shortcut `Ctrl-C`. -But there’s another way to escape this insatiable monster that we mentioned in -the `parse` discussion in “Comparing the Guess to the Secret Number”: if the user -enters a non-number answer, the program will crash. The user can take advantage -of that in order to quit, as shown here: +ユーザは、`Ctrl-C`というキーボードショートカットを使って、いつでもプログラムを強制終了させられます。 +しかし、「予想を秘密の数字と比較する」節の`parse`メソッドに関する議論で触れたこの貪欲なモンスターを +回避する別の方法があります: ユーザが数字以外の答えを入力すれば、プログラムはクラッシュするのです。 +ユーザは、その利点を活かして、終了することができます。以下のようにね: ```text $ cargo run @@ -884,19 +804,21 @@ You win! Please input your guess. quit thread 'main' panicked at 'Please type a number!: ParseIntError { kind: InvalidDigit }', src/libcore/result.rs:785 +(スレッド'main'は'数字を入力してください!: ParseIntError { kind: InvalidDigit }', src/libcore/result.rs:785でパニックしました) note: Run with `RUST_BACKTRACE=1` for a backtrace. +(注釈: `RUST_BACKTRACE=1`で走らせるとバックトレースを見れます) error: Process didn't exit successfully: `target/debug/guess` (exit code: 101) +(エラー: プロセスは予期なく終了しました) ``` -Typing `quit` actually quits the game, but so will any other non-number input. -However, this is suboptimal to say the least. We want the game to automatically -stop when the correct number is guessed. +`quit`と入力すれば、実際にゲームを終了できるわけですが、別に他の数字以外の入力でもそうなります。 +しかしながら、これは最低限度と言えるでしょう。正しい数字が予想されたら、自動的にゲームが停止してほしいわけです。 -### Quitting After a Correct Guess +### 正しい予想をした後に終了する -Let’s program the game to quit when the user wins by adding a `break`: +`break`文を追加してユーザが勝った時にゲームを終了するようにしましょう: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore extern crate rand; @@ -937,16 +859,15 @@ fn main() { } ``` -By adding the `break` line after `You win!`, the program will exit the loop -when the user guesses the secret number correctly. Exiting the loop also means -exiting the program, because the loop is the last part of `main`. +`break`文の1行を`You win!`の後に追記することで、ユーザが秘密の数字を正確に予想したら、プログラムは +ループを抜けるようになりました。ついでに、ループを抜けることは、プログラムを終了することを意味します。 +ループが`main`関数の最後の部分だからですね。 -### Handling Invalid Input +### 不正な入力を処理する -To further refine the game’s behavior, rather than crashing the program when -the user inputs a non-number, let’s make the game ignore a non-number so the -user can continue guessing. We can do that by altering the line where `guess` is -converted from a `String` to a `u32`: +さらにゲームの振る舞いを改善するために、ユーザが数値以外を入力した時にプログラムをクラッシュさせるのではなく、 +非数値を無視してユーザが数当てを続けられるようにしましょう!これは、`guess`が`String`型から +`u32`方に変換される行を改変することで達成できます: ```rust,ignore let guess: u32 = match guess.trim().parse() { @@ -955,30 +876,25 @@ let guess: u32 = match guess.trim().parse() { }; ``` -Switching from an `expect` call to a `match` expression is how you generally -move from crash on error to actually handling the error. Remember that `parse` -returns a `Result` type, and `Result` is an enum that has the variants `Ok` or -`Err`. We’re using a `match` expression here, like we did with the `Ordering` -result of the `cmp` method. - -If `parse` is able to successfully turn the string into a number, it will return -an `Ok` value that contains the resulting number. That `Ok` value will match the -first arm’s pattern, and the `match` expression will just return the `num` value -that `parse` produced and put inside the `Ok` value. That number will end up -right where we want it in the new `guess` variable we’re creating. - -If `parse` is *not* able to turn the string into a number, it will return an -`Err` value that contains more information about the error. The `Err` value -does not match the `Ok(num)` pattern in the first `match` arm, but it does match -the `Err(_)` pattern in the second arm. The `_` is a catchall value; in this -example, we’re saying we want to match all `Err` values, no matter what -information they have inside them. So the program will execute the second arm’s -code, `continue`, which means to go to the next iteration of the `loop` and ask -for another guess. So effectively, the program ignores all errors that `parse` -might encounter! - -Now everything in the program should work as expected. Let’s try it by running -`cargo run`: +`expect`メソッドの呼び出しから`match`式に切り替えることは、エラーでクラッシュする動作から +実際にエラー処理を行う処理へ変更する一般的な手段になります。`parse`メソッドは、`Result`型を +返し、`Result`は`Ok`か`Err`の値を取りうるenumであることを思い出してください。 +ここでは`match`式を使っています。`cmp`メソッドの`Ordering`という結果でしたのと同じですね。 + +`parse`メソッドは、文字列から数値への変換に成功したら、結果の数値を保持する`Ok`値を返します。 +この`Ok`値は、最初のアームのパターンにマッチし、この`match`式は`parse`メソッドが生成し、 +`Ok`値に格納した`num`の値を返すだけです。その数値が最終的に生成した新しい`guess`変数に +含まれます。 + +`parse`メソッドは、文字列から数値への変換に*失敗*したら、エラーに関する情報を多く含む`Err`値を +返します。この`Err`値は、最初の`match`アームの`Ok(num)`というパターンにはマッチしないものの、 +2番目のアームの`Err(_)`というパターンにはマッチするわけです。この`_`は、包括値です; この例では、 +保持している情報がどんなものでもいいから全ての`Err`値にマッチさせたいと宣言しています。 +従って、プログラムは2番目のアームのコードを実行し(`continue`ですね)、これは、`loop`の +次の段階に移り、再度予想入力を求めることを意味します。故に実効的には、プログラムは`parse`メソッドが +遭遇しうる全てのエラーを無視するようになります! + +さて、プログラムの全てがうまく予想通りに動くはずです。`cargo run`コマンドで走らせて、試してみましょう: ```text $ cargo run @@ -1002,12 +918,12 @@ You guessed: 61 You win! ``` -Awesome! With one tiny final tweak, we will finish the guessing game: recall -that the program is still printing out the secret number. That worked well for -testing, but it ruins the game. Let’s delete the `println!` that outputs the -secret number. Listing 2-5 shows the final code: +素晴らしい!最後にひとつまみ変更を加えて、数当てゲームを完了にしましょう: プログラムが未だに +秘密の数字を出力していることを思い出してください。テスト中はうまく動くけど、 +ゲームを台無しにしてしまいます。秘密の数字を出力する`println!`マクロを削除しましょう。 +リスト2-5が成果物のコードです: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore extern crate rand; @@ -1048,17 +964,16 @@ fn main() { } ``` -Listing 2-5: Complete code of the guessing game +リスト2-5: 数当てゲームの完全なコード -## Summary +## まとめ -At this point, you’ve successfully built the guessing game! Congratulations! +ここまでで、数当てゲームの作成に成功しました!おめでとうございます! -This project was a hands-on way to introduce you to many new Rust concepts: -`let`, `match`, methods, associated functions, using external crates, and more. -In the next few chapters, you’ll learn about these concepts in more detail. -Chapter 3 covers concepts that most programming languages have, such as -variables, data types, and functions, and shows how to use them in Rust. -Chapter 4 explores ownership, which is a Rust feature that is most different -from other languages. Chapter 5 discusses structs and method syntax, and -Chapter 6 endeavors to explain enums. +このプロジェクトは、たくさんの新しいRustの概念に触れる実践的な方法でした: +`let`文、`match`式、メソッド、関連付け関数、外部クレートの使用などなど。 +以降の数章で、これらの概念についてより深く学ぶことになるでしょう。 +第3章では、ほとんどのプログラミング言語が持っている、変数、データ型、関数などの概念について解説し、 +それらのRustでの使用方法について示します。 +第4章では、所有権について見ます。所有権は、他の言語とかけ離れているRustの機能の一つです。 +第5章では、構造体とメソッド記法について議論し、第6章ではenumについて説明する努力をしましょう。 diff --git a/second-edition/src/ch03-00-common-programming-concepts.md b/second-edition/src/ch03-00-common-programming-concepts.md index c64f32959..8e717ec07 100644 --- a/second-edition/src/ch03-00-common-programming-concepts.md +++ b/second-edition/src/ch03-00-common-programming-concepts.md @@ -1,20 +1,19 @@ -# Common Programming Concepts +# 一般的なプログラミングの概念 -This chapter covers concepts that appear in almost every programming language -and how they work in Rust. Many programming languages have much in common at -their core. None of the concepts presented in this chapter are unique to Rust, -but we’ll discuss them in the context of Rust and explain their conventions. +この章では、ほとんど全てのプログラミング言語で見られる概念を解説し、それらがRustにおいて、 +どう動作するかを見ていこう。多くのプログラミング言語は、その核心において、いろいろなものを共有しているのです。 +この章で提示する概念は、全てRustに固有のものではありませんが、Rustの文脈で議論し、その表記法を +解説していきます。 -Specifically, you’ll learn about variables, basic types, functions, comments, -and control flow. These foundations will be in every Rust program, and learning -them early will give you a strong core to start from. +具体的には、変数、基本的な型、関数、コメント、そしてフロー制御について学びます。 +これらの基礎は全てのRustプログラムに存在するものであり、それらを早期に学ぶことは +強力な基礎を築くことになるでしょう。 -> ### Keywords +> ### キーワード > -> The Rust language has a set of *keywords* that have been reserved for use by -> the language only, much like other languages do. Keep in mind that you cannot -> use these words as names of variables or functions. Most of the keywords have -> special meanings, and you’ll be using them to do various tasks in your Rust -> programs; a few have no current functionality associated with them but have -> been reserved for functionality that might be added to Rust in the future. You -> can find a list of the keywords in Appendix A. +> Rust言語にも他の言語同様、キーワードが存在し、これらは言語だけが使用できるようになっています。 +> これらの単語は、変数や関数名には使えないことを弁えておいてください。多数のキーワードは、特別な意味を持っており、 +> 自らのRustプログラムにおいて、様々な作業をこなすために使用することができます; +> いくつかは、紐付けられた機能がないものの、将来Rustに追加されるかもしれない機能用に担保されています。 +> キーワードの一覧は、付録Aで確認できます。 + From eeca84ee4aa76b63ef0e82d94862e7d42da567ed Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 12 Jul 2017 21:01:44 +0900 Subject: [PATCH 002/428] First draft of Chapter 3-1 --- .../ch03-00-common-programming-concepts.md | 4 +- .../src/ch03-01-variables-and-mutability.md | 210 ++++++++---------- 2 files changed, 93 insertions(+), 121 deletions(-) diff --git a/second-edition/src/ch03-00-common-programming-concepts.md b/second-edition/src/ch03-00-common-programming-concepts.md index 8e717ec07..7feb257a6 100644 --- a/second-edition/src/ch03-00-common-programming-concepts.md +++ b/second-edition/src/ch03-00-common-programming-concepts.md @@ -1,8 +1,8 @@ # 一般的なプログラミングの概念 この章では、ほとんど全てのプログラミング言語で見られる概念を解説し、それらがRustにおいて、 -どう動作するかを見ていこう。多くのプログラミング言語は、その核心において、いろいろなものを共有しているのです。 -この章で提示する概念は、全てRustに固有のものではありませんが、Rustの文脈で議論し、その表記法を +どう動作するかを見ていこう。多くのプログラミング言語は、その核心において、いろいろなものを共有しています。 +この章で提示する概念は、全てRustに固有のものではありませんが、Rustの文脈で議論し、その規格を 解説していきます。 具体的には、変数、基本的な型、関数、コメント、そしてフロー制御について学びます。 diff --git a/second-edition/src/ch03-01-variables-and-mutability.md b/second-edition/src/ch03-01-variables-and-mutability.md index ef1750d8a..fa96c74b1 100644 --- a/second-edition/src/ch03-01-variables-and-mutability.md +++ b/second-edition/src/ch03-01-variables-and-mutability.md @@ -1,73 +1,65 @@ -## Variables and Mutability +## 変数と可変性 -As mentioned in Chapter 2, by default variables are *immutable*. This is one of -many nudges in Rust that encourages you to write your code in a way that takes -advantage of the safety and easy concurrency that Rust offers. However, you -still have the option to make your variables mutable. Let’s explore how and why -Rust encourages you to favor immutability, and why you might want to opt out. +第2章で触れた通り、変数は標準で*不変*になります。これは、Rustが提供する安全性や簡潔な並列プログラミングの +利点を享受する形でコードを書くことを推奨してくれる一押しです。ところが、まだ変数を可変にするという +選択肢も残されています。不変性を好むようコンパイラが推奨する手段と理由および、それと違う道を選びたくなる理由を +見ていきましょう。 -When a variable is immutable, that means once a value is bound to a name, you -can’t change that value. To illustrate, let’s generate a new project called -*variables* in your *projects* directory by using `cargo new --bin variables`. +変数が不変であるとは、値が一旦名前に束縛されたら、その値を変えることができないことを意味します。 +具体化するために、*projects*ディレクトリに`cargo new --bin variables`コマンドを使って +*variables*という名前のプロジェクトを生成しましょう。 -Then, in your new *variables* directory, open *src/main.rs* and replace its -code with the following: +それから、新規作成した*variables*ディレクトリで、*src/main.rs*ファイルを開き、その中身を以下のように置き換えましょう: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore fn main() { let x = 5; - println!("The value of x is: {}", x); + println!("The value of x is: {}", x); // xの値は{}です x = 6; println!("The value of x is: {}", x); } ``` -Save and run the program using `cargo run`. You should receive an error -message, as shown in this output: +これを保存し、`cargo run`コマンドでプログラムを走らせてください。次の出力に示されているようなエラーメッセージを受け取るはずです: ```text error[E0384]: re-assignment of immutable variable `x` + (不変変数`x`への再代入) --> src/main.rs:4:5 | 2 | let x = 5; | - first assignment to `x` + | (`x`への最初の代入) 3 | println!("The value of x is: {}", x); 4 | x = 6; | ^^^^^ re-assignment of immutable variable ``` -This example shows how the compiler helps you find errors in your programs. -Even though compiler errors can be frustrating, they only mean your program -isn’t safely doing what you want it to do yet; they do *not* mean that you’re -not a good programmer! Experienced Rustaceans still get compiler errors. The -error indicates that the cause of the error is `re-assignment of immutable -variable`, because we tried to assign a second value to the immutable `x` -variable. - -It’s important that we get compile-time errors when we attempt to change a -value that we previously designated as immutable because this very situation -can lead to bugs. If one part of our code operates on the assumption that a -value will never change and another part of our code changes that value, it’s -possible that the first part of the code won’t do what it was designed to do. -This cause of bugs can be difficult to track down after the fact, especially -when the second piece of code changes the value only *sometimes*. - -In Rust the compiler guarantees that when we state that a value won’t change, -it really won’t change. That means that when you’re reading and writing code, -you don’t have to keep track of how and where a value might change, which can -make code easier to reason about. - -But mutability can be very useful. Variables are immutable only by default; we -can make them mutable by adding `mut` in front of the variable name. In -addition to allowing this value to change, it conveys intent to future readers -of the code by indicating that other parts of the code will be changing this -variable value. - -For example, change *src/main.rs* to the following: - -Filename: src/main.rs +この例では、コンパイラがプログラムに潜むエラーを見つけ出す手助けをしてくれることが示されています。 +コンパイルエラーは、イライラするものですが、まだプログラムにしてほしいことを安全に行えていないだけ +なのです; エラーが出るからといって、あなたがいいプログラマではないという意味では*ありません*! +経験豊富なRust市民でも、コンパイラエラーを出すことはあります。このエラーは、エラーの原因が +`不変変数への再代入`であると示しています。不変な`x`という変数に第2段階の値を代入しようとしたからです。 + +以前に不変と指定された値を変えようとした時に、コンパイルエラーが出るのは重要なことです。 +なぜなら、この状況はまさしく、バグに繋がるからです。コードのある部分は、値が変わることはないという +前提のもとに処理を行い、別の部分がその値を変更していたら、最初の部分が目論見通りに +動いていない可能性があるのです。このようなバグの発生は、事実(`脚注`:実際にプログラムを走らせた結果のことと思われる) +の後には追いかけづらいものです。特に第2のコード破片が、値を*時々*しか変えない場合尚更です。 + +Rustでは、値が不変であると宣言したら、本当に変わらないことをコンパイラが担保してくれます。 +つまり、コードを読み書きする際に、どこでどうやって値が変化しているかを追いかける必要がなくなり、 +コードが行うことを把握しやすくなります。 + +しかし、可変性は時として非常に便利なこともあります。変数は、標準でのみ、不変です。つまり、変数名の前に +`mut`キーワードを付ければ、可変にできるわけです。 この値が変化できるようにするとともに、未来の読者に対して +コードの別の部分がこの変数の値を変えることを示すことで、その意図を汲ませることができるのです。 + +例として、*src/main.rs*ファイルを以下のように書き換えてください: + +ファイル名: src/main.rs ```rust fn main() { @@ -78,80 +70,65 @@ fn main() { } ``` -When we run this program, we get the following: +このプログラムを走らせると、以下のような出力が得られます: ```text $ cargo run Compiling variables v0.1.0 (file:///projects/variables) Running `target/debug/variables` -The value of x is: 5 +The value of x is: 5 (xの値は5です) The value of x is: 6 ``` -Using `mut`, we’re allowed to change the value that `x` binds to from `5` to -`6`. In some cases, you’ll want to make a variable mutable because it makes the -code more convenient to write than an implementation that only uses immutable -variables. +`mut`キーワードを使うことで、`x`が束縛している値を`5`から`6`に変更できるようになりました。 +変数を可変にする方が、不変変数だけを使う実装よりも書きやすくなるケースもあるでしょう。 -There are multiple trade-offs to consider, in addition to the prevention of -bugs. For example, in cases where you’re using large data structures, mutating -an instance in place may be faster than copying and returning newly allocated -instances. With smaller data structures, creating new instances and writing in -a more functional programming style may be easier to reason about, so the lower -performance might be a worthwhile penalty for gaining that clarity. +考えるべきトレードオフはバグの阻止以外にも、いくつかあります。例えば、大きなデータ構造を使う場合などです。 +オブジェクトを可変にして変更できるようにする方が、いちいちオブジェクトをコピーして新しくメモリ割り当てされた +オブジェクトを返すよりも速くなります。小規模なデータ構造なら、新規オブジェクトを生成して、 +もっと関数型っぽいコードを書く方が中身を把握しやすくなるため、低パフォーマンスは、その簡潔性を得るのに +足りうるペナルティになるかもしれません。 -### Differences Between Variables and Constants +### 変数と定数(constants)の違い -Being unable to change the value of a variable might have reminded you of -another programming concept that most other languages have: *constants*. Like -immutable variables, constants are also values that are bound to a name and -are not allowed to change, but there are a few differences between constants -and variables. +変数の値を変更できないようにするといえば、他の多くの言語も持っている別のプログラミング概念を思い浮かべるでしょう: +*定数*です. 不変変数のように、定数も名前に紐付き、変更することが叶わない値のことですが、 +定数と変数の間にはいくつかの違いがあります。 -First, we aren’t allowed to use `mut` with constants: constants aren't only -immutable by default, they're always immutable. +まず、定数には`mut`キーワードは使えません: 定数は標準で不変であるだけでなく、常に不変なのです。 -We declare constants using the `const` keyword instead of the `let` keyword, -and the type of the value *must* be annotated. We're about to cover types and -type annotations in the next section, “Data Types,” so don't worry about the -details right now, just know that we must always annotate the type. +定数は`let`キーワードの代わりに、`const`キーワードで宣言し、値の型は*必ず*注釈しなければなりません。 +型と型注釈については次のセクション、「データ型」で解説する予定なので、その詳細については気にする必要はありません。 +ただ単に型を注釈しなければならないのだと思っていてください。 -Constants can be declared in any scope, including the global scope, which makes -them useful for values that many parts of code need to know about. +定数はどんなスコープでも定義できます。グローバルスコープも含めてね。なので、いろんなところで使用される可能性のある値を +定義するのに便利です。 -The last difference is that constants may only be set to a constant expression, -not the result of a function call or any other value that could only be -computed at runtime. +最後の違いは、定数は定数式にしかセットできないことです。関数呼び出し結果や、実行時に評価される値ではありません。 -Here's an example of a constant declaration where the constant's name is -`MAX_POINTS` and its value is set to 100,000. (Rust constant naming convention -is to use all upper case with underscores between words): +定数の名前が`MAX_POINTS`で値が100,000にセットされた定数定義の例をご覧ください。(Rustの定数の命名規則は、 +全て大文字でアンダースコアで単語区切りすることです): ```rust const MAX_POINTS: u32 = 100_000; ``` -Constants are valid for the entire time a program runs, within the scope they -were declared in, making them a useful choice for values in your application -domain that multiple parts of the program might need to know about, such as the -maximum number of points any player of a game is allowed to earn or the speed -of light. +定数は、プログラムが走る期間、定義されたスコープ内でずっと有効です。従って、プログラムのいろんなところで +使用される可能性のあるアプリケーション空間の値を定義するのに便利な選択肢になります。例えば、ゲームでプレイヤーが取得可能なポイントの +最高値や、光速度などですね。 -Naming hardcoded values used throughout your program as constants is useful in -conveying the meaning of that value to future maintainers of the code. It also -helps to have only one place in your code you would need to change if the -hardcoded value needed to be updated in the future. +プログラム中で使用されるハードコードされた値に対して、定数として名前付けすることは、コードの将来的な +管理者にとって値の意味を汲むのに便利です。将来、ハードコードされた値を変える必要が出た時に、 +たった1箇所を変更するだけで済むようにもしてくれる。 -### Shadowing +### (変数の)多重定義 -As we saw in the guessing game tutorial in Chapter 2, we can declare a new -variable with the same name as a previous variable, and the new variable -*shadows* the previous variable. Rustaceans say that the first variable is -*shadowed* by the second, which means that the second variable’s value is what -we’ll see when we use the variable. We can shadow a variable by using the same -variable’s name and repeating the use of the `let` keyword as follows: +第2章の数当てゲームのチュートリアルで見たように、前に定義した変数と同じ名前の変数を新しく定義でき、 +新しい変数は、前の変数を*上書き*(shadow)する。Rust市民はこれを最初の変数は、2番目の変数に*上書き* +されたと言い、この変数を使用した際に、2番目の変数の値が得られるということです。 +以下のようにして、同じ変数名を用いて変数を上書きし、`let`キーワードの使用を繰り返します: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -165,11 +142,10 @@ fn main() { } ``` -This program first binds `x` to a value of `5`. Then it shadows `x` by -repeating `let x =`, taking the original value and adding `1` so the value of -`x` is then `6`. The third `let` statement also shadows `x`, taking the -previous value and multiplying it by `2` to give `x` a final value of `12`. -When you run this program, it will output the following: +このプログラムはまず、`x`を`5`という値に束縛します。それから`let x =`という文法要素を繰り返すことで +`x`を上書きし、元の値に`1`を加えることになるので、`x`の値は、`6`になります。 +3番目の`let`文も`x`を上書きし、以前の値に`2`をかけることになるので、`x`の最終的な値は`12`になります。 +このプログラムを走らせたら、以下のように出力するでしょう: ```text $ cargo run @@ -178,47 +154,43 @@ $ cargo run The value of x is: 12 ``` -This is different than marking a variable as `mut`, because unless we use the -`let` keyword again, we’ll get a compile-time error if we accidentally try to -reassign to this variable. We can perform a few transformations on a value but -have the variable be immutable after those transformations have been completed. +これは、変数を`mut`にするのとは違います。なぜなら、`let`キーワードを使っている限り、誤ってこの変数に +再代入を試みようものなら、コンパイルエラーが出るからです。値にちょっとした加工は加えられますが、 +その加工が終わったら、変数は不変になるわけです。 -The other difference between `mut` and shadowing is that because we’re -effectively creating a new variable when we use the `let` keyword again, we can -change the type of the value, but reuse the same name. For example, say our -program asks a user to show how many spaces they want between some text by -inputting space characters, but we really want to store that input as a number: +`mut`と上書きの別の違いは、再度`let`キーワードを使用したら、実効的には新しい変数を生成していることになるので、 +値の型を変えつつ、同じ変数名を使いまわせることです。例えば、プログラムがユーザに何らかのテキストに対して +空白文字を入力することで何個分のスペースを表示したいかを尋ねるとします。ただ、この入力を数値として +保持したいとしましょう: ```rust let spaces = " "; let spaces = spaces.len(); ``` -This construct is allowed because the first `spaces` variable is a string type, -and the second `spaces` variable, which is a brand-new variable that happens to -have the same name as the first one, is a number type. Shadowing thus spares us -from having to come up with different names, like `spaces_str` and -`spaces_num`; instead, we can reuse the simpler `spaces` name. However, if we -try to use `mut` for this, as shown here: +この文法要素は、容認されます。というのも、最初の`spaces`変数は文字列型であり、2番目の`spaces`変数は、 +たまたま最初の変数と同じ名前になったまっさらな変数のわけですが、数値型になるからです。故に、多重定義のおかげで、 +異なる名前を思いつく必要がなくなるわけです。`spaces_str`と`spaces_num`などですね; 代わりに、 +よりシンプルな`spaces`という名前を再利用できるわけです。一方で、この場合に`mut`を使おうとすると、 +以下に示した通りですが: ```rust,ignore let mut spaces = " "; spaces = spaces.len(); ``` -we’ll get a compile-time error because we’re not allowed to mutate a variable’s -type: +コンパイルエラーが発生します。変数の型を可変にすることは許されていないからですね: ```text -error[E0308]: mismatched types +error[E0308]: mismatched types (型が合いません) --> src/main.rs:3:14 | 3 | spaces = spaces.len(); | ^^^^^^^^^^^^ expected &str, found usize + | (&str型を予期しましたが、usizeが見つかりました) | = note: expected type `&str` found type `usize` ``` -Now that we’ve explored how variables work, let’s look at more data types they -can have. +さあ、変数が動作する方法を見てきたので、今度は変数が取りうるデータ型について見ていきましょう。 From 4b9eea3952e9be8cb05d73cc83b459ec5f0a722f Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 13 Jul 2017 19:42:51 +0900 Subject: [PATCH 003/428] First drafts of whole Chapter 3 --- .../src/ch03-01-variables-and-mutability.md | 2 +- second-edition/src/ch03-02-data-types.md | 343 ++++++++---------- .../src/ch03-03-how-functions-work.md | 239 ++++++------ second-edition/src/ch03-04-comments.md | 30 +- second-edition/src/ch03-05-control-flow.md | 326 ++++++++--------- 5 files changed, 424 insertions(+), 516 deletions(-) diff --git a/second-edition/src/ch03-01-variables-and-mutability.md b/second-edition/src/ch03-01-variables-and-mutability.md index fa96c74b1..5300de31f 100644 --- a/second-edition/src/ch03-01-variables-and-mutability.md +++ b/second-edition/src/ch03-01-variables-and-mutability.md @@ -119,7 +119,7 @@ const MAX_POINTS: u32 = 100_000; プログラム中で使用されるハードコードされた値に対して、定数として名前付けすることは、コードの将来的な 管理者にとって値の意味を汲むのに便利です。将来、ハードコードされた値を変える必要が出た時に、 -たった1箇所を変更するだけで済むようにもしてくれる。 +たった1箇所を変更するだけで済むようにもしてくれます。 ### (変数の)多重定義 diff --git a/second-edition/src/ch03-02-data-types.md b/second-edition/src/ch03-02-data-types.md index f10c6bb25..da2d2fd54 100644 --- a/second-edition/src/ch03-02-data-types.md +++ b/second-edition/src/ch03-02-data-types.md @@ -1,57 +1,53 @@ -## Data Types +## データ型 -Every value in Rust is of a certain *type*, which tells Rust what kind of data -is being specified so it knows how to work with that data. In this section, -we’ll look at a number of types that are built into the language. We split the -types into two subsets: scalar and compound. +Rustにおける値は全て、何らかの*型*になり、コンパイラがどんなデータが指定されているか知れるので、 +そのデータの取り扱い方も把握できるというわけです。この節では、言語に組み込まれている種々の型について +見ていきましょう。型を二分割しましょう: スカラー型と複合型です。 -Throughout this section, 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 Chapter 2, we must add -a type annotation, like this: +この節を通して、Rustは*静的型付け*言語であることを弁えておいてください。つまり、コンパイル時に +全ての変数の型が判明している必要があるということです。コンパイラは通常、値と使用方法に基づいて、 +使用したい型を推論してくれます。複数の型が推論される可能性がある場合、そう例えば、第2章で`parse`メソッドを +使って`String`型を数値型に変換した時のような場合には、型注釈をつけなければいけません。以下のようにね: ```rust -let guess: u32 = "42".parse().expect("Not a number!"); +let guess: u32 = "42".parse().expect("Not a number!"); // 数字ではありません! ``` -If we don’t add the type annotation here, Rust will display the following -error, which means the compiler needs more information from us to know which -possible type we want to use: +ここで型注釈を付けなければ、コンパイラは以下のエラーを表示し、これは可能性のある型のうち、 +どの型を使用したいのかを知るのに、コンパイラがプログラマからもっと情報を得る必要があることを +意味します: ```text error[E0282]: unable to infer enough type information about `_` + (`_`型に関して十分な情報を推論できませんでした) --> src/main.rs:2:9 | 2 | let guess = "42".parse().expect("Not a number!"); | ^^^^^ cannot infer type for `_` + | (`_`の型が推論できません) | = note: type annotations or generic parameter binding required + (注釈: 型注釈、またはジェネリクス引数束縛が必要です) ``` -You’ll see different type annotations as we discuss the various data types. +いろいろなデータ型について議論するにつれて、様々な型注釈を目撃することになるでしょう。 -### Scalar Types +### スカラー型 -A *scalar* type represents a single value. Rust has four primary scalar types: -integers, floating-point numbers, booleans, and characters. You’ll likely -recognize these from other programming languages, but let’s jump into how they -work in Rust. +スカラー型は、単独の値を表します。Rustには主に4つのスカラー型があります: +整数、浮動小数点数、論理値、最後に文字です。他のプログラミング言語でも、これらの型を見かけたことはあるでしょうが、 +Rustでの動作方法について見ていきましょう。 -#### Integer Types +#### 整数型 -An *integer* is a number without a fractional component. We used one integer -type earlier in this chapter, the `i32` type. This type declaration indicates -that the value it’s associated with should be a signed integer (hence the `i`, -as opposed to a `u` for unsigned) 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, *i32*) can be used to declare the type of an -integer value. +整数とは、小数部分のない数値のことです。この章の前半で一つの整数型を使用しました。`i32`型です。 +この型定義は、紐付けられる値が、符号付き整数(そのため、`i`になります。非負整数に対する`u`と逆ですね) +になり、これは、32ビット分のサイズを取ります。表3-1は、Rustの組み込み整数型を表示しています。 +符号付きと符号なし欄の各バリアント(例: *i32*)を使用して、整数値の型を定義することができます。 -Table 3-1: Integer Types in Rust +表3-1: Rustの整数型 -| Length | Signed | Unsigned | +| 大きさ | 符号付き | 符号なし | |--------|--------|----------| | 8-bit | i8 | u8 | | 16-bit | i16 | u16 | @@ -59,61 +55,52 @@ integer value. | 64-bit | i64 | u64 | | arch | isize | usize | -Each variant can be either signed or unsigned and has an explicit size. -Signed and unsigned refers to whether it’s possible for the number to be -negative or positive; in other words, whether the number needs to have a sign -with it (signed) or whether it will only ever be positive and can therefore be -represented without a sign (unsigned). It’s like writing numbers on paper: when -the sign matters, a number is shown with a plus sign or a minus sign; however, -when it’s safe to assume the number is positive, it’s shown with no sign. -Signed numbers are stored using two’s complement representation (if you’re -unsure what this is, you can search for it online; an explanation is outside -the scope of this book). - -Each signed variant can store numbers from -(2n - 1) to 2n - -1 - 1 inclusive, where `n` is the number of bits that variant uses. So an -`i8` can store numbers from -(27) to 27 - 1, which equals --128 to 127. Unsigned variants can store numbers from 0 to 2n - 1, -so a `u8` can store numbers from 0 to 28 - 1, which equals 0 to 255. - -Additionally, the `isize` and `usize` types depend on the kind of computer your -program is running on: 64-bits if you’re on a 64-bit architecture and 32-bits -if you’re on a 32-bit architecture. - -You can write integer literals in any of the forms shown in Table 3-2. Note -that all number literals except the byte literal allow a type suffix, such as -`57u8`, and `_` as a visual separator, such as `1_000`. - -Table 3-2: Integer Literals in Rust - -| Number literals | Example | +各バリアントは、符号付きか符号なしかを選べ、明示的なサイズを持ちます。符号付きと符号なしの特性は、 +数値が正負を持つかどうかを示します。つまり、数値が符号を持つ必要があるかどうか(符号付き)、または、 +絶対に正数にしかならず符号なしで表現できるかどうか(符号なし)です。これは、数値を紙に書き下すのと似ています: +符号が問題になるなら、数値はプラス記号、またはマイナス記号とともに表示されます; しかしながら、 +その数値が正数であると仮定することが安全なら、符号なしで表示できるわけです。符号付き数値は、 +2の補数表現で保持されます(これが何なのか確信を持てないのであれば、ネットで検索することができます。 +まあ要するに、この解説は、この本の範疇外というわけです)。 + +各符号付きバリアントは、-(2n - 1)から2n - 1 - 1までの数値を保持でき、 +ここで`n`はこのバリアントが使用するビット数です。以上から、`i8`型は-(27)から +27 - 1まで、つまり、-128から127までを保持できます。符号なしバリアントは、0から +2n - 1までを保持できるので、`u8`型は、0から28 - 1までの値、つまり、 +0から255までを保持できることになります。 + +加えて、`isize`と`usize`型は、プログラムが動作しているコンピュータの種類に依存します: +64ビットアーキテクチャなら、64ビットですし、32ビットアーキテクチャなら、32ビットになります。 + +整数リテラル(`脚注`: リテラルとは、見たまんまの値ということ)は表3-2に示すどの形態でも記述することができます。バイトリテラルを除く数値リテラルは全て、 +型接尾辞を付加すること(例えば、`57u8`)と`_`を見た目の区切り記号(例えば、`1_000`)にできます。 + +表3-2: Rustの整数リテラル + +| 数値リテラル | 例 | |------------------|---------------| -| Decimal | `98_222` | -| Hex | `0xff` | -| Octal | `0o77` | -| Binary | `0b1111_0000` | -| Byte (`u8` only) | `b'A'` | +| 10進数 | `98_222` | +| 16進数 | `0xff` | +| 8進数 | `0o77` | +| 2進数 | `0b1111_0000` | +| バイト (`u8`だけ) | `b'A'` | -So how do you know which type of integer to use? If you’re unsure, Rust’s -defaults are generally good choices, and integer types default to `i32`: it’s -generally the fastest, even on 64-bit systems. The primary situation in which -you’d use `isize` or `usize` is when indexing some sort of collection. +では、どの整数型を使うべきかはどう把握すればいいのでしょうか?もし確信が持てないのならば、Rustの +デフォルトは一般的にいい選択になります。整数型の基準は`i32`型です: 64ビットシステム上でも、 +普通最速になります。`isize`と`usize`を使う主な状況は、何らかのコレクションにアクセスすることです。 -#### Floating-Point Types +#### 浮動小数点型 -Rust also has two primitive types for *floating-point numbers*, which are -numbers with decimal points. Rust’s floating-point types are `f32` and `f64`, -which are 32 bits and 64 bits in size, respectively. The default type is `f64` -because it’s roughly the same speed as `f32` but is capable of more precision. -It’s possible to use an `f64` type on 32-bit systems, but it will be slower -than using an `f32` type on those systems. Most of the time, trading potential -worse performance for better precision is a reasonable initial choice, and you -should benchmark your code if you suspect floating-point size is a problem in -your situation. +Rustにはさらに、*浮動小数点数*に対しても、2種類の基本型があり、浮動小数点数とは10進小数のことです。 +Rustの浮動小数点型は、`f32`と`f64`で、それぞれ32ビットと64ビットサイズです。基準型は`f64`です。 +なぜなら、`f32`とほぼ同スピードにもかかわらず、より精度が高くなるからです。32ビットシステム上でも、 +`f64`型を使用することはできますが、`f32`型を使うよりも遅くなります。ほとんどの場合、パフォーマンスが悪くなる +可能性と引き換えに高精度を得ることは、一考の価値のある第1選択肢になる上、自らのコードで浮動小数点数のサイズが +問題になる可能性があると疑うのなら、ベンチマークをしてみるべきです。 -Here’s an example that shows floating-point numbers in action: +実際に動作している浮動小数点数の例をご覧ください: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -123,101 +110,92 @@ fn main() { } ``` -Floating-point numbers are represented according to the IEEE-754 standard. The -`f32` type is a single-precision float, and `f64` has double precision. +浮動小数点数は、IEEE-754規格に従って表現されています。`f32`が単精度浮動小数点数、 +`f64`が倍精度浮動小数点数です。 -#### Numeric Operations +#### 数値演算 -Rust supports the usual basic mathematical operations you’d expect for all of the -number types: addition, subtraction, multiplication, division, and remainder. -The following code shows how you’d use each one in a `let` statement: +Rustにも期待されうる標準的な数学演算が全数値型に対して用意されています: 足し算、引き算、掛け算、割り算、余りです。 +以下の例では、`let`文での各演算の使用方法をご覧になれます: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { - // addition + // 足し算 let sum = 5 + 10; - // subtraction + // 引き算 let difference = 95.5 - 4.3; - // multiplication + // 掛け算 let product = 4 * 30; - // division + // 割り算 let quotient = 56.7 / 32.2; - // remainder + // 余り let remainder = 43 % 5; } ``` -Each expression in these statements uses a mathematical operator and evaluates -to a single value, which is then bound to a variable. Appendix B contains a -list of all operators that Rust provides. +これらの文の各式は、数学演算子を使用しており、一つの値に評価され、変数に束縛されます。付録BにRustで使える +演算子の一覧が載っています。 -#### The Boolean Type +#### 論理値型 -As in most other programming languages, a boolean type in Rust has two possible -values: `true` and `false`. The boolean type in Rust is specified using `bool`. -For example: +他の多くの言語同様、Rustの論理値型も取りうる値は二つしかありません: `true`と`false`です。 +Rustの論理値型は、`bool`と指定されます。 +例です: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { let t = true; - let f: bool = false; // with explicit type annotation + let f: bool = false; // 明示的型注釈付きで } ``` -The main way to consume boolean values is through conditionals, such as an `if` -expression. We’ll cover how `if` expressions work in Rust in the “Control Flow” -section. +論理値を消費する主な手段は、条件式です。例えば、`if`式などですね。`if`式の動作方法については、 +「フロー制御」節で解説します。 -#### The Character Type +#### 文字型 -So far we’ve only worked with numbers, but Rust supports letters too. Rust’s -`char` type is the language’s most primitive alphabetic type, and the following -code shows one way to use it: +ここまで、数値型のみ扱ってきましたが、Rustには文字も用意されています。Rustの`char`型は、言語の最も +基本的なアルファベット型であり、以下のコードでその使用方法の一例を見ることができます: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { let c = 'z'; let z = 'ℤ'; - let heart_eyed_cat = '😻'; + let heart_eyed_cat = '😻'; //ハート目の猫 } ``` -Rust’s `char` type represents a Unicode Scalar Value, which means it can -represent a lot more than just ASCII. Accented letters, Chinese/Japanese/Korean -ideographs, emoji, and zero width spaces are all valid `char` types in Rust. -Unicode Scalar Values range from `U+0000` to `U+D7FF` and `U+E000` to -`U+10FFFF` inclusive. However, a “character” isn’t really a concept in Unicode, -so your human intuition for what a “character” is may not match up with what a -`char` is in Rust. We’ll discuss this topic in detail in the “Strings” section -in Chapter 8. +Rustの`char`型は、ユニコードのスカラー値を表します。これはつまり、アスキーよりもずっとたくさんの +ものを表せるということです。アクセント文字、中国語/日本語/韓国語表意文字(`脚注`: 漢字のことだと思われる)、 +絵文字、ゼロ幅スペースは、全てRustでは、有効な`char`型になります。ユニコードスカラー値は、 +`U+0000`から`U+D7FF`までと`U+E0000`から`U+10FFFF`までの範囲になります。ところが、「文字」は +実はユニコードの概念ではないので、文字とは何かという人間としての直観は、Rustにおける`char`型が何か +とは合致しない可能性があります。この話題については第8章の「文字列」節で詳しく議論しましょう。 -### Compound Types +### 複合型 -*Compound types* can group multiple values of other types into one type. Rust -has two primitive compound types: tuples and arrays. +*複合型*により、複数の型の値を一つの型にまとめることができます。Rustには、 +2種類の基本的な複合型があります: タプルと配列です。 -#### Grouping Values into Tuples +#### 値をタプルにまとめ上げる -A tuple is a general way of grouping together some number of other values with -a variety of types into one compound type. +タプルは、複数の型の何らかの値を一つの複合型にまとめ上げる一般的な手段です。 -We create a tuple by writing a comma-separated list of values inside -parentheses. Each position in the tuple has a type, and the types of the -different values in the tuple don’t have to be the same. We’ve added optional -type annotations in this example: +タプルは、丸かっこの中にカンマ区切りの値リストを書くことで生成します。タプルの各位置には型が紐付けられ、 +タプルの値は全てが同じ型である必要はありません。今回の例では、型注釈をあえて追加してみました: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -225,11 +203,10 @@ fn main() { } ``` -The variable `tup` binds to the entire tuple, since a tuple is considered a -single compound element. To get the individual values out of a tuple, we can -use pattern matching to destructure a tuple value, like this: +変数`tup`は、タプル全体に束縛されています。なぜなら、タプルは、一つの複合要素と考えられるからです。 +タプルからここの値を取り出すには、パターンマッチングにより分解を使用することができます。以下のように: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -241,17 +218,15 @@ fn main() { } ``` -This program first creates a tuple and binds it to the variable `tup`. It then -uses a pattern with `let` to take `tup` and turn it into three separate -variables, `x`, `y`, and `z`. This is called *destructuring*, because it breaks -the single tuple into three parts. Finally, the program prints the value of -`y`, which is `6.4`. +このプログラムは、まずタプルを生成し、それを変数`tup`に束縛しています。それから`let`文と +パターンを使って`tup`変数の中身を3つの個別の変数(`x`、`y`、`z`ですね)に変換しています。 +この過程は、*分解*と呼ばれます。単独のタプルを破壊して三分割しているからです。最後に、 +プログラムは`y`変数の値を出力し、それは`6.4`になります。 -In addition to destructuring through pattern matching, we can also access a -tuple element directly by using a period (`.`) followed by the index of the -value we want to access. For example: +パターンマッチングを通しての分解の他にも、アクセスしたい値の番号をピリオドに続けて書くことで、 +タプルの要素に直接アクセスすることもできます。例です: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -265,21 +240,18 @@ fn main() { } ``` -This program creates a tuple, `x`, and then makes new variables for each -element by using their index. As with most programming languages, the first -index in a tuple is 0. +このプログラムは、新しいタプル`x`を作成し、添え字アクセスで書く要素に対して新しい変数も作成しています。 +多くのプログラミング言語同様、タプルの最初の添え字は0です。 -#### Arrays +#### 配列 -Another way to have a collection of multiple values is with an *array*. Unlike -a tuple, every element of an array must have the same type. Arrays in Rust are -different than arrays in some other languages because arrays in Rust have a -fixed length: once declared, they cannot grow or shrink in size. +*配列*によっても、複数の値のコレクションを得ることができます。タプルと異なり、配列の全要素は、 +同じ型でなければなりません。Rustの配列は、他の言語と異なっている場合があります。Rustの配列は、 +固定長なのです: 一度定義されたら、サイズを伸ばすことも縮めることもできません。 -In Rust, the values going into an array are written as a comma-separated list -inside square brackets: +Rustでは、配列に入れる要素は、角かっこ内にカンマ区切りリストとして記述します: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -287,30 +259,26 @@ fn main() { } ``` -Arrays are useful when you want your data allocated on the stack rather than -the heap (we will discuss the stack and the heap more in Chapter 4), or when -you want to ensure you always have a fixed number of elements. They aren’t as -flexible as the vector type, though. The vector type is a similar collection -type provided by the standard library that *is* allowed to grow or shrink in -size. If you’re unsure whether to use an array or a vector, you should probably -use a vector: Chapter 8 discusses vectors in more detail. +配列は、ヒープよりもスタック(スタックとヒープについては第4章で詳らかに議論します)にデータのメモリを確保したい時、 +または、常に固定長の要素があることを確認したい時に便利です。ただ、配列は、ベクタ型ほどは柔軟ではありません。 +ベクタ型も、標準ライブラリによって提供されている似たようなコレクション型で、こちらは、 +サイズを伸縮させることが*できます*。配列とベクタ型、どちらを使うべきか確信が持てない時は、 +おそらくベクタ型を使うべきです: 第8章でベクタ型について詳細に議論します。 -An example of when you might want to use an array rather than a vector is in a -program that needs to know the names of the months of the year. It’s very -unlikely that such a program will need to add or remove months, so you can use -an array because you know it will always contain 12 items: +ベクタ型よりも配列を使いたくなる例は、1年の月の名前を扱うプログラムです。そのようなプログラムで、 +月を追加したり削除したりすることはほぼ稀なので、配列を使用できます。常に12個要素があることも自明ですしね: ```rust let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; ``` -##### Accessing Array Elements +##### 配列の要素にアクセスする -An array is a single chunk of memory allocated on the stack. We can access -elements of an array using indexing, like this: +配列は、スタック上に確保される一塊のメモリです。添え字によって配列の +要素にアクセスすることができます。こんな感じ: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -321,16 +289,15 @@ fn main() { } ``` -In this example, the variable named `first` will get the value `1`, because -that is the value at index `[0]` in the array. The variable named `second` will -get the value `2` from index `[1]` in the array. +この例では、`first`という名前の変数には`1`という値が格納されます。配列の`[0]`番目にある値が +それだからですね。`second`という名前の変数には、配列の`[1]`番目の値`2`が格納されます。 -##### Invalid Array Element Access +##### 配列要素への無効なアクセス -What happens if we try to access an element of an array that is past the end of -the array? Say we change the example to the following: +配列の終端を越えて要素にアクセスしようとしたら、どうなるだろうか?先ほどの例を以下のように +変えたとしよう: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -339,11 +306,11 @@ fn main() { let element = a[index]; - println!("The value of element is: {}", element); + println!("The value of element is: {}", element); // 要素の値は{}です } ``` -Running this code using `cargo run` produces the following result: +このコードを`cargo run`で走らせると、以下のような結果になります: ```text $ cargo run @@ -351,17 +318,17 @@ $ cargo run Running `target/debug/arrays` thread '
' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:6 +スレッド'
'は'範囲外アクセス: 長さは5ですが、添え字は10でした', src/main.rs:6 +でパニックしました note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` -The compilation didn’t produce any errors, but the program results in a -*runtime* error and didn’t exit successfully. When you attempt to access an -element using indexing, Rust will check that the index you’ve specified is less -than the array length. If the index is greater than the length, Rust will -*panic*, which is the term Rust uses when a program exits with an error. - -This is the first example of Rust’s safety principles in action. In many -low-level languages, this kind of check is not done, and when you provide an -incorrect index, invalid memory can be accessed. Rust protects you against this -kind of error by immediately exiting instead of allowing the memory access and -continuing. Chapter 9 discusses more of Rust’s error handling. +コンパイルでは何もエラーが出なかったものの、プログラムは*実行時*エラーに陥り、 +正常終了しませんでした。要素に添え字アクセスを試みると、言語は、指定されたその添え字が +配列長よりも小さいかをチェックしてくれます。添え字が配列長よりも大きければ、言語は*パニック*します。 +パニックとは、プログラムがエラーで終了したことを表すRust用語です。 + +これは、実際に稼働しているRustの安全機構の最初の例になります。低レベル言語の多くでは、 +この種のチェックは行われないため、間違った添え字を与えると、無効なメモリにアクセスできてしまいます。 +Rustでは、メモリアクセスを許可し、処理を継続する代わりに即座にプログラムを終了することで +この種のエラーからプログラマを保護しています。Rustのエラー処理については、第9章で詳しく議論します。 diff --git a/second-edition/src/ch03-03-how-functions-work.md b/second-edition/src/ch03-03-how-functions-work.md index d4879491b..b04ec15fe 100644 --- a/second-edition/src/ch03-03-how-functions-work.md +++ b/second-edition/src/ch03-03-how-functions-work.md @@ -1,15 +1,14 @@ -## How Functions Work +## 関数の動作方法 -Functions are pervasive in Rust code. You’ve already seen one of the most -important functions in the language: the `main` function, which is the entry -point of many programs. You’ve also seen the `fn` keyword, which allows you to -declare new functions. +関数は、Rustのコードにおいてよく見かける存在です。すでに、言語において最も重要な関数のうちの +一つを目撃していますね: そう、`main`関数で、これは、多くのプログラムのエントリーポイントになります。 +`fn`キーワードもすでに見かけましたね。これによって新しい関数を定義することができます。 -Rust code uses *snake case* as the conventional style for function and variable -names. In snake case, all letters are lowercase and underscores separate words. -Here’s a program that contains an example function definition: +Rustの関数と変数の命名規則は、*スネークケース*(`脚注`: some_variableのような命名規則)です。 +スネークケースとは、全文字を小文字にし、単語区切りにアンダースコアを使うことです。 +以下のプログラムで、サンプルの関数定義をご覧ください: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -19,24 +18,22 @@ fn main() { } fn another_function() { - println!("Another function."); + println!("Another function."); // 別の関数 } ``` -Function definitions in Rust start with `fn` and have a set of parentheses -after the function name. The curly braces tell the compiler where the function -body begins and ends. +Rustにおいて関数定義は、`fn`キーワードで始まり、関数名の後に丸かっこの組が続きます。 +波かっこの位置が、コンパイラが関数本体の位置と判断する場所です。 -We can call any function we’ve defined by entering its name followed by a set -of parentheses. Because `another_function` is defined in the program, it can be -called from inside the `main` function. Note that we defined `another_function` -*after* the `main` function in the source code; we could have defined it before -as well. Rust doesn’t care where you define your functions, only that they’re -defined somewhere. +定義した関数は、名前に丸かっこの組を続けることで呼び出すことができます。`another_function`関数が +プログラム内で定義されているので、`main`関数内から呼び出すことができるわけです。ソースコード中で +`another_function`を`main`関数の*後*に定義していることに注目してください; 勿論、main関数の前に +定義することもできます。コンパイラは、関数がどこで定義されているかは気にしません。 +どこかで定義されていることのみ気にします。 -Let’s start a new binary project named *functions* to explore functions -further. Place the `another_function` example in *src/main.rs* and run it. You -should see the following output: +*functions*という名前の新しいバイナリ生成プロジェクトを始めて、関数についてさらに深く探知していきましょう。 +`another_function`の例を*src/main.rs*ファイルに配置して、走らせてください。 +以下のような出力が得られるはずです: ```text $ cargo run @@ -46,24 +43,20 @@ Hello, world! Another function. ``` -The lines execute in the order in which they appear in the `main` function. -First, the “Hello, world!” message prints, and then `another_function` is -called and its message is printed. +行出力は、`main`関数内に書かれた順序で実行されています。最初に、"Hello, world"メッセージが出、 +それから`another_function`が呼ばれて、こちらのメッセージが出力されています。 -### Function Parameters +### 関数の引数 -Functions can also be defined to have *parameters*, which are special variables -that are part of a function's signature. When a function has parameters, we can -provide it with concrete values for those parameters. Technically, the concrete -values are called *arguments*, but in casual conversation people tend to use -the words “parameter” and “argument” interchangeably for either the variables -in a function's definition or the concrete values passed in when you call a -function. +関数は、引数を持つようにも定義できます。引数とは、関数シグニチャの一部になる特別な変数のことです。 +関数に引数があると、引数の位置に実際の値を与えることができます。技術的にはこの実際の値は +*実引数*と呼ばれますが、普段の会話では、仮引数("parameter")と実引数("argument")を +関数定義の変数と関数呼び出し時に渡す実際の値、両方の意味に区別なく使います(`脚注`: 日本語では、 +どちらも単に引数と呼ぶことが多いでしょう)。 -The following rewritten version of `another_function` shows what parameters -look like in Rust: +以下の書き直した`another_function`では、Rustのパラメータがどんな見た目なのかを示しています: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -71,11 +64,11 @@ fn main() { } fn another_function(x: i32) { - println!("The value of x is: {}", x); + println!("The value of x is: {}", x); // xの値は{}です } ``` -Try running this program; you should get the following output: +このプログラムを走らせてみてください; 以下のような出力が得られるはずです: ```text $ cargo run @@ -84,20 +77,18 @@ $ cargo run The value of x is: 5 ``` -The declaration of `another_function` has one parameter named `x`. The type of -`x` is specified as `i32`. When `5` is passed to `another_function`, the -`println!` macro puts `5` where the pair of curly braces were in the format -string. +`another_function`の定義には、`x`という名前の仮引数があります。`x`の型は、`i32`と +指定されています。値`5`が`another_function`に渡されると、`println!`マクロにより、 +フォーマット文字列中の1組の波かっこがある位置に値`5`が出力されます。 -In function signatures, you *must* declare the type of each parameter. This is -a deliberate decision in Rust’s design: requiring type annotations in function -definitions means the compiler almost never needs you to use them elsewhere in -the code to figure out what you mean. +関数シグニチャにおいて、各仮引数の型を宣言しなければなりません。これは、Rustの設計において、 +意図的な判断です: 関数定義で型注釈が必要不可欠ということは、コンパイラがその意図するところを +推し量るのに、コードの他の箇所で使用する必要がないということを意味します。 -When you want a function to have multiple parameters, separate the parameter -declarations with commas, like this: +関数に複数の仮引数をもたせたいときは、仮引数定義をカンマで区切ってください。 +こんな感じです: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -110,14 +101,12 @@ fn another_function(x: i32, y: i32) { } ``` -This example creates a function with two parameters, both of which are `i32` -types. The function then prints out the values in both of its parameters. Note -that function parameters don't all need to be the same type, they just happen -to be in this example. +この例では、2引数の関数を生成しています。そして、引数はどちらも`i32`型です。この関数は、 +仮引数の値を両方出力します。関数引数は、全てが同じ型である必要はありません。今回は、 +偶然同じになっただけです。 -Let’s try running this code. Replace the program currently in your *function* -project’s *src/main.rs* file with the preceding example, and run it using -`cargo run`: +このコードを走らせてみましょう。今、*function*プロジェクトの*src/main.rs*ファイルに記載されている +プログラムを先ほどの例と置き換えて、`cargo run`で走らせてください: ```text $ cargo run @@ -127,29 +116,25 @@ The value of x is: 5 The value of y is: 6 ``` -Because we called the function with `5` as the value for `x` and `6` is passed -as the value for `y`, the two strings are printed with these values. +`x`に対して値`5`、`y`に対して値`6`を渡して関数を呼び出したので、この二つの文字列は、 +この値で出力されました。 -### Function Bodies +### 関数本体 -Function bodies are made up of a series of statements optionally ending in an -expression. So far, we’ve only covered functions without an ending expression, -but we have seen expressions as parts of statements. Because Rust is an -expression-based language, this is an important distinction to understand. -Other languages don’t have the same distinctions, so let’s look at what -statements and expressions are and how their differences affect the bodies of -functions. +関数本体は、文が並び、最後に式を置くか文を置くという形で形成されます。現在までには、式で終わらない +関数だけを見てきたわけですが、式が文の一部になっているものなら見かけましたね。Rustは、式志向言語なので、 +これは理解しておくべき重要な差異になります。他の言語にこの差異はありませんので、文と式がなんなのかと、 +その違いが関数本体にどんな影響を与えるかを見ていきましょう。 -### Statements and Expressions +### 文と式 -We’ve actually already used statements and expressions. *Statements* are -instructions that perform some action and do not return a value. *Expressions* -evaluate to a resulting value. Let’s look at some examples. +実のところ、もう文と式は使っています。*文*とは、なんらかの動作をして値を返さない命令です。 +*式*は結果値に評価されます。ちょっと例を眺めてみましょう。 -Creating a variable and assigning a value to it with the `let` keyword is a -statement. In Listing 3-3, `let y = 6;` is a statement: +`let`キーワードを使用して変数を生成し、値を代入することは文になります。 +リスト3-3で`let y = 6;`は文です: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -157,15 +142,14 @@ fn main() { } ``` -Listing 3-3: A `main` function declaration containing one statement. +リスト3-3: 1文を含む`main`関数宣言 -Function definitions are also statements; the entire preceding example is a -statement in itself. +関数定義も文になります。つまり、先の例は全体としても文になるわけです。 -Statements do not return values. Therefore, you can’t assign a `let` statement -to another variable, as the following code tries to do: +文は値を返しません。故に、`let`文を他の変数に代入することはできません。 +以下のコードでは試みてますけどね: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -173,35 +157,33 @@ fn main() { } ``` -When you run this program, you’ll get an error like this: +このプログラムを実行すると、以下のようなエラーが出るでしょう: ```text $ cargo run Compiling functions v0.1.0 (file:///projects/functions) error: expected expression, found statement (`let`) +(エラー: 式を予期しましたが、文が見つかりました (`let`)) --> src/main.rs:2:14 | 2 | let x = (let y = 6); | ^^^ | = note: variable declaration using `let` is a statement + (注釈: `let`を使う変数宣言は、文です) ``` -The `let y = 6` statement does not return a value, so there isn’t anything for -`x` to bind to. This is different than in other languages, such as C and Ruby, -where the assignment returns the value of the assignment. In those languages, -you can write `x = y = 6` and have both `x` and `y` have the value `6`; that is -not the case in Rust. +この`let y = 6`という文は値を返さないので、`x`を束縛する相手がないわけです。これは、 +CやRubyなどの言語とは異なる動作です。CやRubyでは、代入は代入値を返します。これらの言語では、 +`x = y = 6`と書いて、`x`も`y`も値6になるようにできるのですが、Rustにおいては、 +そうは問屋が卸さないわけです。 -Expressions evaluate to something and make up most of the rest of the code that -you’ll write in Rust. Consider a simple math operation, such as `5 + 6`, which -is an expression that evaluates to the value `11`. Expressions can be part of -statements: in Listing 3-3 that had the statement `let y = 6;`, `6` is an -expression that evaluates to the value `6`. Calling a function is an -expression. Calling a macro is an expression. The block that we use to create -new scopes, `{}`, is an expression, for example: +式は何かに評価され、これからあなたが書くRustコードの多くを構成します。簡単な数学演算(`5 + 6`など)を +思い浮かべましょう。この例は、値`11`に評価される式です。式は文の一部になりえます: `let y = 6`という +文を含むリスト3-3では、`6`は値`6`に評価される式です。関数呼び出しも式です。マクロ呼び出しも式です。 +新しいスコープを作る際に使用するブロック(`{}`)も式です: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -216,7 +198,7 @@ fn main() { } ``` -This expression: +この式は: ```rust,ignore { @@ -225,22 +207,18 @@ This expression: } ``` -is a block that, in this case, evaluates to `4`. That value gets bound to `y` -as part of the `let` statement. Note the line without a semicolon at the end, -unlike most of the lines you’ve seen so far. Expressions do not include ending -semicolons. If you add a semicolon to the end of an expression, you turn it -into a statement, which will then not return a value. Keep this in mind as you -explore function return values and expressions next. +今回の場合、`4`に評価されるブロックです。その値が、`let`文の一部として`y`に束縛されます。 +今まで見かけてきた行と異なり、セミコロンがついていない行に気をつけてください。式に終端のセミコロンは、 +含みません。式の終端にセミコロンを付けたら、文に変えてしまいます。そして、文は値を返しません。 +次に関数の戻り値や式を見ていく際にこのことを肝に命じておいてください。 -### Functions with Return Values +### 戻り値のある関数 -Functions can return values to the code that calls them. We don’t name return -values, but we do declare their type after an arrow (`->`). In Rust, the return -value of the function is synonymous with the value of the final expression in -the block of the body of a function. Here’s an example of a function that -returns a value: +関数は、それを呼び出したコードに値を返すことができます。戻り値に名前付けはできませんが、 +矢印(`->`)の後に型を書いて宣言します。Rustでは、関数の戻り値は、関数本体ブロックの最後の式の値と +同義です。こちらが、値を返す関数の例です: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn five() -> i32 { @@ -254,10 +232,9 @@ fn main() { } ``` -There are no function calls, macros, or even `let` statements in the `five` -function—just the number `5` by itself. That’s a perfectly valid function in -Rust. Note that the function’s return type is specified, too, as `-> i32`. Try -running this code; the output should look like this: +`five`関数内には、関数呼び出しもマクロ呼び出しも、`let`文でさえ存在しません。数字の5が単独であるだけです。 +これは、Rustにおいて、完璧に問題ない関数です。関数の戻り値型が`-> i32`と指定されていることにも注目してください。 +このコードを実行してみましょう; 出力はこんな感じになるはずです: ```text $ cargo run @@ -266,22 +243,18 @@ $ cargo run The value of x is: 5 ``` -The `5` in `five` is the function’s return value, which is why the return type -is `i32`. Let’s examine this in more detail. There are two important bits: -first, the line `let x = five();` shows that we’re using the return value of a -function to initialize a variable. Because the function `five` returns a `5`, -that line is the same as the following: +`five`内の`5`が関数の戻り値です。だから、戻り値型が`i32`なのです。これについてもっと深く考察しましょう。 +重要な箇所は2つあります: まず、`let x = five()`という行は、関数の戻り値を使って変数を初期化している +ことを示しています。関数`five`は`5`を返すので、この行は以下のように書くのと同義です: ```rust let x = 5; ``` -Second, the `five` function has no parameters and defines the type of the -return value, but the body of the function is a lonely `5` with no semicolon -because it’s an expression whose value we want to return. Let’s look at another -example: +2番目に、`five`関数は仮引数をもたず、戻り値型を定義していますが、関数本体はセミコロンなしの`5`単独です。 +なぜなら、これが返したい値になる式だからです。もう一つ例を見てみましょう: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -295,11 +268,10 @@ fn plus_one(x: i32) -> i32 { } ``` -Running this code will print `The value of x is: 6`. What happens if we place a -semicolon at the end of the line containing `x + 1`, changing it from an -expression to a statement? +このコードを走らせると、`The value of x is: 6`と出力されるでしょう。では、`x + 1`を含む行の +終端にセミコロンを付けて、式から文に変えてみたら、どうなるでしょうか? -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -313,10 +285,11 @@ fn plus_one(x: i32) -> i32 { } ``` -Running this code produces an error, as follows: +このコードを実行すると、以下のようにエラーが出ます: ```text error[E0308]: mismatched types + (型が合いません) --> src/main.rs:7:28 | 7 | fn plus_one(x: i32) -> i32 { @@ -324,20 +297,20 @@ error[E0308]: mismatched types 8 | | x + 1; 9 | | } | |_^ expected i32, found () + | (i32を予期したのに、()型が見つかりました) | = note: expected type `i32` found type `()` help: consider removing this semicolon: +(助言: このセミコロンを除くことを考えてみてください) --> src/main.rs:8:10 | 8 | x + 1; | ^ ``` -The main error message, “mismatched types,” reveals the core issue with this -code. The definition of the function `plus_one` says that it will return an -`i32`, but statements don’t evaluate to a value, which is expressed by `()`, -the empty tuple. Therefore, nothing is returned, which contradicts the function -definition and results in an error. In this output, Rust provides a message to -possibly help rectify this issue: it suggests removing the semicolon, which -would fix the error. +メインのエラーメッセージである「型が合いません」でこのコードの根本的な問題が明らかになるでしょう。 +関数`plus_one`の定義では、`i32`型を返すと言っているのに、文は値に評価されないからです。このことは、 +`()`、つまり空のタプルとして表現されています。それゆえに、何も戻り値がなく、これが関数定義と矛盾するので、 +結果としてエラーになるわけです。この出力内で、コンパイラは問題を修正する手助けになりそうなメッセージも出していますね: +セミコロンを削除するよう提言しています。そして、そうすれば、エラーは直るわけです。 diff --git a/second-edition/src/ch03-04-comments.md b/second-edition/src/ch03-04-comments.md index 664e155d7..ab0a80649 100644 --- a/second-edition/src/ch03-04-comments.md +++ b/second-edition/src/ch03-04-comments.md @@ -1,46 +1,46 @@ -## Comments +## コメント -All programmers strive to make their code easy to understand, but sometimes -extra explanation is warranted. In these cases, programmers leave notes, or -*comments*, in their source code that the compiler will ignore but people -reading the source code may find useful. +全プログラマは、自分のコードがわかりやすくなるよう努めますが、時として追加の説明が許されることもあります。 +このような場合、プログラマは注釈または*コメント*をソースコードに残し、コメントをコンパイラは無視しますが、 +ソースコードを読む人間には便利なものと思えるでしょう。 -Here’s a simple comment: +こちらが単純なコメントです: ```rust // Hello, world. ``` -In Rust, comments must start with two slashes and continue until the end of the -line. For comments that extend beyond a single line, you’ll need to include -`//` on each line, like this: +Rustでは、コメントは2連スラッシュで始め、行の終わりまで続きます。コメントが複数行にまたがる場合、 +各行に`//`を含める必要があります。こんな感じに: ```rust // So we’re doing something complicated here, long enough that we need // multiple lines of comments to do it! Whew! Hopefully, this comment will // explain what’s going on. +// ここで何か複雑なことをしていて、長すぎるから複数行のコメントが必要なんだ。 +// ふう!願わくば、このコメントで何が起きているか説明されていると嬉しい。 ``` -Comments can also be placed at the end of lines containing code: +コメントは、コードが書かれた行の末尾にも配置することができます: Filename: src/main.rs ```rust fn main() { - let lucky_number = 7; // I’m feeling lucky today. + let lucky_number = 7; // I’m feeling lucky today.(今日はラッキーな気がするよ) } ``` -But you’ll more often see them used in this format, with the comment on a -separate line above the code it's annotating: +しかし、こちらの形式のコメントの方が見かける機会は多いでしょう。注釈しようとしているコードの1行上に書く形式です: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { // I’m feeling lucky today. + // 今日はラッキーな気がするよ let lucky_number = 7; } ``` -That’s all there is to comments. They’re not particularly complicated. +コメントについては以上。特に複雑ではなかったでしょ。 diff --git a/second-edition/src/ch03-05-control-flow.md b/second-edition/src/ch03-05-control-flow.md index 20093b340..d9e472f91 100644 --- a/second-edition/src/ch03-05-control-flow.md +++ b/second-edition/src/ch03-05-control-flow.md @@ -1,50 +1,42 @@ -## Control Flow +## フロー制御 -Deciding whether or not to run some code depending on if a condition is true or -deciding to run some code repeatedly while a condition is true are basic -building blocks in most programming languages. The most common constructs that -let you control the flow of execution of Rust code are `if` expressions and -loops. +条件が真かどうかによってコードを走らせるかどうかを決定したり、条件が真の間繰り返しコードを走らせるか +決定したりすることは、多くのプログラミング言語において、基本的な構成ブロックです。Rustコードの +実行フローを制御する最も一般的な文法要素は、`if`式とループです。 -### `if` Expressions +### `if`式 -An `if` expression allows us to branch our code depending on conditions. We -provide a condition and then state, “If this condition is met, run this block -of code. If the condition is not met, do not run this block of code.” +if式によって、条件に依存して枝分かれをさせることができます。条件を与え、以下のように宣言します。 +「もし条件が合ったら、この一連のコードを実行しろ。条件に合わなければ、この一連のコードは実行するな」と。 -Create a new project called *branches* in your *projects* directory to explore -the `if` expression. In the *src/main.rs* file, input the following: +*projects*ディレクトリに*branches*という名のプロジェクトを作って`if`式について掘り下げていきましょう。 +*src/main.rs*ファイルに、以下のように入力してください: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { let number = 3; if number < 5 { - println!("condition was true"); + println!("condition was true"); // 条件は真です } else { - println!("condition was false"); + println!("condition was false"); // 条件は偽です } } ``` -All `if` expressions start with the keyword `if`, which is followed by a -condition. In this case, the condition checks whether or not the variable -`number` has a value less than 5. The block of code we want to execute if the -condition is true is placed immediately after the condition inside curly -braces. Blocks of code associated with the conditions in `if` expressions are -sometimes called *arms*, just like the arms in `match` expressions that we -discussed in the “Comparing the Guess to the Secret Number” section of -Chapter 2. Optionally, we can also include an `else` expression, which we chose -to do here, to give the program an alternative block of code to execute should -the condition evaluate to false. If you don’t provide an `else` expression and -the condition is false, the program will just skip the `if` block and move on -to the next bit of code. - -Try running this code; you should see the following output: +`if`式は全て、キーワードの`if`から始め、条件式を続けます。今回の場合、条件式は変数`number`が +5未満の値になっているかどうかをチェックします。条件が真の時に実行したい一連のコードを条件式の直後に +波かっこで包んで配置します。`if`式の条件式と紐付けられる一連のコードは、時として*アーム*と呼ばれることがあります。 +第2章の「予想と秘密の数字を比較する」の節で議論した`match`式のアームのようですね。オプションとして、 +`else`式を含むこともでき(ここではそうしています)、これによりプログラムは、条件式が偽になった時に +実行するコードを与えられることになります。仮に、`else`式を与えずに条件式が偽になったら、プログラムは単に +`if`ブロックを無視して次のコードを実行しにいきます。 + +このコードを走らせてみましょう; 以下のような出力を目の当たりにするはずです: ```text $ cargo run @@ -53,14 +45,13 @@ $ cargo run condition was true ``` -Let’s try changing the value of `number` to a value that makes the condition -`false` to see what happens: +`number`の値を条件が`false`になるような値に変更してどうなるか確かめてみましょう: ```rust,ignore let number = 7; ``` -Run the program again, and look at the output: +再度プログラムを実行して、出力に注目してください: ```text $ cargo run @@ -69,82 +60,82 @@ $ cargo run condition was false ``` -It’s also worth noting that the condition in this code *must* be a `bool`. To -see what happens if the condition isn’t a `bool`, try running the following -code: +このコード内の条件式は、`bool`型で*なければならない*ことにも触れる価値があります。条件式が、 +`bool`型でない時に何が起こるかを確かめるために、以下のコードを走らせてみましょう: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore fn main() { let number = 3; if number { - println!("number was three"); + println!("number was three"); // 数値は3です } } ``` -The `if` condition evaluates to a value of `3` this time, and Rust throws an -error: +今回、`if`の条件式は`3`という値に評価され、コンパイラがエラーを投げます: ```text error[E0308]: mismatched types + (型が合いません) --> src/main.rs:4:8 | 4 | if number { | ^^^^^^ expected bool, found integral variable + | (bool型を予期したのに、整数変数が見つかりました) | = note: expected type `bool` found type `{integer}` ``` -The error indicates that Rust expected a `bool` but got an integer. Rust will -not automatically try to convert non-boolean types to a boolean, unlike -languages such as Ruby and JavaScript. You must be explicit and always provide -`if` with a `boolean` as its condition. If we want the `if` code block to run -only when a number is not equal to `0`, for example, we can change the `if` -expression to the following: +このエラーは、コンパイラは`bool`型を予期していたのに、整数だったことを示唆しています。Rustでは、 +論理値以外の値が、自動的に論理値に変換されることはありません。RubyやJavaScriptなどの言語とは +異なりますね。明示的に必ず`if`には条件式として、`論理値`を与えなければなりません。例えば、 +数値が`0`以外の時だけ`if`のコードを走らせたいなら、以下のように`if`式を変更することができます: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { let number = 3; if number != 0 { - println!("number was something other than zero"); + println!("number was something other than zero"); // 数値は0以外の何かです } } ``` -Running this code will print `number was something other than zero`. +このコードを実行したら、`number was something other than zero`と表示されるでしょう。 -#### Multiple Conditions with `else if` +#### `else if`で複数の条件 -We can have multiple conditions by combining `if` and `else` in an `else if` -expression. For example: +`if`と`else`を組み合わせて`else if`式にすることで複数の条件を持たせることもできます。例です: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { let number = 6; if number % 4 == 0 { + // 数値は4で割り切れます println!("number is divisible by 4"); } else if number % 3 == 0 { + // 数値は3で割り切れます println!("number is divisible by 3"); } else if number % 2 == 0 { + // 数値は2で割り切れます println!("number is divisible by 2"); } else { + // 数値は4、3、2で割り切れません println!("number is not divisible by 4, 3, or 2"); } } ``` -This program has four possible paths it can take. After running it, you should -see the following output: +このプログラムには、通り道が4つあります。実行後、以下のような出力を目の当たりにするはずです: ```text $ cargo run @@ -153,23 +144,20 @@ $ cargo run number is divisible by 3 ``` -When this program executes, it checks each `if` expression in turn and executes -the first body for which the condition holds true. Note that even though 6 is -divisible by 2, we don’t see the output `number is divisible by 2`, nor do we -see the `number is not divisible by 4, 3, or 2` text from the `else` block. The -reason is that Rust will only execute the block for the first true condition, -and once it finds one, it won’t even check the rest. +このプログラムを実行すると、`if`式が順番に吟味され、最初に条件が真になった本体が実行されます。 +6は2で割り切れるものの、`number is devisible by 2`や`else`ブロックの`number is not divisible by 4, 3, or 2` +という出力はされないことに注目してください。その原因は、言語が最初の真条件のブロックのみを実行し、 +条件に合ったものが見つかったら、残りはチェックすらしないということだからです。 -Using too many `else if` expressions can clutter your code, so if you have more -than one, you might want to refactor your code. Chapter 6 describes a powerful -Rust branching construct called `match` for these cases. +`else if`式を使いすぎると、コードがめちゃくちゃになってしまうので、1つ以上あるなら、 +コードをリファクタリングしたくなるかもしれません。これらのケースに有用な`match`と呼ばれる +強力なRustの枝分かれ文法要素については第6章で解説します。 -#### Using `if` in a `let` statement +#### `let`文内で`if`式を使う -Because `if` is an expression, we can use it on the right side of a `let` -statement, for instance in Listing 3-4: +`if`は式なので、`let`文の右辺に持ってくることができます。例はリスト3-4の通り: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -180,15 +168,14 @@ fn main() { 6 }; + // numberの値は、{}です println!("The value of number is: {}", number); } ``` -Listing 3-4: Assigning the result of an `if` expression -to a variable +リスト3-4: `if`式の結果を変数に代入する -The `number` variable will be bound to a value based on the outcome of the `if` -expression. Run this code to see what happens: +この`number`変数は、`if`式の結果に基づいた値に束縛されます。このコードを走らせてどうなるか確かめてください: ```text $ cargo run @@ -197,15 +184,13 @@ $ cargo run The value of number is: 5 ``` -Remember that blocks of code evaluate to the last expression in them, and -numbers by themselves are also expressions. In this case, the value of the -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-4, the results of both the `if` arm and the `else` -arm were `i32` integers. But what happens if the types are mismatched, as in -the following example? +一連のコードは、そのうちの最後の式に評価され、数値はそれ単独でも式になることを思い出してください。 +今回の場合、この`if`式全体の値は、どのブロックのコードが実行されるかに基づきます。これはつまり、 +`if`の各アームの結果になる可能性がある値は、同じ型でなければならないということになります; +リスト3-4で、`if`アームも`else`アームも結果は、`i32`の整数でした。では、以下の例のように、 +型が合わない時には、どうなるのでしょうか? -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -221,12 +206,12 @@ fn main() { } ``` -When we try to run this code, we’ll get an error. The `if` and `else` arms have -value types that are incompatible, and Rust indicates exactly where to find the -problem in the program: +このコードを走らせようとすると、エラーになります。`if`と`else`アームは互換性のない値の型になり、 +コンパイラがプログラム内で問題の見つかった箇所をスバリ指摘してくれます: ```text error[E0308]: if and else have incompatible types + (ifとelseの型に互換性がありません) --> src/main.rs:4:18 | 4 | let number = if condition { @@ -236,50 +221,47 @@ error[E0308]: if and else have incompatible types 7 | | "six" 8 | | }; | |_____^ expected integral variable, found reference + | (整数変数を予期しましたが、参照が見つかりました) | = note: expected type `{integer}` found type `&'static str` ``` -The expression in the `if` block evaluates to an integer, and the expression in -the `else` block evaluates to a string. This won’t work because variables must -have a single type. Rust needs to know at compile time what type the `number` -variable is, definitively, so it can verify at compile time that its type is -valid everywhere we use `number`. Rust wouldn’t be able to do that if the type -of `number` was only determined at runtime; the compiler would be more complex -and would make fewer guarantees about the code if it had to keep track of -multiple hypothetical types for any variable. +`if`ブロックの式は整数に評価され、`else`ブロックの式は文字列に評価されます。これでは動作しません。 +変数は単独の型でなければならないのです。コンパイラは、コンパイル時に`number`変数の型を確実に +把握する必要があるため、コンパイル時に`number`が使われている箇所全部で型が有効かどうか +検査することができるのです。`number`の型が実行時にしか決まらないのであれば、コンパイラは +それを実行することができなくなってしまいます; コンパイラはより複雑であり、どの変数に対しても、 +架空の複数の型があることを追いかけなければならないのであれば、コードに対して行える保証が +少なくなってしまうでしょう。 -### Repetition with Loops +### ループでの繰り返し -It’s often useful to execute a block of code more than once. For this task, -Rust provides several *loops*. A loop runs through the code inside the loop -body to the end and then starts immediately back at the beginning. To -experiment with loops, let’s make a new project called *loops*. +一連のコードを1回以上実行できることは、しばしば便利です。この作業用に、Rustにはいくつかの +*ループ*が用意されています。ループは、本体内のコードを最後まで実行し、直後にまた最初から開始します。 +ループを試してみるのに、*loops*という名の新プロジェクトを作りましょう。 -Rust has three kinds of loops: `loop`, `while`, and `for`. Let’s try each one. +Rustには3種類のループが存在します: `loop`と`while`と`for`です。 それぞれ試してみましょう。 -#### Repeating Code with `loop` +#### `loop`でコードを繰り返す -The `loop` keyword tells Rust to execute a block of code over and over again -forever or until you explicitly tell it to stop. +`loop`キーワードを使用すると、同じコードを何回も何回も永遠に明示的にやめさせるまで実行します。 -As an example, change the *src/main.rs* file in your *loops* directory to look -like this: +例として、*loops*ディレクトリの*src/main.rs*ファイルを以下のような感じに書き換えましょう: -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore fn main() { loop { - println!("again!"); + println!("again!"); // また } } ``` -When we run this program, we’ll see `again!` printed over and over continuously -until we stop the program manually. Most terminals support a keyboard shortcut, - ctrl-C, to halt a program that is stuck in a continual loop. Give it a try: +このプログラムを実行すると、プログラムを手動で止めるまで、何度も何度も続けて`again!`と出力するでしょう。 +ほとんどのターミナルでctrl-Cというショートカットが使え、永久ループに囚われてしまったプログラムを終了させられます。 +試しにやってみましょう: ```text $ cargo run @@ -292,30 +274,26 @@ again! ^Cagain! ``` -The symbol `^C` represents where you pressed ctrl-C. You may or may not see the -word `again!` printed after the `^C`, depending on where the code was in the -loop when it received the halt signal. +`^C`という記号が出た場所が、ctrl-Cを押した場所です。`^C`の後には`again!`と表示されたり、 +されなかったりします。ストップシグナルをコードが受け取った時にループのどこにいたかによります。 -Fortunately, Rust provides another, more reliable way to break out of a loop. -You can place the `break` keyword within the loop to tell the program when to -stop executing the loop. Recall that we did this in the guessing game in the -“Quitting After a Correct Guess” section of Chapter 2 to exit the -program when the user won the game by guessing the correct number. +幸いなことに、Rustにはループを抜け出す別のより信頼できる手段があります。ループ内に`break` +キーワードを配置することでプログラムに実行を終了すべきタイミングを教えることができます。 +第2章の「正しい予想をした後に終了する」節の数当てゲーム内でこれをして、ユーザが予想を的中させ、 +ゲームに勝った時にプログラムを終了させたことを思い出してください。 -#### Conditional Loops with `while` +#### `while`で条件付きループ -It’s often useful for a program to evaluate a condition within a loop. While -the condition is true, the loop runs. When the condition ceases to be true, you -call `break`, stopping the loop. This loop type could be implemented using a -combination of `loop`, `if`, `else`, and `break`; you could try that now in a -program, if you’d like. +プログラムにとってループ内で条件式を評価できると、便利なことがしばしばあります。条件が真の間、 +ループが走るわけです。条件が真でなくなった時に`break`を呼び出し、ループを終了します。 +このタイプのループは、`loop`、`if`、`else`、`break`を組み合わせることで実装できます; +なんならプログラムで試してみるのもいいでしょう。 -However, this pattern is so common that Rust has a built-in language construct -for it, and it’s called a `while` loop. The following example uses `while`: the -program loops three times, counting down each time. Then, after the loop, it -prints another message and exits: +しかし、このパターンは頻出するので、Rustにはそれ用の文法要素が用意されており、`while`ループと呼ばれます。 +以下の例では、`while`を使用しています: プログラムは3回ループし、それぞれカウントダウンします。 +そして、ループ後に別のメッセージを表示して終了します: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -327,20 +305,19 @@ fn main() { number = number - 1; } + // 発射! println!("LIFTOFF!!!"); } ``` -This construct eliminates a lot of nesting that would be necessary if you used -`loop`, `if`, `else`, and `break`, and it’s clearer. While a condition holds -true, the code runs; otherwise, it exits the loop. +この文法要素により、`loop`、`if`、`else`、`break`を使った時に必要になるネストがなくなり、 +より明確になります。条件が真の間、コードは実行されます; そうでなければ、ループを抜けます. -#### Looping Through a Collection with `for` +#### `for`でコレクションを覗き見る -You could use the `while` construct to loop over the elements of a collection, -such as an array. For example: +`while`要素を使って配列などのコレクションの要素を覗き見ることができます。例です: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -348,6 +325,7 @@ fn main() { let mut index = 0; while index < 5 { + // 値は{}です println!("the value is: {}", a[index]); index = index + 1; @@ -355,13 +333,11 @@ fn main() { } ``` -Listing 3-5: Looping through each element of a collection -using a `while` loop +リスト3-5: `while`ループでコレクションの各要素を覗き見る -Here, the code counts up through the elements in the array. It starts at index -`0`, and then loops until it reaches the final index in the array (that is, -when `index < 5` is no longer true). Running this code will print out every -element in the array: +ここで、コードは配列の要素を順番にカウントアップして覗いています。番号0から始まり、 +配列の最終番号に到達するまでループします(つまり、`index < 5`が真でなくなる時です)。 +このコードを走らせると、配列内の全要素が出力されます: ```text $ cargo run @@ -374,55 +350,49 @@ the value is: 40 the value is: 50 ``` -All five array values appear in the terminal, as expected. Even though `index` -will reach a value of `5` at some point, the loop stops executing before trying -to fetch a sixth value from the array. +予想通り、配列の5つの要素が全てターミナルに出力されました。`index`変数の値はどこかで`5`という値になるものの、 +配列から6番目の値を拾おうとする前にループは実行を終了します。 -But this approach is error prone; we could cause the program to panic if the -index length is incorrect. It’s also slow, because the compiler adds runtime -code to perform the conditional check on every element on every iteration -through the loop. +しかし、このアプローチは間違いが発生しやすいです; 添え字の長さが間違っていれば、プログラムは +パニックしてしまいます。また遅いです。コンパイラが実行時にループの各回ごとに境界値チェックを行う +ようなコードを追加するからです。 -As a more efficient alternative, you can use a `for` loop and execute some code -for each item in a collection. A `for` loop looks like this: +より効率的な対立案として、`for`ループを使ってコレクションの各アイテムにコードを実行することができます。 +`for`ループはこんな見た目です: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { let a = [10, 20, 30, 40, 50]; for element in a.iter() { + // 値は{}です println!("the value is: {}", element); } } ``` -Listing 3-6: Looping through each element of a collection -using a `for` loop +リスト3-6: `for`ループを使ってコレクションの各要素を覗き見る -When we run this code, we’ll see the same output as in Listing 3-5. More -importantly, we’ve now increased the safety of the code and eliminated the -chance of bugs that might result from going beyond the end of the array or not -going far enough and missing some items. +このコードを走らせたら、リスト3-5と同じ出力が得られるでしょう。より重要なのは、コードの安全性を +向上させ、配列の終端を超えてアクセスしたり、終端に届く前にループを終えてアイテムを見逃してしまったりする +バグの可能性を完全に排除したことです。 -For example, in the code in Listing 3-5, if you removed an item from the `a` -array but forgot to update the condition to `while index < 4`, the code would -panic. Using the `for` loop, you don’t need to remember to change any other -code if you changed the number of values in the array. +例えば、リスト3-5のコードで、`a`配列からアイテムを1つ削除したのに、条件式を`while index < 4`に +するのを忘れていたら、コードはパニックします。`for`ループを使っていれば、配列の要素数を変えても、 +他のコードをいじることを覚えておく必要はなくなるわけです。 -The safety and conciseness of `for` loops make them the most commonly used loop -construct in Rust. Even in situations in which you want to run some code a -certain number of times, as in the countdown example that used a `while` loop -in Listing 3-5, most Rustaceans would use a `for` loop. The way to do that -would be to use a `Range`, which is a type provided by the standard library -that generates all numbers in sequence starting from one number and ending -before another number. +`for`ループのこの安全性と簡潔性により、Rustで使用頻度の最も高いループになっています。 +リスト3-5で`while`ループを使ったカウントダウンサンプルのように、一定の回数、同じコードを実行したい +ような状況であっても、多くのRust市民は、`for`ループを使うでしょう。どうやってやるかといえば、 +`Range`型を使うのです。Range型は、標準ライブラリで提供される片方の数字から始まって、もう片方の数字未満の +数値を順番に生成する型です。 -Here’s what the countdown would look like using a `for` loop and another method -we’ve not yet talked about, `rev`, to reverse the range: +`for`ループを使い、まだ話していない別のメソッド`rev`を使って範囲を逆順にした +カウントダウンはこうなります: -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -433,18 +403,16 @@ fn main() { } ``` -This code is a bit nicer, isn’t it? +こちらのコードの方が少しいいでしょう? -## Summary +## まとめ -You made it! That was a sizable chapter: you learned about variables, scalar -and `if` expressions, and loops! If you want to practice with the concepts -discussed in this chapter, try building programs to do the following: +やりましたね!結構長い章でした: 変数とスカラー値、`if`式、そして、ループについて学びました! +この章で議論した概念について経験を積みたいのであれば、以下のことをするプログラムを組んでみてください: -* Convert temperatures between Fahrenheit and Celsius. -* Generate the nth Fibonacci number. -* Print the lyrics to the Christmas carol “The Twelve Days of Christmas,” -taking advantage of the repetition in the song. +* 温度を華氏と摂氏で変換する。 +* フィボナッチ数列のn番目を生成する。 +* クリスマスキャロルの定番、"The Twelve Days of Christmas"の歌詞を +曲の反復性を利用して出力する。 -When you’re ready to move on, we’ll talk about a concept in Rust that *doesn’t* -commonly exist in other programming languages: ownership. +次に進む準備ができたら、他の言語にはあまり存在*しない*Rustの概念について話しましょう: 所有権です。 From e586723b919498fdad16091f8f4578790734313f Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 13 Jul 2017 19:54:48 +0900 Subject: [PATCH 004/428] Add Japanese messages on README.md --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 3bec4b508..7507f25b3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ +# Rust言語 + +このリポジトリには、Rust本第1版と第2版両方がありますが、今回は第2版のみの翻訳です。 +第1版以上に、量が多そうなので、大変そうですが、以下の2点を重視して翻訳していきます。 + +* 逐語訳に拘らず、読者にとってわかりやすい訳を目指す(適宜、脚注を挟むなど) +* 原文の語順を極力尊重する(..., like so)みたいな句を文中に持っていかず、(...。こんな感じに) +のような形で訳す。つまり、ですます調で訳しますが、あまり堅すぎる文章にはしたくないという意図です + +僭越ながら、頑張りますので、よろしくお願いいたします。 + # The Rust Programming Language [![Build Status](https://travis-ci.org/rust-lang/book.svg?branch=master)](https://travis-ci.org/rust-lang/book) From 402c80a95c532a0fd6376721b8a461b27693a104 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 14 Jul 2017 20:04:52 +0900 Subject: [PATCH 005/428] First drafts of chapter 4-0 and 4-1, and add the original texts as comments on chapters 2 and 3 --- README.md | 2 +- .../src/ch02-00-guessing-game-tutorial.md | 614 ++++++++- .../ch03-00-common-programming-concepts.md | 21 + .../src/ch03-01-variables-and-mutability.md | 152 ++- second-edition/src/ch03-02-data-types.md | 274 +++- .../src/ch03-03-how-functions-work.md | 180 ++- second-edition/src/ch03-04-comments.md | 20 + second-edition/src/ch03-05-control-flow.md | 239 ++++ .../src/ch04-00-understanding-ownership.md | 18 +- .../src/ch04-01-what-is-ownership.md | 1127 ++++++++++++----- 10 files changed, 2264 insertions(+), 383 deletions(-) diff --git a/README.md b/README.md index 7507f25b3..506eb0ab2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 第1版以上に、量が多そうなので、大変そうですが、以下の2点を重視して翻訳していきます。 * 逐語訳に拘らず、読者にとってわかりやすい訳を目指す(適宜、脚注を挟むなど) -* 原文の語順を極力尊重する(..., like so)みたいな句を文中に持っていかず、(...。こんな感じに) +* 原文の語順を極力尊重する。(..., like so)みたいな句を文中に持っていかず、(...。こんな感じに) のような形で訳す。つまり、ですます調で訳しますが、あまり堅すぎる文章にはしたくないという意図です 僭越ながら、頑張りますので、よろしくお願いいたします。 diff --git a/second-edition/src/ch02-00-guessing-game-tutorial.md b/second-edition/src/ch02-00-guessing-game-tutorial.md index 472803279..f54f0da76 100644 --- a/second-edition/src/ch02-00-guessing-game-tutorial.md +++ b/second-edition/src/ch02-00-guessing-game-tutorial.md @@ -1,18 +1,37 @@ + + # 数当てゲーム + + + + + + 実物のプロジェクトに一緒に取り組むことで、Rustの世界へ飛び込みましょう! この章では、実際のプログラム内で使用する方法を通じて、いくつかの一般的なRustの概念に触れます。 let文、match式、メソッド、関連関数、外部クレートの使用などについて学ぶでしょう! 後ほどの章でこれらの概念について深く知ることになります。この章では、基礎部分だけにしましょう。 + + + + + + 古典的な初心者向けのプログラミング問題を実装してみましょう: 数当てゲームです。 これは以下のように動作します: プログラムは1から100までの乱数整数を生成します。 さらにプレーヤーに予想を入力するよう促します。予想を入力し終わったら、プログラムは、 その予想が少なすぎたか多すぎたかを出力します。予想が当たっていれば、ゲームが祝福してくれ、 そのまま終了します。 + + ## 新規プロジェクトの立ち上げ + + + 新規プロジェクトを立ち上げるには、第1章で作成した*projects*ディレクトリに行き、 Cargoを使って新規プロジェクトを作成します。そう、以下のように: @@ -21,13 +40,22 @@ $ cargo new guessing_game --bin $ cd guessing_game ``` + + + + + 最初のコマンド`cargo new`は、プロジェクト名を第1引数に取ります(`guessing_game`ですね)。 `--bin`というフラグは、Cargoにバイナリ生成プロジェクトを作成させます。第1章のものと似ていますね。 2番目のコマンドで新規プロジェクトのディレクトリに移動します。 -生成された*Cargo.toml*ファイルを見てみましょう: + + +生成された*Cargo.toml*ファイルを見てください: -Filename: Cargo.toml + + +ファイル名: Cargo.toml ```toml [package] @@ -38,13 +66,21 @@ authors = ["名前 "] [dependencies] ``` -もし、Cargoがあなたの環境から自動取得した書き手情報が間違っていたら、 + + + +もし、Cargoがあなたの環境から取得した書き手情報が間違っていたら、 ファイルを編集して保存し直してください。 + + + 第1章でも見かけたように、`cargo new`コマンドは、"Hello, world!"プログラムを生成してくれます。 *src/main.rs*ファイルをチェックしてみましょう: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust fn main() { @@ -52,6 +88,9 @@ fn main() { } ``` + + + さて、この"Hello, world!"プログラムをコンパイルし、`cargo run`コマンドを使用して、 以前と同じように動かしてみましょう: @@ -62,19 +101,33 @@ $ cargo run Hello, world! ``` + + + + `run`コマンドは、プロジェクトに段階を踏んで取り掛かる必要がある場合に有用であり、 このゲームはその類のプロジェクトになります。 つまり、次のステップに進む前に各段階を急速にテストする必要があるわけです。 + + *src/main.rs*ファイルを開き直しましょう。ここにすべてのコードを書いてきます。 + + ## 予想を処理する + + + + プログラムの最初のパートは、ユーザに入力を求め、その入力を処理し、予期した形態になっていることを確認します。 手始めにプレーヤーが予想を入力できるようにしましょう。 リスト2-1のコードを*src/main.rs*に入力してください。 -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust,ignore use std::io; @@ -93,12 +146,19 @@ fn main() { } ``` + + リスト2-1: ユーザに予想を入力してもらい、それを出力するコード > 注釈: The programming language Rust第1版の翻訳者によると、ソースコードのコメント中以外に > 日本語文字があるとコンパイルに失敗することがあるそうなので、文字列の英語は、コメントに和訳を載せます。 > また、重複する内容の場合には、最初の1回だけ掲載するようにします。 + + + + + このコードには、たくさんの情報が詰め込まれてますね。なので、少しずつ噛み砕いていきましょう。 ユーザ入力を受け付け、結果を出力するためには、`io`(入/出力)ライブラリをスコープに導入する必要があります。 `io`ライブラリは、標準ライブラリ(`std`として知られています)に存在します。: @@ -107,6 +167,12 @@ fn main() { use std::io; ``` + + + + + + 標準では、コンパイラは、[*prelude*][prelude]に存在するいくつかの型しかプログラムで使用させてくれません。 もし、使用したい型がpreludeにない場合は、`use`文で明示的にその型をスコープに導入する必要があります。 `std::io`ライブラリを使用することで、実用的な`入出力`関連の機能を使用することができます。 @@ -114,13 +180,22 @@ use std::io; [prelude]: ../../std/prelude/index.html -第1章で示した通り、`main`関数がプログラムへのエントリーポイント(スタート地点)になります: + + + +第1章で目の当たりにした通り、`main`関数がプログラムへのエントリーポイント(スタート地点)になります: ```rust,ignore fn main() { ``` -`fn`記法が関数を新しく定義し、`()`は引数がないことを示し、`{`が関数本体のスタート地点になります。 + + + +`fn`記法が関数を新しく宣言し、`()`は引数がないことを示し、`{`が関数本体のスタート地点になります。 + + + また、第1章で学んだように、`println!`マクロは、文字列を画面に表示するマクロになります: @@ -130,16 +205,27 @@ println!("Guess the number!"); println!("Please input your guess."); ``` -このコードは、このゲームが何かを出力し、ユーザに入力を求めるだけです。 + + + +このコードは、このゲームが何かを出力し、ユーザに入力を求めているだけです。 + + ### 値を変数に保持する + + 次に、ユーザ入力を保持する場所を作りましょう。こんな感じに: ```rust,ignore let mut guess = String::new(); ``` + + + + さあ、プログラムが面白くなってきましたね。このたった1行でいろんなことが起きています。 これが`let`文であることに注目してください。これを使用して*変数*を生成しています。 こちらは、別の例です: @@ -148,6 +234,10 @@ let mut guess = String::new(); let foo = bar; ``` + + + + この行では、`foo`という名前の新しい変数を作成し、`bar`の値に束縛しています。 Rustでは、変数は標準で不変(immutable)です。以下の例には、変数名の前に`mut`修飾子をつけて 変数を可変にする方法が示されています: @@ -157,9 +247,20 @@ let foo = 5; // immutable let mut bar = 5; // mutable ``` + + + + > 注釈: `//`という記法は、行末まで続くコメントを記述します。 > コンパイラは、コメントを一切無視します。 + + + + + + + さあ、`let mut guess`が`guess`という名前の可変変数を導入するとわかりましたね。 イコール記号(`=`)の逆側には、変数`guess`が束縛される値があります。この値は、今回の場合、 `String::new`関数の呼び出し結果であり、この関数は、`String`型のオブジェクトを返します。 @@ -168,16 +269,32 @@ let mut bar = 5; // mutable [string]: ../../std/string/struct.String.html + + + + + `::new`行にある`::`という記法は、`new`が`String`型の*関連付け関数*であることを表しています。 関連付け関数とは、`String`型の特定のオブジェクトよりも型(この場合は`String`)に対して 実装された関数のことであり、*静的メソッド*と呼ばれる言語もあります。 + + + + この`new`関数は、新しく空の`String`オブジェクトを生成します。`new`関数は、いろんな型に見られます。 なぜなら、何らかの新規値を生成する関数にとってありふれた名前だからです。 + + + まとめると、`let mut guess = String::new();`という行は、現在、新規で空の`String`オブジェクトに束縛されている 可変変数を作っているわけです。ふう! + + + + プログラムの1行目で、`use std::io`として、標準ライブラリから入/出力機能を取り込んだことを思い出してください。 今度は、`io`型の`stdin`関連付け関数を呼び出しましょう: @@ -186,22 +303,46 @@ io::stdin().read_line(&mut guess) .expect("Failed to read line"); ``` + + + + + 仮に、プログラムの冒頭で`use std::io`としていなければ、この関数呼び出しは、`std::io::stdin`と記述していたでしょう。 この`stdin`関数は、 [`std::io::Stdin`][iostdin]オブジェクトを返し、この型は、 ターミナルの標準入力へのハンドルを表す型になります。 [iostdin]: ../../std/io/struct.Stdin.html + + + + + その次のコード破片、`.read_line(&mut guess)`は、標準入力ハンドルの[`read_line`][read_line] メソッドを呼び出して、ユーザから入力を受け付けます。また、`read_line`メソッドに対して、引数を一つ渡していますね: `&mut guess`. [read_line]: ../../std/io/struct.Stdin.html#method.read_line + + + + + `read_line`メソッドの仕事は、ユーザが標準入力したものすべてを取り出し、文字列に格納することなので、 格納する文字列を引数として取ります。この文字列引数は、可変である必要があります。 メソッドがユーザ入力を追記して、文字列の中身を変えられるようにってことですね。 + + + + + + + + + `&`という記号は、この引数が*参照*であることを表し、これのおかげで、データを複数回メモリにコピーせずとも、 コードの複数箇所で同じデータにアクセスできるようになるわけです。参照は複雑な機能であり、 とても安全かつ簡単に参照を使うことができることは、Rustの主要な利点の一つでもあります。 @@ -209,6 +350,10 @@ guess`. 第4章で参照について詳しく見ることにしましょう。現時点では、変数のように、参照も標準で不変であることを 知っておけばいいでしょう。故に、`&guess`と書くのではなく、`&mut guess`と書いて、可変にする必要があるのです。 + + + + まだ、この行は終わりではありませんよ。テキストでは1行ですが、コードとしての論理行としては、 まだ所詮最初の部分でしかないのです。2番目の部分はこのメソッドです。: @@ -216,6 +361,10 @@ guess`. .expect("Failed to read line"); ``` + + + + `.foo()`という記法で、メソッドを呼び出す時、改行と空白で長い行を分割するのは賢いことです。 今回の場合、こう書くこともできますよね: @@ -223,11 +372,22 @@ guess`. io::stdin().read_line(&mut guess).expect("Failed to read line"); ``` + + + しかし、長い行は読みづらいものです。なので、分割しましょう。2回のメソッド呼び出しに、2行です。 さて、この行が何をしているのかについて議論しましょうか。 + + ### `Result`型で、失敗する可能性について対処する + + + + + + 以前にも述べたように、`read_line`メソッドは、渡された文字列にユーザが入力したものを入れ込むだけでなく、 値も返します(今回は[`io::Result`][ioresult]です)。 Rustには`Result`と名のついた型が 標準ライブラリにたくさんあります: ジェネリクスバージョンの[`Result`][result]の他、 @@ -236,16 +396,38 @@ io::stdin().read_line(&mut guess).expect("Failed to read line"); [ioresult]: ../../std/io/type.Result.html [result]: ../../std/result/enum.Result.html + + + + + この`Result`型は、[*列挙型*][enums]であり、普通、*enum*(イーナム)と呼ばれます。 列挙型とは、固定された種類の値を持つ型のことであり、それらの値は、enumの*バリアント*(variant)と呼ばれます。 enumについては、第6章で詳しく解説します。 [enums]: ch06-00-enums.html + + + + + `Result`型に関しては、取りうる型の値(variant)は`Ok`か`Err`です。値`Ok`は、処理が成功したことを表し、 中に生成された値を保持します。`Err`は、処理が失敗したことを意味し、`Err`は、処理が失敗した過程や、 理由などの情報を含有します。 + + + + + + + + + + + + これら`Result`型の目的は、エラー処理の情報をエンコードすることです。`Result`型の値も、他の型同様、 メソッドが定義されています。`io::Result`オブジェクトには、呼び出し可能な [`expect`メソッド][expect]があります。 @@ -258,6 +440,8 @@ enumについては、第6章で詳しく解説します。 [expect]: ../../std/result/enum.Result.html#method.expect + + もし、`expect`メソッドを呼び出さなかったら、コンパイルは通るものの、警告が出るでしょう: ```text @@ -270,23 +454,40 @@ src/main.rs:10 io::stdin().read_line(&mut guess); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` + + + + + + コンパイラは、私たちが`read_line`メソッドから返ってきた`Result`値を使用していないと警告してきており、 これは、プログラムがエラーの可能性に対処していないことを示します。警告を抑制する正しい手段は、実際にエラー対処 コードを書くことですが、今は、問題が起きた時にプロラグムをただ単にクラッシュさせたいので、`expect`を使用できるわけです。 エラーから復旧する方法については、第9章で学ぶでしょう。 + + ### `println!`マクロのプレースホルダーで値を出力する + + + 閉じ波かっこを除けば、ここまでに追加されたコードのうち議論すべきものは、残り1行であり、それは以下の通りです: ```rust,ignore println!("You guessed: {}", guess); ``` -この行は、ユーザ入力を保存した文字列の中身を出力する。1組の`{}`は、値を保持しておくプレースホルダーの役目を果たします。 + + + + + + +この行は、ユーザ入力を保存した文字列の中身を出力します。1組の`{}`は、値を保持しておくプレースホルダーの役目を果たします。 `{}`記法を使って一つ以上の値を出力できます: 最初の`{}`の組は、フォーマット文字列の後に列挙された最初の値に対応し、 2組目は、2つ目の値、とそんな感じで続いていきます。1回の`println!`マクロの呼び出しで複数値を出力するコードは、 -以下のような感じになります。: +以下のような感じになります: ```rust let x = 5; @@ -295,10 +496,16 @@ let y = 10; println!("x = {} and y = {}", x, y); ``` + + このコードは、`x = 5 and y = 10`と出力するでしょう. + + ### 最初の部分をテストする + + 数当てゲームの最初の部分をテストしてみましょう。`cargo run`コマンドでプログラムを走らせることができます: ```text @@ -311,10 +518,21 @@ Please input your guess. (ほら、予想を入力して) You guessed(次のように予想したよ): 6 ``` + + + ここまでで、ゲームの最初の部分は完成になります: キーボードからの入力を受け付け、出力できるようになりました。 + + ## 秘密の数字を生成する + + + + + + 次に、ユーザが数当てに挑戦する秘密の数字を生成する必要があります。毎回この秘密の数字は、変わるべきです。 ゲームが何回も楽しめるようにですね。ゲームが難しくなりすぎないように、1から100までの乱数を使用しましょう。 Rustの標準ライブラリには、乱数機能はまだ含まれていません。ですが、Rustチームが[`rand`クレート][randcrate]を @@ -322,16 +540,30 @@ Rustの標準ライブラリには、乱数機能はまだ含まれていませ [randcrate]: https://crates.io/crates/rand + + ### クレートを使用して機能を追加する + + + + *クレート*はRustコードのパッケージであることを思い出してください。私たちがここまで作ってきたプロジェクトは、 *バイナリークレート*であり、これは実行可能形式になります。`rand`クレートは*ライブラリクレート*であり、 他のプロラグムで使用する用のコードが含まれています。 + + + + + + Cargoを使って外部クレートを使用すると、Cargoがとても輝きます。`rand`を使ったコードを書くためには、 *Cargo.toml*ファイルを編集して、`rand`クレートを依存ファイルとして取り込む必要があります。 このファイルを開いて、以下の行をCargoが自動生成した`[dependencies]`セクションヘッダーの一番下に追記しましょう: + + ファイル名: Cargo.toml ```toml @@ -340,6 +572,16 @@ Cargoを使って外部クレートを使用すると、Cargoがとても輝き rand = "0.3.14" ``` + + + + + + + + + + *Cargo.toml*ファイルにおいて、ヘッダーに続くものは全て、他のセクションが始まるまで続くセクションの一部になります。 `[dependecies]`セクションは、プロジェクトが依存する外部クレートと必要とするバージョンを記述するところです。 今は、`rand`クレートで、意味論的バージョンには`0.3.14`を指定します。Cargoは[意味論的バージョン付け][semver] @@ -349,6 +591,9 @@ rand = "0.3.14" [semver]: http://semver.org + + + さて、コードは一切変えずに、プロジェクトをビルドしましょう。リスト2-2に示したようにね: ```text @@ -361,22 +606,47 @@ $ cargo build Compiling guessing_game v0.1.0 (file:///projects/guessing_game) (guessing_game v0.1.0をコンパイルしています) ``` + + + リスト2-2: randクレートを依存ファイルとして追加した後の`cargo build`コマンドの出力 + + + もしかしたら、バージョンナンバーは違うかもしれません(でも、互換性はあります、SemVerのおかげでね!) そして、行の出力順序も違うかもしれません。 + + + + + 今や、外部依存ファイルを持つようになったので、Cargoは*registry*(登録所)から最新バージョンを拾ってきます。 *レジストリ*とは、[Crates.io][cratesio]のデータのコピーです. Crates.ioとは、Rustのエコシステムにいる人間が 他の人も使えるように自分のオープンソースのRustプロジェクトを投稿する場所です。 [cratesio]: https://crates.io + + + + + + レジストリの更新後、Cargoは`[dependencies]`セクションをチェックし、まだ取得していないものを全部ダウンロードします。 今回の場合、`rand`しか依存ファイルには列挙していませんが、Cargoは`libc`のコピーも拾ってきます。 `rand`クレートが`libc`に依存しているからですね。ダウンロード完了後、コンパイラは依存ファイル、 そして、依存ファイルが利用可能な状態でプロジェクトをコンパイルします。 + + + + + + + + 何も変更せず即座に`cargo build`コマンドを走らせたら、何も出力されないでしょう。 Cargoは、すでに依存ファイルをダウンロードしてコンパイル済みであることを検知し、プログラマが *Cargo.toml*ファイルを弄ってないからです。さらに、Cargoはプログラマがコードを変更していないことも @@ -388,17 +658,42 @@ $ cargo build Compiling guessing_game v0.1.0 (file:///projects/guessing_game) ``` + + + + + この行は、Cargoが*src/main.rs*ファイルへの取るに足らない変更に対してビルドを更新していることを示しています。 依存ファイルは変更していないので、Cargoは、すでにダウンロードし、コンパイル済みの依存ファイルを使用できると 検知します。自分で書いたコードのみ再ビルドをかけるわけです。 + + #### *Cargo.lock*ファイルで再生成可能なビルドを保証する + + + + + + + Cargoには、プログラマが自分のコードを更新するたびに同じ生成物を再構成することを保証してくれるメカニズムを 備えています: Cargoは、プログラマが明示するまで、指定したバージョンの依存ファイルのみを使用してくれるでしょう。 例として、`rand`クレートの次週のバージョン`v0.3.15`が登場し、重要なバグ修正がなされているけれども、 自分のコードを破壊してしまう互換性破壊があった場合はどうなるでしょう? + + + + + + + + + + + この問題に対する回答は、*Cargo.lock*ファイルであり、このファイルは、初めて`cargo build`コマンドを 走らせた時に生成され、*guessing_game*ディレクトリに存在しています。プロジェクトを始めてビルドする際に、 Cargoは判断基準(criteria)に合致する依存ファイルのバージョンを割り出し、*Cargo.lock*ファイルに記述します。 @@ -407,13 +702,26 @@ Cargoは判断基準(criteria)に合致する依存ファイルのバージョ このことにより、自動的に再生成可能なビルドを構成できるのです。つまり、明示的にアップグレードしない限り、 プロジェクトが使用するバージョンは`0.3.14`に保たれるのです。*Cargo.lock*ファイルのおかげでね。 + + #### クレートを更新して新バージョンを取得する + + + クレートを*本当に*アップグレードする必要が出てきたら、Cargoの別のコマンド(`update`)を使用しましょう。これは: + + + + 1. *Cargo.lock*ファイルを無視して*Cargo.toml*ファイルに指定された通りの最新バージョンを全て割り出します。 1. それがうまくいったら、Cargoはそれらのバージョンを*Cargo.lock*ファイルに記述します。 + + + + しかし標準でCargoは、`0.3.0`以上、`0.4.0`未満のバージョンのみを検索します。`rand`クレートの新バージョンが 2つリリースされていたら(`0.3.15`と`0.4.0`ですね)、`cargo update`コマンドを走らせた時に以下のような メッセージを目の当たりにするでしょう: @@ -426,9 +734,17 @@ $ cargo update (randクレートをv0.3.14 -> v0.3.15に更新しています) ``` -ここで、プログラマはさらに*Cargo.lock*ファイルの中身が、現在使用している`rand`クレートのバージョンは、 + + + + + +ここで、プログラマはさらに*Cargo.lock*ファイルの中身の、現在使用している`rand`クレートのバージョンが、 `0.3.15`になっていることに気付くでしょう。 + + + `rand`のバージョン`0.4.0`または、`0.4.x`シリーズのどれかを使用したかったら、 代わりに*Cargo.toml*ファイルを以下のように更新しなければならないでしょう: @@ -438,8 +754,18 @@ $ cargo update rand = "0.4.0" ``` -次回、`cargo build`コマンドを走らせたら、Cargoは利用可能なクレート登録所を更新し、`rand`クレートの -必要条件を指定した新しいバージョンに再評価します。 + + + + +次回、`cargo build`コマンドを走らせたら、Cargoは利用可能なクレートのレジストリを更新し、 +`rand`クレートの必要条件を指定した新しいバージョンに再評価します。 + + + + + + まだ第14章で議論する[Cargo][doccargo]と[そのエコシステム][doccratesio] については述べたいことが山ほどありますが、とりあえずは、これで知っておくべきことは全てです。 @@ -449,10 +775,17 @@ Cargoのおかげでライブラリはとても簡単に再利用ができるの [doccargo]: http://doc.crates.io [doccratesio]: http://doc.crates.io/crates-io.html + + ### 乱数を生成する + + + `rand`クレートを*使用*開始しましょう。次のステップは、*src/main.rs*ファイルを更新することです。リスト2-3みたいにね: + + ファイル名: src/main.rs ```rust,ignore @@ -466,7 +799,7 @@ fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); - println!("The secret number is: {}", secret_number); //秘密の数字は次の通り + println!("The secret number is: {}", secret_number); //秘密の数字は次の通り: {} println!("Please input your guess."); @@ -479,15 +812,37 @@ fn main() { } ``` + + + リスト2-3: 乱数を生成するのに必要なコードの変更 + + + + + 冒頭に`extern crate rand;`行を追加して、コンパイラにこの外部依存ファイルを使用することを知らせています。 これにより、`use rand`を呼ぶのと同じ効果が得られるので、`rand`クレートのものを`rand::` という接頭辞をつけて呼び出せるようになりました。 + + + + 次に、別の`use`行を追加しています: `use rand::Rng`ですね。`Rng`とは乱数生成器が実装するメソッドを定義した トレイトであり、このトレイトがスコープにないと、メソッドを使用できないのです。トレイトについて詳しくは、 -第10章を参照されたし。 +第10章を解説します。 + + + + + + + + + + また、途中に2行追加もしています。`rand::thread_rng`関数は、私たちが使う特定の乱数生成器を 返してくれます: この乱数生成器は、実行スレッドに特有で、OSにより、シード値を与えられています。 @@ -496,15 +851,30 @@ fn main() { それらの間の乱数を生成してくれます。最低値は含むものの、最高値は含まないため、`1`と`101`と指定しないと 1から100の範囲の数字は得られません。 + + + + + + + + 使用すべきトレイトとクレートから呼び出すべき関数とメソッドを知ることが、単純に*知っている*ことではないでしょう。 クレートの使用方法は、各クレートのドキュメントにある。Cargoの別の巧妙な機能は、`cargo doc --open`コマンドを 走らせてローカルに存在する依存ファィルすべてのドキュメントをビルドし、Webブラウザで閲覧できる機能です。例えば、 `rand`クレートの他の機能に興味があるなら、`cargo doc --open`コマンドを走らせて、左側のサイドバーから `rand`をクリックすればいいわけです。 -コードに追加した2行目は、秘密の数字を出力してくれます。これは、プログラムをテストする構築中には便利であるが、 + + + + + +コードに追加した2行目は、秘密の数字を出力してくれます。これは、プログラムをテストする構築中には便利ですが、 最終版からは削除する予定です。プログラムがスタートと同時に答えを出力しちゃったら、ゲームにならないからですね! + + 何回かプログラムを走らせてみてください: ```text @@ -525,13 +895,23 @@ Please input your guess. You guessed: 5 ``` + + + 毎回異なる乱数が出、その数字はすべて1から100の範囲になるはずです。よくやりました! + + ## 予想と秘密の数字を比較する + + + 今や、ユーザ入力と乱数生成ができるようになったので、比較することができますね。 このステップはリスト2-4に示されています: + + ファイル名: src/main.rs ```rust,ignore @@ -565,12 +945,23 @@ fn main() { } ``` + + + リスト2-4: 2値比較の返り値を処理する + + + + + + 最初の新しい点は、別の`use`文です。これで、`std::cmp::Ordering`という型を標準ライブラリから スコープに導入しています。`Ordering`もenumです。`Result`のようにね。ただ、`Ordering`が取りうる値は、 `Less`、`Greater`そして、`Equal`です。これらは、2値比較した時に発生しうる3種類の結果です。 + + それから、一番下に5行追加して`Ordering`型を使用しています: ```rust,ignore @@ -581,6 +972,14 @@ match guess.cmp(&secret_number) { } ``` + + + + + + + + `cmp`メソッドは、2値を比較し、比較できるものに対してならなんに対しても呼び出せます。このメソッドは、 比較したいものへの参照を取ります: ここでは、`guess`変数と`secret_number`変数を比較しています。 `cmp`メソッドは`use`文でスコープに導入した`Ordering`列挙型の値を返します。 @@ -589,12 +988,32 @@ match guess.cmp(&secret_number) { [match]: ch06-02-match.html + + + + + + + + `match`式は、複数の*アーム*(腕)からできています。一つのアームは、パターンとそのパターンに `match`式の冒頭で与えた値がマッチした時に走るコードから構成されています。Rustは、`match`に与えられた 値を取り、各アームのパターンを順番に吟味していきます。`match`式とパターンは、コードを書く際に 目の当たりにする様々なシチュエーションを表現させてくれ、すべてのシチュエーションに対処する手助けをしてくれる Rustの強力な機能です。これらの機能は、それぞれ、第6章と第18章で詳しく解説することにします。 + + + + + + + + + + + + ここで使われている`match`式でどんなことが起こるかの例をじっくり観察してみましょう!例えば、 ユーザは50と予想し、ランダム生成された秘密の数字は今回、38だったとしましょう。コードが50と38を比較すると、 `cmp`メソッドは`Ordering::Greater`を返します。50は38よりも大きいからですね。`Ordering::Greater`が、 @@ -604,6 +1023,8 @@ Rustの強力な機能です。これらの機能は、それぞれ、第6章と このアームに紐づけられたコードが実行され、画面に`Too big!`が表示されます。 これで`match`式の実行は終わりになります。この筋書きでは、最後のアームを吟味する必要はもうないからですね。 + + ところが、リスト2-4のコードは、まだコンパイルが通りません。試してみましょう: ```text @@ -623,6 +1044,17 @@ error: aborting due to previous error (先のエラーのため、処理を中 Could not compile `guessing_game`. (`guessing_game`をコンパイルできませんでした) ``` + + + + + + + + + + + このエラーの核は、*型の不一致*があると言っています。Rustは、強力な静的型付けシステムを持っています。 しかし、型推論にも対応しています。`let guess = String::new()`と書いた時、コンパイラは、 `guess`が`String`型であるべきと推論してくれ、その型を明示させられることはありませんでした。 @@ -631,9 +1063,15 @@ Could not compile `guessing_game`. (`guessing_game`をコンパイルでき Rustでの標準は、`i32`型であり、型情報をどこかに追加して、コンパイラに異なる数値型だと推論させない限り、 `secret_number`の型はこれになります。エラーの原因は、Rustでは、文字列と数値型を比較できないことです。 + + + + 究極的には、プログラムが入力として読み込む`String`型を現実の数値型に変換し、予想と数値として比較できるように したいわけです。これは、以下の2行を`main`関数の本体に追記することでできます: + + ファイル名: src/main.rs ```rust,ignore @@ -670,6 +1108,8 @@ fn main() { } ``` + + その2行とは以下のようなものです: ```rust,ignore @@ -677,12 +1117,30 @@ let guess: u32 = guess.trim().parse() .expect("Please type a number!"); ``` + + + + + + + + `guess`という名前の変数を生成しています。あれ、でも待って。もうプログラムには`guess`という名前の変数が ありませんでしたっけ?確かにありますが、Rustでは、新しい値で`guess`の値を*多重定義*(shadow)することが 許されているのです。この機能は、今回のような、値を別の型に変換したいシチュエーションでよく使われます。 多重定義のおかげで別々の変数を2つ作らされることなく、`guess`という変数名を再利用することができるのです。 `guess_str`と`guess`みたいなね(多重定義については、第3章でもっと掘り下げます)。 + + + + + + + + + + `guess`を`guess.trim().parse()`という式に束縛しています。この式中の`guess`は、入力が入った `String`型の元々の`guess`を指しています。`String`オブジェクトの`trim`メソッドは、 両端の空白をすべて除去します。`u32`型は、数字しか含むことができませんが、ユーザは、`read_line`の @@ -691,6 +1149,17 @@ let guess: u32 = guess.trim().parse() 次のようになります: `5\n`。この`\n`が改行、つまりリターンキーを表しているわけです。 `trim`メソッドは、`\n`を削除するので、ただの`5`になります。 + + + + + + + + + + + [文字列の`parse`メソッド][parse]は、文字列を解析して何らかの数値にします。 このメソッドは、いろんな数値型を解析できるので、`let guess: u32`としてコンパイラに私たちが 求めている型をズバリ示唆する必要があるのです。`guess`の後のコロン(`:`)がコンパイラに変数の型を @@ -702,6 +1171,17 @@ let guess: u32 = guess.trim().parse() [parse]: ../../std/primitive.str.html#method.parse + + + + + + + + + + + `parse`メソッドの呼び出しは、エラーになりやすいです。例としては、文字列が`A👍%`を含んでいたら、 数値に変換できるわけがないわけです。失敗する可能性があるので、`parse`メソッドは、`Result`型を 返すわけです。ちょうど、「Result型で失敗する可能性に対処する」節で先ほど議論した`read_line`メソッドが @@ -711,6 +1191,8 @@ let guess: u32 = guess.trim().parse() もし、`parse`メソッドが文字列の数値への変換に成功したら、`Result`型の`Ok`値を返し、 `expect`メソッドは、`Ok`値から必要な数値を返してくれます。 + + さあ、プログラムを走らせましょう! ```text @@ -725,17 +1207,32 @@ You guessed: 76 Too big! ``` + + + + + いいですね!予想の前にスペースを追加したにもかかわらず、プログラムはちゃんとユーザが76と予想したことを 導き出しました。プログラムを何回か走らせて、異なる入力の異なる振る舞いを確認してください: つまり、 数字を正しく言い当てたり、大きすぎる値を予想したり、低すぎる数字を入力したりということです。 + + + ここまでで大方ゲームはうまく動くようになりましたが、まだユーザは1回しか予想できません。 ループを追加して、その部分を変更しましょう! + + ## ループで複数回の予想を可能にする + + + `loop`キーワードは、無限ループを作り出します。これを追加して、ユーザが何回も予想できるようにしましょう: + + ファイル名: src/main.rs ```rust,ignore @@ -774,9 +1271,22 @@ fn main() { } ``` + + + + + + 見てわかる通り、予想入力部分以降をループに入れ込みました。変更した行にインデントを追加するのを忘れないようにして、 またプログラムを走らせてみましょう。新たな問題が発生したことに気をつけてください。 -プログラムが教えた通りに動作しているからですね: 永遠に予想入力を求めるわけです!これでは、終了できません! +プログラムが教えた通りに動作しているからですね: 永遠に予想入力を求めるわけです! +これでは、ユーザが終了できないようです! + + + + + + ユーザは、`Ctrl-C`というキーボードショートカットを使って、いつでもプログラムを強制終了させられます。 しかし、「予想を秘密の数字と比較する」節の`parse`メソッドに関する議論で触れたこの貪欲なモンスターを @@ -811,12 +1321,22 @@ error: Process didn't exit successfully: `target/debug/guess` (exit code: 101) (エラー: プロセスは予期なく終了しました) ``` + + + + `quit`と入力すれば、実際にゲームを終了できるわけですが、別に他の数字以外の入力でもそうなります。 しかしながら、これは最低限度と言えるでしょう。正しい数字が予想されたら、自動的にゲームが停止してほしいわけです。 + + ### 正しい予想をした後に終了する -`break`文を追加してユーザが勝った時にゲームを終了するようにしましょう: + + +`break`文を追加して、ユーザが勝った時にゲームが終了するようにしましょう: + + ファイル名: src/main.rs @@ -859,12 +1379,23 @@ fn main() { } ``` + + + + `break`文の1行を`You win!`の後に追記することで、ユーザが秘密の数字を正確に予想したら、プログラムは ループを抜けるようになりました。ついでに、ループを抜けることは、プログラムを終了することを意味します。 ループが`main`関数の最後の部分だからですね。 + + ### 不正な入力を処理する + + + + + さらにゲームの振る舞いを改善するために、ユーザが数値以外を入力した時にプログラムをクラッシュさせるのではなく、 非数値を無視してユーザが数当てを続けられるようにしましょう!これは、`guess`が`String`型から `u32`方に変換される行を改変することで達成できます: @@ -876,16 +1407,38 @@ let guess: u32 = match guess.trim().parse() { }; ``` + + + + + + `expect`メソッドの呼び出しから`match`式に切り替えることは、エラーでクラッシュする動作から 実際にエラー処理を行う処理へ変更する一般的な手段になります。`parse`メソッドは、`Result`型を 返し、`Result`は`Ok`か`Err`の値を取りうるenumであることを思い出してください。 ここでは`match`式を使っています。`cmp`メソッドの`Ordering`という結果でしたのと同じですね。 + + + + + + `parse`メソッドは、文字列から数値への変換に成功したら、結果の数値を保持する`Ok`値を返します。 この`Ok`値は、最初のアームのパターンにマッチし、この`match`式は`parse`メソッドが生成し、 `Ok`値に格納した`num`の値を返すだけです。その数値が最終的に生成した新しい`guess`変数に 含まれます。 + + + + + + + + + + `parse`メソッドは、文字列から数値への変換に*失敗*したら、エラーに関する情報を多く含む`Err`値を 返します。この`Err`値は、最初の`match`アームの`Ok(num)`というパターンにはマッチしないものの、 2番目のアームの`Err(_)`というパターンにはマッチするわけです。この`_`は、包括値です; この例では、 @@ -894,6 +1447,9 @@ let guess: u32 = match guess.trim().parse() { 次の段階に移り、再度予想入力を求めることを意味します。故に実効的には、プログラムは`parse`メソッドが 遭遇しうる全てのエラーを無視するようになります! + + + さて、プログラムの全てがうまく予想通りに動くはずです。`cargo run`コマンドで走らせて、試してみましょう: ```text @@ -918,11 +1474,18 @@ You guessed: 61 You win! ``` + + + + + 素晴らしい!最後にひとつまみ変更を加えて、数当てゲームを完了にしましょう: プログラムが未だに 秘密の数字を出力していることを思い出してください。テスト中はうまく動くけど、 ゲームを台無しにしてしまいます。秘密の数字を出力する`println!`マクロを削除しましょう。 リスト2-5が成果物のコードです: + + ファイル名: src/main.rs ```rust,ignore @@ -964,12 +1527,27 @@ fn main() { } ``` + + リスト2-5: 数当てゲームの完全なコード + + ## まとめ + + ここまでで、数当てゲームの作成に成功しました!おめでとうございます! + + + + + + + + + このプロジェクトは、たくさんの新しいRustの概念に触れる実践的な方法でした: `let`文、`match`式、メソッド、関連付け関数、外部クレートの使用などなど。 以降の数章で、これらの概念についてより深く学ぶことになるでしょう。 diff --git a/second-edition/src/ch03-00-common-programming-concepts.md b/second-edition/src/ch03-00-common-programming-concepts.md index 7feb257a6..4c4c07770 100644 --- a/second-edition/src/ch03-00-common-programming-concepts.md +++ b/second-edition/src/ch03-00-common-programming-concepts.md @@ -1,14 +1,35 @@ + + # 一般的なプログラミングの概念 + + + + + この章では、ほとんど全てのプログラミング言語で見られる概念を解説し、それらがRustにおいて、 どう動作するかを見ていこう。多くのプログラミング言語は、その核心において、いろいろなものを共有しています。 この章で提示する概念は、全てRustに固有のものではありませんが、Rustの文脈で議論し、その規格を 解説していきます。 + + + + 具体的には、変数、基本的な型、関数、コメント、そしてフロー制御について学びます。 これらの基礎は全てのRustプログラムに存在するものであり、それらを早期に学ぶことは 強力な基礎を築くことになるでしょう。 + + + + + + + + + + > ### キーワード > > Rust言語にも他の言語同様、キーワードが存在し、これらは言語だけが使用できるようになっています。 diff --git a/second-edition/src/ch03-01-variables-and-mutability.md b/second-edition/src/ch03-01-variables-and-mutability.md index 5300de31f..e6ab6bd8d 100644 --- a/second-edition/src/ch03-01-variables-and-mutability.md +++ b/second-edition/src/ch03-01-variables-and-mutability.md @@ -1,16 +1,33 @@ + + ## 変数と可変性 + + + + + + 第2章で触れた通り、変数は標準で*不変*になります。これは、Rustが提供する安全性や簡潔な並列プログラミングの 利点を享受する形でコードを書くことを推奨してくれる一押しです。ところが、まだ変数を可変にするという 選択肢も残されています。不変性を好むようコンパイラが推奨する手段と理由および、それと違う道を選びたくなる理由を 見ていきましょう。 + + + + 変数が不変であるとは、値が一旦名前に束縛されたら、その値を変えることができないことを意味します。 具体化するために、*projects*ディレクトリに`cargo new --bin variables`コマンドを使って *variables*という名前のプロジェクトを生成しましょう。 + + + それから、新規作成した*variables*ディレクトリで、*src/main.rs*ファイルを開き、その中身を以下のように置き換えましょう: + + ファイル名: src/main.rs ```rust,ignore @@ -22,6 +39,9 @@ fn main() { } ``` + + + これを保存し、`cargo run`コマンドでプログラムを走らせてください。次の出力に示されているようなエラーメッセージを受け取るはずです: ```text @@ -37,28 +57,59 @@ error[E0384]: re-assignment of immutable variable `x` | ^^^^^ re-assignment of immutable variable ``` + + + + + + + + この例では、コンパイラがプログラムに潜むエラーを見つけ出す手助けをしてくれることが示されています。 コンパイルエラーは、イライラするものですが、まだプログラムにしてほしいことを安全に行えていないだけ なのです; エラーが出るからといって、あなたがいいプログラマではないという意味では*ありません*! 経験豊富なRust市民でも、コンパイラエラーを出すことはあります。このエラーは、エラーの原因が `不変変数への再代入`であると示しています。不変な`x`という変数に第2段階の値を代入しようとしたからです。 + + + + + + + + 以前に不変と指定された値を変えようとした時に、コンパイルエラーが出るのは重要なことです。 なぜなら、この状況はまさしく、バグに繋がるからです。コードのある部分は、値が変わることはないという 前提のもとに処理を行い、別の部分がその値を変更していたら、最初の部分が目論見通りに 動いていない可能性があるのです。このようなバグの発生は、事実(`脚注`:実際にプログラムを走らせた結果のことと思われる) の後には追いかけづらいものです。特に第2のコード破片が、値を*時々*しか変えない場合尚更です。 + + + + + Rustでは、値が不変であると宣言したら、本当に変わらないことをコンパイラが担保してくれます。 つまり、コードを読み書きする際に、どこでどうやって値が変化しているかを追いかける必要がなくなり、 コードが行うことを把握しやすくなります。 + + + + + + しかし、可変性は時として非常に便利なこともあります。変数は、標準でのみ、不変です。つまり、変数名の前に -`mut`キーワードを付ければ、可変にできるわけです。 この値が変化できるようにするとともに、未来の読者に対して +`mut`キーワードを付ければ、可変にできるわけです。この値が変化できるようにするとともに、未来の読者に対して コードの別の部分がこの変数の値を変えることを示すことで、その意図を汲ませることができるのです。 + + 例として、*src/main.rs*ファイルを以下のように書き換えてください: + + ファイル名: src/main.rs ```rust @@ -70,6 +121,8 @@ fn main() { } ``` + + このプログラムを走らせると、以下のような出力が得られます: ```text @@ -80,32 +133,71 @@ The value of x is: 5 (xの値は5です) The value of x is: 6 ``` + + + + + `mut`キーワードを使うことで、`x`が束縛している値を`5`から`6`に変更できるようになりました。 変数を可変にする方が、不変変数だけを使う実装よりも書きやすくなるケースもあるでしょう。 + + + + + + + 考えるべきトレードオフはバグの阻止以外にも、いくつかあります。例えば、大きなデータ構造を使う場合などです。 オブジェクトを可変にして変更できるようにする方が、いちいちオブジェクトをコピーして新しくメモリ割り当てされた オブジェクトを返すよりも速くなります。小規模なデータ構造なら、新規オブジェクトを生成して、 もっと関数型っぽいコードを書く方が中身を把握しやすくなるため、低パフォーマンスは、その簡潔性を得るのに 足りうるペナルティになるかもしれません。 + + ### 変数と定数(constants)の違い + + + + + + 変数の値を変更できないようにするといえば、他の多くの言語も持っている別のプログラミング概念を思い浮かべるでしょう: *定数*です. 不変変数のように、定数も名前に紐付き、変更することが叶わない値のことですが、 定数と変数の間にはいくつかの違いがあります。 + + + まず、定数には`mut`キーワードは使えません: 定数は標準で不変であるだけでなく、常に不変なのです。 + + + + + 定数は`let`キーワードの代わりに、`const`キーワードで宣言し、値の型は*必ず*注釈しなければなりません。 型と型注釈については次のセクション、「データ型」で解説する予定なので、その詳細については気にする必要はありません。 ただ単に型を注釈しなければならないのだと思っていてください。 + + + 定数はどんなスコープでも定義できます。グローバルスコープも含めてね。なので、いろんなところで使用される可能性のある値を 定義するのに便利です。 + + + + 最後の違いは、定数は定数式にしかセットできないことです。関数呼び出し結果や、実行時に評価される値ではありません。 + + + + 定数の名前が`MAX_POINTS`で値が100,000にセットされた定数定義の例をご覧ください。(Rustの定数の命名規則は、 全て大文字でアンダースコアで単語区切りすることです): @@ -113,21 +205,43 @@ The value of x is: 6 const MAX_POINTS: u32 = 100_000; ``` + + + + + + 定数は、プログラムが走る期間、定義されたスコープ内でずっと有効です。従って、プログラムのいろんなところで -使用される可能性のあるアプリケーション空間の値を定義するのに便利な選択肢になります。例えば、ゲームでプレイヤーが取得可能なポイントの -最高値や、光速度などですね。 +使用される可能性のあるアプリケーション空間の値を定義するのに便利な選択肢になります。例えば、 +ゲームでプレイヤーが取得可能なポイントの最高値や、光速度などですね。 + + + + + プログラム中で使用されるハードコードされた値に対して、定数として名前付けすることは、コードの将来的な 管理者にとって値の意味を汲むのに便利です。将来、ハードコードされた値を変える必要が出た時に、 たった1箇所を変更するだけで済むようにもしてくれます。 + + ### (変数の)多重定義 + + + + + + + 第2章の数当てゲームのチュートリアルで見たように、前に定義した変数と同じ名前の変数を新しく定義でき、 新しい変数は、前の変数を*上書き*(shadow)する。Rust市民はこれを最初の変数は、2番目の変数に*上書き* されたと言い、この変数を使用した際に、2番目の変数の値が得られるということです。 以下のようにして、同じ変数名を用いて変数を上書きし、`let`キーワードの使用を繰り返します: + + ファイル名: src/main.rs ```rust @@ -142,6 +256,12 @@ fn main() { } ``` + + + + + + このプログラムはまず、`x`を`5`という値に束縛します。それから`let x =`という文法要素を繰り返すことで `x`を上書きし、元の値に`1`を加えることになるので、`x`の値は、`6`になります。 3番目の`let`文も`x`を上書きし、以前の値に`2`をかけることになるので、`x`の最終的な値は`12`になります。 @@ -154,11 +274,22 @@ $ cargo run The value of x is: 12 ``` + + + + + これは、変数を`mut`にするのとは違います。なぜなら、`let`キーワードを使っている限り、誤ってこの変数に 再代入を試みようものなら、コンパイルエラーが出るからです。値にちょっとした加工は加えられますが、 その加工が終わったら、変数は不変になるわけです。 -`mut`と上書きの別の違いは、再度`let`キーワードを使用したら、実効的には新しい変数を生成していることになるので、 + + + + + + +`mut`と上書きのもう一つの違いは、再度`let`キーワードを使用したら、実効的には新しい変数を生成していることになるので、 値の型を変えつつ、同じ変数名を使いまわせることです。例えば、プログラムがユーザに何らかのテキストに対して 空白文字を入力することで何個分のスペースを表示したいかを尋ねるとします。ただ、この入力を数値として 保持したいとしましょう: @@ -168,6 +299,13 @@ let spaces = " "; let spaces = spaces.len(); ``` + + + + + + + この文法要素は、容認されます。というのも、最初の`spaces`変数は文字列型であり、2番目の`spaces`変数は、 たまたま最初の変数と同じ名前になったまっさらな変数のわけですが、数値型になるからです。故に、多重定義のおかげで、 異なる名前を思いつく必要がなくなるわけです。`spaces_str`と`spaces_num`などですね; 代わりに、 @@ -179,6 +317,9 @@ let mut spaces = " "; spaces = spaces.len(); ``` + + + コンパイルエラーが発生します。変数の型を可変にすることは許されていないからですね: ```text @@ -193,4 +334,7 @@ error[E0308]: mismatched types (型が合いません) found type `usize` ``` + + + さあ、変数が動作する方法を見てきたので、今度は変数が取りうるデータ型について見ていきましょう。 diff --git a/second-edition/src/ch03-02-data-types.md b/second-edition/src/ch03-02-data-types.md index da2d2fd54..576e2e5e4 100644 --- a/second-edition/src/ch03-02-data-types.md +++ b/second-edition/src/ch03-02-data-types.md @@ -1,9 +1,23 @@ + + ## データ型 + + + + + Rustにおける値は全て、何らかの*型*になり、コンパイラがどんなデータが指定されているか知れるので、 そのデータの取り扱い方も把握できるというわけです。この節では、言語に組み込まれている種々の型について 見ていきましょう。型を二分割しましょう: スカラー型と複合型です。 + + + + + + + この節を通して、Rustは*静的型付け*言語であることを弁えておいてください。つまり、コンパイル時に 全ての変数の型が判明している必要があるということです。コンパイラは通常、値と使用方法に基づいて、 使用したい型を推論してくれます。複数の型が推論される可能性がある場合、そう例えば、第2章で`parse`メソッドを @@ -13,6 +27,10 @@ Rustにおける値は全て、何らかの*型*になり、コンパイラが let guess: u32 = "42".parse().expect("Not a number!"); // 数字ではありません! ``` + + + + ここで型注釈を付けなければ、コンパイラは以下のエラーを表示し、これは可能性のある型のうち、 どの型を使用したいのかを知るのに、コンパイラがプログラマからもっと情報を得る必要があることを 意味します: @@ -30,23 +48,52 @@ error[E0282]: unable to infer enough type information about `_` (注釈: 型注釈、またはジェネリクス引数束縛が必要です) ``` + + いろいろなデータ型について議論するにつれて、様々な型注釈を目撃することになるでしょう。 + + ### スカラー型 + + + + + スカラー型は、単独の値を表します。Rustには主に4つのスカラー型があります: 整数、浮動小数点数、論理値、最後に文字です。他のプログラミング言語でも、これらの型を見かけたことはあるでしょうが、 Rustでの動作方法について見ていきましょう。 + + #### 整数型 + + + + + + + + 整数とは、小数部分のない数値のことです。この章の前半で一つの整数型を使用しました。`i32`型です。 この型定義は、紐付けられる値が、符号付き整数(そのため、`i`になります。非負整数に対する`u`と逆ですね) になり、これは、32ビット分のサイズを取ります。表3-1は、Rustの組み込み整数型を表示しています。 符号付きと符号なし欄の各バリアント(例: *i32*)を使用して、整数値の型を定義することができます。 + + 表3-1: Rustの整数型 + + + + + + + + | 大きさ | 符号付き | 符号なし | |--------|--------|----------| | 8-bit | i8 | u8 | @@ -55,6 +102,17 @@ Rustでの動作方法について見ていきましょう。 | 64-bit | i64 | u64 | | arch | isize | usize | + + + + + + + + + + + 各バリアントは、符号付きか符号なしかを選べ、明示的なサイズを持ちます。符号付きと符号なしの特性は、 数値が正負を持つかどうかを示します。つまり、数値が符号を持つ必要があるかどうか(符号付き)、または、 絶対に正数にしかならず符号なしで表現できるかどうか(符号なし)です。これは、数値を紙に書き下すのと似ています: @@ -63,20 +121,44 @@ Rustでの動作方法について見ていきましょう。 2の補数表現で保持されます(これが何なのか確信を持てないのであれば、ネットで検索することができます。 まあ要するに、この解説は、この本の範疇外というわけです)。 + + + + + + 各符号付きバリアントは、-(2n - 1)から2n - 1 - 1までの数値を保持でき、 ここで`n`はこのバリアントが使用するビット数です。以上から、`i8`型は-(27)から 27 - 1まで、つまり、-128から127までを保持できます。符号なしバリアントは、0から 2n - 1までを保持できるので、`u8`型は、0から28 - 1までの値、つまり、 0から255までを保持できることになります。 + + + + 加えて、`isize`と`usize`型は、プログラムが動作しているコンピュータの種類に依存します: 64ビットアーキテクチャなら、64ビットですし、32ビットアーキテクチャなら、32ビットになります。 + + + + 整数リテラル(`脚注`: リテラルとは、見たまんまの値ということ)は表3-2に示すどの形態でも記述することができます。バイトリテラルを除く数値リテラルは全て、 型接尾辞を付加すること(例えば、`57u8`)と`_`を見た目の区切り記号(例えば、`1_000`)にできます。 + + 表3-2: Rustの整数リテラル + + + + + + + + | 数値リテラル | 例 | |------------------|---------------| | 10進数 | `98_222` | @@ -85,12 +167,29 @@ Rustでの動作方法について見ていきましょう。 | 2進数 | `0b1111_0000` | | バイト (`u8`だけ) | `b'A'` | + + + + + では、どの整数型を使うべきかはどう把握すればいいのでしょうか?もし確信が持てないのならば、Rustの デフォルトは一般的にいい選択になります。整数型の基準は`i32`型です: 64ビットシステム上でも、 普通最速になります。`isize`と`usize`を使う主な状況は、何らかのコレクションにアクセスすることです。 + + #### 浮動小数点型 + + + + + + + + + + Rustにはさらに、*浮動小数点数*に対しても、2種類の基本型があり、浮動小数点数とは10進小数のことです。 Rustの浮動小数点型は、`f32`と`f64`で、それぞれ32ビットと64ビットサイズです。基準型は`f64`です。 なぜなら、`f32`とほぼ同スピードにもかかわらず、より精度が高くなるからです。32ビットシステム上でも、 @@ -98,8 +197,12 @@ Rustの浮動小数点型は、`f32`と`f64`で、それぞれ32ビットと64 可能性と引き換えに高精度を得ることは、一考の価値のある第1選択肢になる上、自らのコードで浮動小数点数のサイズが 問題になる可能性があると疑うのなら、ベンチマークをしてみるべきです。 + + 実際に動作している浮動小数点数の例をご覧ください: + + ファイル名: src/main.rs ```rust @@ -110,16 +213,46 @@ fn main() { } ``` + + + 浮動小数点数は、IEEE-754規格に従って表現されています。`f32`が単精度浮動小数点数、 `f64`が倍精度浮動小数点数です。 + + #### 数値演算 + + + + Rustにも期待されうる標準的な数学演算が全数値型に対して用意されています: 足し算、引き算、掛け算、割り算、余りです。 以下の例では、`let`文での各演算の使用方法をご覧になれます: + + ファイル名: src/main.rs + + + + + + + + + + + + + + + + + + + ```rust fn main() { // 足し算 @@ -139,17 +272,37 @@ fn main() { } ``` + + + + これらの文の各式は、数学演算子を使用しており、一つの値に評価され、変数に束縛されます。付録BにRustで使える 演算子の一覧が載っています。 + + #### 論理値型 + + + + 他の多くの言語同様、Rustの論理値型も取りうる値は二つしかありません: `true`と`false`です。 Rustの論理値型は、`bool`と指定されます。 例です: + + ファイル名: src/main.rs + + + + + + + + ```rust fn main() { let t = true; @@ -158,14 +311,26 @@ fn main() { } ``` + + + + 論理値を消費する主な手段は、条件式です。例えば、`if`式などですね。`if`式の動作方法については、 「フロー制御」節で解説します。 + + #### 文字型 + + + + ここまで、数値型のみ扱ってきましたが、Rustには文字も用意されています。Rustの`char`型は、言語の最も 基本的なアルファベット型であり、以下のコードでその使用方法の一例を見ることができます: + + ファイル名: src/main.rs ```rust @@ -176,6 +341,15 @@ fn main() { } ``` + + + + + + + + + Rustの`char`型は、ユニコードのスカラー値を表します。これはつまり、アスキーよりもずっとたくさんの ものを表せるということです。アクセント文字、中国語/日本語/韓国語表意文字(`脚注`: 漢字のことだと思われる)、 絵文字、ゼロ幅スペースは、全てRustでは、有効な`char`型になります。ユニコードスカラー値は、 @@ -183,18 +357,35 @@ Rustの`char`型は、ユニコードのスカラー値を表します。これ 実はユニコードの概念ではないので、文字とは何かという人間としての直観は、Rustにおける`char`型が何か とは合致しない可能性があります。この話題については第8章の「文字列」節で詳しく議論しましょう。 + + ### 複合型 + + + *複合型*により、複数の型の値を一つの型にまとめることができます。Rustには、 2種類の基本的な複合型があります: タプルと配列です。 + + #### 値をタプルにまとめ上げる + + + タプルは、複数の型の何らかの値を一つの複合型にまとめ上げる一般的な手段です。 + + + + + タプルは、丸かっこの中にカンマ区切りの値リストを書くことで生成します。タプルの各位置には型が紐付けられ、 タプルの値は全てが同じ型である必要はありません。今回の例では、型注釈をあえて追加してみました: + + ファイル名: src/main.rs ```rust @@ -203,9 +394,15 @@ fn main() { } ``` + + + + 変数`tup`は、タプル全体に束縛されています。なぜなら、タプルは、一つの複合要素と考えられるからです。 タプルからここの値を取り出すには、パターンマッチングにより分解を使用することができます。以下のように: + + ファイル名: src/main.rs ```rust @@ -218,14 +415,26 @@ fn main() { } ``` + + + + + + このプログラムは、まずタプルを生成し、それを変数`tup`に束縛しています。それから`let`文と パターンを使って`tup`変数の中身を3つの個別の変数(`x`、`y`、`z`ですね)に変換しています。 この過程は、*分解*と呼ばれます。単独のタプルを破壊して三分割しているからです。最後に、 プログラムは`y`変数の値を出力し、それは`6.4`になります。 + + + + パターンマッチングを通しての分解の他にも、アクセスしたい値の番号をピリオドに続けて書くことで、 タプルの要素に直接アクセスすることもできます。例です: + + ファイル名: src/main.rs ```rust @@ -240,17 +449,33 @@ fn main() { } ``` + + + + このプログラムは、新しいタプル`x`を作成し、添え字アクセスで書く要素に対して新しい変数も作成しています。 多くのプログラミング言語同様、タプルの最初の添え字は0です。 + + #### 配列 + + + + + *配列*によっても、複数の値のコレクションを得ることができます。タプルと異なり、配列の全要素は、 同じ型でなければなりません。Rustの配列は、他の言語と異なっている場合があります。Rustの配列は、 固定長なのです: 一度定義されたら、サイズを伸ばすことも縮めることもできません。 + + + Rustでは、配列に入れる要素は、角かっこ内にカンマ区切りリストとして記述します: + + ファイル名: src/main.rs ```rust @@ -259,25 +484,45 @@ fn main() { } ``` + + + + + + + + 配列は、ヒープよりもスタック(スタックとヒープについては第4章で詳らかに議論します)にデータのメモリを確保したい時、 または、常に固定長の要素があることを確認したい時に便利です。ただ、配列は、ベクタ型ほどは柔軟ではありません。 ベクタ型も、標準ライブラリによって提供されている似たようなコレクション型で、こちらは、 サイズを伸縮させることが*できます*。配列とベクタ型、どちらを使うべきか確信が持てない時は、 おそらくベクタ型を使うべきです: 第8章でベクタ型について詳細に議論します。 + + + + + ベクタ型よりも配列を使いたくなる例は、1年の月の名前を扱うプログラムです。そのようなプログラムで、 -月を追加したり削除したりすることはほぼ稀なので、配列を使用できます。常に12個要素があることも自明ですしね: +月を追加したり削除したりすることはほぼ稀なので、配列を使用できます。常に12個要素があることもわかってますしね: ```rust let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; ``` + + ##### 配列の要素にアクセスする + + + 配列は、スタック上に確保される一塊のメモリです。添え字によって配列の 要素にアクセスすることができます。こんな感じ: + + ファイル名: src/main.rs ```rust @@ -289,14 +534,25 @@ fn main() { } ``` + + + + この例では、`first`という名前の変数には`1`という値が格納されます。配列の`[0]`番目にある値が それだからですね。`second`という名前の変数には、配列の`[1]`番目の値`2`が格納されます。 + + ##### 配列要素への無効なアクセス -配列の終端を越えて要素にアクセスしようとしたら、どうなるだろうか?先ほどの例を以下のように + + + +配列の終端を越えて要素にアクセスしようとしたら、どうなるでしょうか?先ほどの例を以下のように 変えたとしよう: + + ファイル名: src/main.rs ```rust,ignore @@ -310,6 +566,8 @@ fn main() { } ``` + + このコードを`cargo run`で走らせると、以下のような結果になります: ```text @@ -323,11 +581,23 @@ thread '
' panicked at 'index out of bounds: the len is 5 but the index is note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` + + + + + + コンパイルでは何もエラーが出なかったものの、プログラムは*実行時*エラーに陥り、 正常終了しませんでした。要素に添え字アクセスを試みると、言語は、指定されたその添え字が 配列長よりも小さいかをチェックしてくれます。添え字が配列長よりも大きければ、言語は*パニック*します。 パニックとは、プログラムがエラーで終了したことを表すRust用語です。 + + + + + + これは、実際に稼働しているRustの安全機構の最初の例になります。低レベル言語の多くでは、 この種のチェックは行われないため、間違った添え字を与えると、無効なメモリにアクセスできてしまいます。 Rustでは、メモリアクセスを許可し、処理を継続する代わりに即座にプログラムを終了することで diff --git a/second-edition/src/ch03-03-how-functions-work.md b/second-edition/src/ch03-03-how-functions-work.md index b04ec15fe..88181e9e8 100644 --- a/second-edition/src/ch03-03-how-functions-work.md +++ b/second-edition/src/ch03-03-how-functions-work.md @@ -1,13 +1,26 @@ + + ## 関数の動作方法 + + + + + 関数は、Rustのコードにおいてよく見かける存在です。すでに、言語において最も重要な関数のうちの 一つを目撃していますね: そう、`main`関数で、これは、多くのプログラムのエントリーポイントになります。 `fn`キーワードもすでに見かけましたね。これによって新しい関数を定義することができます。 + + + + Rustの関数と変数の命名規則は、*スネークケース*(`脚注`: some_variableのような命名規則)です。 スネークケースとは、全文字を小文字にし、単語区切りにアンダースコアを使うことです。 以下のプログラムで、サンプルの関数定義をご覧ください: + + ファイル名: src/main.rs ```rust @@ -22,15 +35,30 @@ fn another_function() { } ``` + + + + Rustにおいて関数定義は、`fn`キーワードで始まり、関数名の後に丸かっこの組が続きます。 波かっこの位置が、コンパイラが関数本体の位置と判断する場所です。 + + + + + + + 定義した関数は、名前に丸かっこの組を続けることで呼び出すことができます。`another_function`関数が プログラム内で定義されているので、`main`関数内から呼び出すことができるわけです。ソースコード中で `another_function`を`main`関数の*後*に定義していることに注目してください; 勿論、main関数の前に 定義することもできます。コンパイラは、関数がどこで定義されているかは気にしません。 どこかで定義されていることのみ気にします。 + + + + *functions*という名前の新しいバイナリ生成プロジェクトを始めて、関数についてさらに深く探知していきましょう。 `another_function`の例を*src/main.rs*ファイルに配置して、走らせてください。 以下のような出力が得られるはずです: @@ -43,19 +71,38 @@ Hello, world! Another function. ``` + + + + 行出力は、`main`関数内に書かれた順序で実行されています。最初に、"Hello, world"メッセージが出、 それから`another_function`が呼ばれて、こちらのメッセージが出力されています。 + + ### 関数の引数 + + + + + + + + 関数は、引数を持つようにも定義できます。引数とは、関数シグニチャの一部になる特別な変数のことです。 関数に引数があると、引数の位置に実際の値を与えることができます。技術的にはこの実際の値は *実引数*と呼ばれますが、普段の会話では、仮引数("parameter")と実引数("argument")を 関数定義の変数と関数呼び出し時に渡す実際の値、両方の意味に区別なく使います(`脚注`: 日本語では、 どちらも単に引数と呼ぶことが多いでしょう)。 + + + 以下の書き直した`another_function`では、Rustのパラメータがどんな見た目なのかを示しています: + + ファイル名: src/main.rs ```rust @@ -68,6 +115,8 @@ fn another_function(x: i32) { } ``` + + このプログラムを走らせてみてください; 以下のような出力が得られるはずです: ```text @@ -77,17 +126,32 @@ $ cargo run The value of x is: 5 ``` -`another_function`の定義には、`x`という名前の仮引数があります。`x`の型は、`i32`と + + + + + +`another_function`の宣言には、`x`という名前の仮引数があります。`x`の型は、`i32`と 指定されています。値`5`が`another_function`に渡されると、`println!`マクロにより、 フォーマット文字列中の1組の波かっこがある位置に値`5`が出力されます。 + + + + + 関数シグニチャにおいて、各仮引数の型を宣言しなければなりません。これは、Rustの設計において、 意図的な判断です: 関数定義で型注釈が必要不可欠ということは、コンパイラがその意図するところを 推し量るのに、コードの他の箇所で使用する必要がないということを意味します。 + + + 関数に複数の仮引数をもたせたいときは、仮引数定義をカンマで区切ってください。 こんな感じです: + + ファイル名: src/main.rs ```rust @@ -101,10 +165,19 @@ fn another_function(x: i32, y: i32) { } ``` + + + + + この例では、2引数の関数を生成しています。そして、引数はどちらも`i32`型です。この関数は、 仮引数の値を両方出力します。関数引数は、全てが同じ型である必要はありません。今回は、 偶然同じになっただけです。 + + + + このコードを走らせてみましょう。今、*function*プロジェクトの*src/main.rs*ファイルに記載されている プログラムを先ほどの例と置き換えて、`cargo run`で走らせてください: @@ -116,24 +189,48 @@ The value of x is: 5 The value of y is: 6 ``` + + + `x`に対して値`5`、`y`に対して値`6`を渡して関数を呼び出したので、この二つの文字列は、 この値で出力されました。 + + ### 関数本体 + + + + + + + + 関数本体は、文が並び、最後に式を置くか文を置くという形で形成されます。現在までには、式で終わらない 関数だけを見てきたわけですが、式が文の一部になっているものなら見かけましたね。Rustは、式志向言語なので、 これは理解しておくべき重要な差異になります。他の言語にこの差異はありませんので、文と式がなんなのかと、 その違いが関数本体にどんな影響を与えるかを見ていきましょう。 + + ### 文と式 + + + + 実のところ、もう文と式は使っています。*文*とは、なんらかの動作をして値を返さない命令です。 *式*は結果値に評価されます。ちょっと例を眺めてみましょう。 + + + `let`キーワードを使用して変数を生成し、値を代入することは文になります。 リスト3-3で`let y = 6;`は文です: + + ファイル名: src/main.rs ```rust @@ -142,13 +239,23 @@ fn main() { } ``` + + リスト3-3: 1文を含む`main`関数宣言 + + + 関数定義も文になります。つまり、先の例は全体としても文になるわけです。 + + + 文は値を返しません。故に、`let`文を他の変数に代入することはできません。 以下のコードでは試みてますけどね: + + ファイル名: src/main.rs ```rust,ignore @@ -157,6 +264,8 @@ fn main() { } ``` + + このプログラムを実行すると、以下のようなエラーが出るでしょう: ```text @@ -173,16 +282,32 @@ error: expected expression, found statement (`let`) (注釈: `let`を使う変数宣言は、文です) ``` + + + + + + この`let y = 6`という文は値を返さないので、`x`を束縛する相手がないわけです。これは、 CやRubyなどの言語とは異なる動作です。CやRubyでは、代入は代入値を返します。これらの言語では、 `x = y = 6`と書いて、`x`も`y`も値6になるようにできるのですが、Rustにおいては、 そうは問屋が卸さないわけです。 + + + + + + + + 式は何かに評価され、これからあなたが書くRustコードの多くを構成します。簡単な数学演算(`5 + 6`など)を 思い浮かべましょう。この例は、値`11`に評価される式です。式は文の一部になりえます: `let y = 6`という 文を含むリスト3-3では、`6`は値`6`に評価される式です。関数呼び出しも式です。マクロ呼び出しも式です。 新しいスコープを作る際に使用するブロック(`{}`)も式です: + + ファイル名: src/main.rs ```rust @@ -198,6 +323,8 @@ fn main() { } ``` + + この式は: ```rust,ignore @@ -207,17 +334,34 @@ fn main() { } ``` + + + + + + + 今回の場合、`4`に評価されるブロックです。その値が、`let`文の一部として`y`に束縛されます。 今まで見かけてきた行と異なり、セミコロンがついていない行に気をつけてください。式に終端のセミコロンは、 含みません。式の終端にセミコロンを付けたら、文に変えてしまいます。そして、文は値を返しません。 次に関数の戻り値や式を見ていく際にこのことを肝に命じておいてください。 + + ### 戻り値のある関数 + + + + + + 関数は、それを呼び出したコードに値を返すことができます。戻り値に名前付けはできませんが、 矢印(`->`)の後に型を書いて宣言します。Rustでは、関数の戻り値は、関数本体ブロックの最後の式の値と 同義です。こちらが、値を返す関数の例です: + + ファイル名: src/main.rs ```rust @@ -232,6 +376,11 @@ fn main() { } ``` + + + + + `five`関数内には、関数呼び出しもマクロ呼び出しも、`let`文でさえ存在しません。数字の5が単独であるだけです。 これは、Rustにおいて、完璧に問題ない関数です。関数の戻り値型が`-> i32`と指定されていることにも注目してください。 このコードを実行してみましょう; 出力はこんな感じになるはずです: @@ -243,6 +392,12 @@ $ cargo run The value of x is: 5 ``` + + + + + + `five`内の`5`が関数の戻り値です。だから、戻り値型が`i32`なのです。これについてもっと深く考察しましょう。 重要な箇所は2つあります: まず、`let x = five()`という行は、関数の戻り値を使って変数を初期化している ことを示しています。関数`five`は`5`を返すので、この行は以下のように書くのと同義です: @@ -251,9 +406,16 @@ The value of x is: 5 let x = 5; ``` + + + + + 2番目に、`five`関数は仮引数をもたず、戻り値型を定義していますが、関数本体はセミコロンなしの`5`単独です。 なぜなら、これが返したい値になる式だからです。もう一つ例を見てみましょう: + + ファイル名: src/main.rs ```rust @@ -268,9 +430,15 @@ fn plus_one(x: i32) -> i32 { } ``` + + + + このコードを走らせると、`The value of x is: 6`と出力されるでしょう。では、`x + 1`を含む行の 終端にセミコロンを付けて、式から文に変えてみたら、どうなるでしょうか? + + ファイル名: src/main.rs ```rust,ignore @@ -285,6 +453,8 @@ fn plus_one(x: i32) -> i32 { } ``` + + このコードを実行すると、以下のようにエラーが出ます: ```text @@ -309,6 +479,14 @@ help: consider removing this semicolon: | ^ ``` + + + + + + + + メインのエラーメッセージである「型が合いません」でこのコードの根本的な問題が明らかになるでしょう。 関数`plus_one`の定義では、`i32`型を返すと言っているのに、文は値に評価されないからです。このことは、 `()`、つまり空のタプルとして表現されています。それゆえに、何も戻り値がなく、これが関数定義と矛盾するので、 diff --git a/second-edition/src/ch03-04-comments.md b/second-edition/src/ch03-04-comments.md index ab0a80649..aea0d9271 100644 --- a/second-edition/src/ch03-04-comments.md +++ b/second-edition/src/ch03-04-comments.md @@ -1,15 +1,28 @@ + + ## コメント + + + + + 全プログラマは、自分のコードがわかりやすくなるよう努めますが、時として追加の説明が許されることもあります。 このような場合、プログラマは注釈または*コメント*をソースコードに残し、コメントをコンパイラは無視しますが、 ソースコードを読む人間には便利なものと思えるでしょう。 + + こちらが単純なコメントです: ```rust // Hello, world. ``` + + + + Rustでは、コメントは2連スラッシュで始め、行の終わりまで続きます。コメントが複数行にまたがる場合、 各行に`//`を含める必要があります。こんな感じに: @@ -21,6 +34,8 @@ Rustでは、コメントは2連スラッシュで始め、行の終わりまで // ふう!願わくば、このコメントで何が起きているか説明されていると嬉しい。 ``` + + コメントは、コードが書かれた行の末尾にも配置することができます: Filename: src/main.rs @@ -31,6 +46,9 @@ fn main() { } ``` + + + しかし、こちらの形式のコメントの方が見かける機会は多いでしょう。注釈しようとしているコードの1行上に書く形式です: ファイル名: src/main.rs @@ -43,4 +61,6 @@ fn main() { } ``` + + コメントについては以上。特に複雑ではなかったでしょ。 diff --git a/second-edition/src/ch03-05-control-flow.md b/second-edition/src/ch03-05-control-flow.md index d9e472f91..c3d2b3b8c 100644 --- a/second-edition/src/ch03-05-control-flow.md +++ b/second-edition/src/ch03-05-control-flow.md @@ -1,17 +1,36 @@ + + ## フロー制御 + + + + + + 条件が真かどうかによってコードを走らせるかどうかを決定したり、条件が真の間繰り返しコードを走らせるか 決定したりすることは、多くのプログラミング言語において、基本的な構成ブロックです。Rustコードの 実行フローを制御する最も一般的な文法要素は、`if`式とループです。 + + ### `if`式 + + + + if式によって、条件に依存して枝分かれをさせることができます。条件を与え、以下のように宣言します。 「もし条件が合ったら、この一連のコードを実行しろ。条件に合わなければ、この一連のコードは実行するな」と。 + + + *projects*ディレクトリに*branches*という名のプロジェクトを作って`if`式について掘り下げていきましょう。 *src/main.rs*ファイルに、以下のように入力してください: + + ファイル名: src/main.rs ```rust @@ -28,6 +47,19 @@ fn main() { + + + + + + + + + + + + + `if`式は全て、キーワードの`if`から始め、条件式を続けます。今回の場合、条件式は変数`number`が 5未満の値になっているかどうかをチェックします。条件が真の時に実行したい一連のコードを条件式の直後に 波かっこで包んで配置します。`if`式の条件式と紐付けられる一連のコードは、時として*アーム*と呼ばれることがあります。 @@ -36,6 +68,8 @@ fn main() { 実行するコードを与えられることになります。仮に、`else`式を与えずに条件式が偽になったら、プログラムは単に `if`ブロックを無視して次のコードを実行しにいきます。 + + このコードを走らせてみましょう; 以下のような出力を目の当たりにするはずです: ```text @@ -45,12 +79,17 @@ $ cargo run condition was true ``` + + + `number`の値を条件が`false`になるような値に変更してどうなるか確かめてみましょう: ```rust,ignore let number = 7; ``` + + 再度プログラムを実行して、出力に注目してください: ```text @@ -60,9 +99,15 @@ $ cargo run condition was false ``` + + + + このコード内の条件式は、`bool`型で*なければならない*ことにも触れる価値があります。条件式が、 `bool`型でない時に何が起こるかを確かめるために、以下のコードを走らせてみましょう: + + ファイル名: src/main.rs ```rust,ignore @@ -75,6 +120,9 @@ fn main() { } ``` + + + 今回、`if`の条件式は`3`という値に評価され、コンパイラがエラーを投げます: ```text @@ -90,11 +138,20 @@ error[E0308]: mismatched types found type `{integer}` ``` + + + + + + + このエラーは、コンパイラは`bool`型を予期していたのに、整数だったことを示唆しています。Rustでは、 論理値以外の値が、自動的に論理値に変換されることはありません。RubyやJavaScriptなどの言語とは 異なりますね。明示的に必ず`if`には条件式として、`論理値`を与えなければなりません。例えば、 数値が`0`以外の時だけ`if`のコードを走らせたいなら、以下のように`if`式を変更することができます: + + ファイル名: src/main.rs ```rust @@ -107,12 +164,21 @@ fn main() { } ``` + + このコードを実行したら、`number was something other than zero`と表示されるでしょう。 + + #### `else if`で複数の条件 + + + `if`と`else`を組み合わせて`else if`式にすることで複数の条件を持たせることもできます。例です: + + ファイル名: src/main.rs ```rust @@ -135,6 +201,9 @@ fn main() { } ``` + + + このプログラムには、通り道が4つあります。実行後、以下のような出力を目の当たりにするはずです: ```text @@ -144,19 +213,37 @@ $ cargo run number is divisible by 3 ``` + + + + + + + このプログラムを実行すると、`if`式が順番に吟味され、最初に条件が真になった本体が実行されます。 6は2で割り切れるものの、`number is devisible by 2`や`else`ブロックの`number is not divisible by 4, 3, or 2` という出力はされないことに注目してください。その原因は、言語が最初の真条件のブロックのみを実行し、 条件に合ったものが見つかったら、残りはチェックすらしないということだからです。 + + + + `else if`式を使いすぎると、コードがめちゃくちゃになってしまうので、1つ以上あるなら、 コードをリファクタリングしたくなるかもしれません。これらのケースに有用な`match`と呼ばれる 強力なRustの枝分かれ文法要素については第6章で解説します。 + + #### `let`文内で`if`式を使う + + + `if`は式なので、`let`文の右辺に持ってくることができます。例はリスト3-4の通り: + + ファイル名: src/main.rs ```rust @@ -173,8 +260,14 @@ fn main() { } ``` + + リスト3-4: `if`式の結果を変数に代入する + + + この`number`変数は、`if`式の結果に基づいた値に束縛されます。このコードを走らせてどうなるか確かめてください: ```text @@ -184,12 +277,22 @@ $ cargo run The value of number is: 5 ``` + + + + + + + + 一連のコードは、そのうちの最後の式に評価され、数値はそれ単独でも式になることを思い出してください。 今回の場合、この`if`式全体の値は、どのブロックのコードが実行されるかに基づきます。これはつまり、 `if`の各アームの結果になる可能性がある値は、同じ型でなければならないということになります; リスト3-4で、`if`アームも`else`アームも結果は、`i32`の整数でした。では、以下の例のように、 型が合わない時には、どうなるのでしょうか? + + ファイル名: src/main.rs ```rust,ignore @@ -206,6 +309,10 @@ fn main() { } ``` + + + + このコードを走らせようとすると、エラーになります。`if`と`else`アームは互換性のない値の型になり、 コンパイラがプログラム内で問題の見つかった箇所をスバリ指摘してくれます: @@ -227,6 +334,15 @@ error[E0308]: if and else have incompatible types found type `&'static str` ``` + + + + + + + + + `if`ブロックの式は整数に評価され、`else`ブロックの式は文字列に評価されます。これでは動作しません。 変数は単独の型でなければならないのです。コンパイラは、コンパイル時に`number`変数の型を確実に 把握する必要があるため、コンパイル時に`number`が使われている箇所全部で型が有効かどうか @@ -235,20 +351,39 @@ error[E0308]: if and else have incompatible types 架空の複数の型があることを追いかけなければならないのであれば、コードに対して行える保証が 少なくなってしまうでしょう。 + + ### ループでの繰り返し + + + + + 一連のコードを1回以上実行できることは、しばしば便利です。この作業用に、Rustにはいくつかの *ループ*が用意されています。ループは、本体内のコードを最後まで実行し、直後にまた最初から開始します。 ループを試してみるのに、*loops*という名の新プロジェクトを作りましょう。 + + Rustには3種類のループが存在します: `loop`と`while`と`for`です。 それぞれ試してみましょう。 + + #### `loop`でコードを繰り返す + + + `loop`キーワードを使用すると、同じコードを何回も何回も永遠に明示的にやめさせるまで実行します。 + + + 例として、*loops*ディレクトリの*src/main.rs*ファイルを以下のような感じに書き換えましょう: + + ファイル名: src/main.rs ```rust,ignore @@ -259,6 +394,10 @@ fn main() { } ``` + + + + このプログラムを実行すると、プログラムを手動で止めるまで、何度も何度も続けて`again!`と出力するでしょう。 ほとんどのターミナルでctrl-Cというショートカットが使え、永久ループに囚われてしまったプログラムを終了させられます。 試しにやってみましょう: @@ -274,25 +413,50 @@ again! ^Cagain! ``` + + + + `^C`という記号が出た場所が、ctrl-Cを押した場所です。`^C`の後には`again!`と表示されたり、 されなかったりします。ストップシグナルをコードが受け取った時にループのどこにいたかによります。 + + + + + + 幸いなことに、Rustにはループを抜け出す別のより信頼できる手段があります。ループ内に`break` キーワードを配置することでプログラムに実行を終了すべきタイミングを教えることができます。 第2章の「正しい予想をした後に終了する」節の数当てゲーム内でこれをして、ユーザが予想を的中させ、 ゲームに勝った時にプログラムを終了させたことを思い出してください。 + + #### `while`で条件付きループ + + + + + + プログラムにとってループ内で条件式を評価できると、便利なことがしばしばあります。条件が真の間、 ループが走るわけです。条件が真でなくなった時に`break`を呼び出し、ループを終了します。 このタイプのループは、`loop`、`if`、`else`、`break`を組み合わせることで実装できます; なんならプログラムで試してみるのもいいでしょう。 + + + + + しかし、このパターンは頻出するので、Rustにはそれ用の文法要素が用意されており、`while`ループと呼ばれます。 以下の例では、`while`を使用しています: プログラムは3回ループし、それぞれカウントダウンします。 そして、ループ後に別のメッセージを表示して終了します: + + ファイル名: src/main.rs ```rust @@ -310,13 +474,24 @@ fn main() { } ``` + + + + この文法要素により、`loop`、`if`、`else`、`break`を使った時に必要になるネストがなくなり、 より明確になります。条件が真の間、コードは実行されます; そうでなければ、ループを抜けます. + + #### `for`でコレクションを覗き見る + + + `while`要素を使って配列などのコレクションの要素を覗き見ることができます。例です: + + ファイル名: src/main.rs ```rust @@ -333,8 +508,16 @@ fn main() { } ``` + + + リスト3-5: `while`ループでコレクションの各要素を覗き見る + + + + + ここで、コードは配列の要素を順番にカウントアップして覗いています。番号0から始まり、 配列の最終番号に到達するまでループします(つまり、`index < 5`が真でなくなる時です)。 このコードを走らせると、配列内の全要素が出力されます: @@ -350,16 +533,30 @@ the value is: 40 the value is: 50 ``` + + + + 予想通り、配列の5つの要素が全てターミナルに出力されました。`index`変数の値はどこかで`5`という値になるものの、 配列から6番目の値を拾おうとする前にループは実行を終了します。 + + + + + しかし、このアプローチは間違いが発生しやすいです; 添え字の長さが間違っていれば、プログラムは パニックしてしまいます。また遅いです。コンパイラが実行時にループの各回ごとに境界値チェックを行う ようなコードを追加するからです。 + + + より効率的な対立案として、`for`ループを使ってコレクションの各アイテムにコードを実行することができます。 `for`ループはこんな見た目です: + + ファイル名: src/main.rs ```rust @@ -373,25 +570,51 @@ fn main() { } ``` + + + リスト3-6: `for`ループを使ってコレクションの各要素を覗き見る + + + + + このコードを走らせたら、リスト3-5と同じ出力が得られるでしょう。より重要なのは、コードの安全性を 向上させ、配列の終端を超えてアクセスしたり、終端に届く前にループを終えてアイテムを見逃してしまったりする バグの可能性を完全に排除したことです。 + + + + + 例えば、リスト3-5のコードで、`a`配列からアイテムを1つ削除したのに、条件式を`while index < 4`に するのを忘れていたら、コードはパニックします。`for`ループを使っていれば、配列の要素数を変えても、 他のコードをいじることを覚えておく必要はなくなるわけです。 + + + + + + + + `for`ループのこの安全性と簡潔性により、Rustで使用頻度の最も高いループになっています。 リスト3-5で`while`ループを使ったカウントダウンサンプルのように、一定の回数、同じコードを実行したい ような状況であっても、多くのRust市民は、`for`ループを使うでしょう。どうやってやるかといえば、 `Range`型を使うのです。Range型は、標準ライブラリで提供される片方の数字から始まって、もう片方の数字未満の 数値を順番に生成する型です。 + + + `for`ループを使い、まだ話していない別のメソッド`rev`を使って範囲を逆順にした カウントダウンはこうなります: + + ファイル名: src/main.rs ```rust @@ -403,16 +626,32 @@ fn main() { } ``` + + こちらのコードの方が少しいいでしょう? + + ## まとめ + + + + やりましたね!結構長い章でした: 変数とスカラー値、`if`式、そして、ループについて学びました! この章で議論した概念について経験を積みたいのであれば、以下のことをするプログラムを組んでみてください: + + + + + * 温度を華氏と摂氏で変換する。 * フィボナッチ数列のn番目を生成する。 * クリスマスキャロルの定番、"The Twelve Days of Christmas"の歌詞を 曲の反復性を利用して出力する。 + + + 次に進む準備ができたら、他の言語にはあまり存在*しない*Rustの概念について話しましょう: 所有権です。 diff --git a/second-edition/src/ch04-00-understanding-ownership.md b/second-edition/src/ch04-00-understanding-ownership.md index 0b132e5e3..e0fb8efd8 100644 --- a/second-edition/src/ch04-00-understanding-ownership.md +++ b/second-edition/src/ch04-00-understanding-ownership.md @@ -1,7 +1,13 @@ -# Understanding Ownership + -Ownership is Rust’s most unique feature, and it enables Rust to make memory -safety guarantees without needing a garbage collector. Therefore, it’s -important to understand how ownership works in Rust. In this chapter we’ll talk -about ownership as well as several related features: borrowing, slices, and how -Rust lays data out in memory. +# 所有権を理解する + + + + + + + +所有権はRustの最もユニークな機能であり、これのおかげでガベージコレクタなしで安全性担保を行うことができるのです。 +故に、Rustにおいて、所有権がどう動作するのかを理解するのは重要です。この章では、所有権以外にも、関連する機能を +いくつか話していきます: 借用、スライス、そして、コンパイラがデータをメモリにどう配置するかです。 diff --git a/second-edition/src/ch04-01-what-is-ownership.md b/second-edition/src/ch04-01-what-is-ownership.md index 31cf4004b..ce9a7b0ca 100644 --- a/second-edition/src/ch04-01-what-is-ownership.md +++ b/second-edition/src/ch04-01-what-is-ownership.md @@ -1,327 +1,579 @@ -## What Is Ownership? +## 所有権とは? + -Rust’s central feature is *ownership*. Although the feature is straightforward -to explain, it has deep implications for the rest of the language. + + -All programs have to manage the way they use a computer’s memory while running. -Some languages have garbage collection that constantly looks for no longer used -memory as the program runs; in other languages, the programmer must explicitly -allocate and free the memory. Rust uses a third approach: memory is managed -through a system of ownership with a set of rules that the compiler checks at -compile time. No run-time costs are incurred for any of the ownership features. +Rustの中心的な機能は、*所有権*です。機能は説明するのに実直なのですが、言語の残りの機能全てにかかるほど +深い裏の意味を含んでいるのです。 -Because ownership is a new concept for many programmers, it does take some time -to get used to. The good news is that the more experienced you become with Rust -and the rules of the ownership system, the more you’ll be able to naturally -develop code that is safe and efficient. Keep at it! + + + + + + -When you understand ownership, you’ll have a solid foundation for understanding -the features that make Rust unique. In this chapter, you’ll learn ownership by -working through some examples that focus on a very common data structure: -strings. +全てのプログラムは、実行中にコンピュータのメモリの使用方法を管理する必要があります。プログラムが動作するにつれて、 +定期的に使用されていないメモリを検索するガベージコレクションを持つ言語もありますが、他の言語では、 +プログラマが明示的にメモリを確保したり、解放したりしなければなりません。Rustでは第3の選択肢を取っています: +メモリは、コンパイラがコンパイル時にチェックする一定の規則とともに所有権システムを通じて管理されています。 +実行コストを、所有権機能に負担することはありません。 + + + + + + +所有権は多くのプログラマにとって新しい概念なので、慣れるまでに時間がかかります。Rustと +所有権システムの経験を積むにつれて、自然に安全かつ効率的なコードを構築できるようになることは、 +素晴らしいお知らせです。その調子でいきましょう! + + + + + + +所有権を理解した時、Rustを際立たせる機能の理解に対する強固な礎を得ることになるでしょう。この章では、 +非常に一般的なデータ構造に着目した例を取り扱うことで所有権を学んでいくでしょう: 文字列です。 -> ### The Stack and the Heap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +> ### スタックとヒープ > -> In many programming languages, we don’t have to think about the stack and the -> heap very often. But in a systems programming language like Rust, whether a -> value is on the stack or the heap has more of an effect on how the language -> behaves and why we have to make certain decisions. We’ll describe parts of -> ownership in relation to the stack and the heap later in this chapter, so here -> is a brief explanation in preparation. +> 多くのプログラミング言語において、スタックとヒープについて考える機会はそう多くないでしょう。 +> しかし、Rustのようなシステムプログラミング言語においては、値がスタックに載るかヒープに載るかは、 +> 言語の振る舞い方や、特定の決断を下す理由などに影響以上のものを与えるのです。 +> この章の後半でスタックとヒープを絡めて所有権について解説するので、ここでちょっと予行演習をしておきましょう。 > -> Both the stack and the heap are parts of memory that is available to your code -> to use at runtime, but they are structured in different ways. The stack stores -> values in the order it gets them and removes the values in the opposite order. -> This is referred to as *last in, first out*. Think of a stack of plates: when -> you add more plates, you put them on top of the pile, and when you need a -> plate, you take one off the top. Adding or removing plates from the middle or -> bottom wouldn’t work as well! Adding data is called *pushing onto the stack*, -> and removing data is called *popping off the stack*. +> スタックもヒープも、実行時にコードが使用できるメモリの一部になりますが、異なる手段で構成されています。 +> スタックは、得た順番に値を並べ、逆の順で値を取り除いていきます。これは、*last in, first out* +> (あえて日本語にするなら、けつ入れ頭出しといったところでしょうか)と呼ばれます。お皿の山を思い浮かべてください: +> お皿を追加する時には、山の一番上に置き、お皿が必要になったら、一番上から1枚を取り去りますよね。 +> 途中や一番下に追加したり、取り除いたりすることは同じようにはできません。データを追加することは、 +> *スタックにpushする*といい、データを取り除くことは、*スタックからpopする*と表現します(`脚注`: これらの動作に対する +> 画一的な日本語訳を見かけたことはありません)。 > -> The stack is fast because of the way it accesses the data: it never has to -> search for a place to put new data or a place to get data from because that -> place is always the top. Another property that makes the stack fast is that all -> data on the stack must take up a known, fixed size. +> データへのアクセス方法のおかげで、スタックは高速です: 新データを置いたり、データを取得する場所を +> 探す必要が絶対にないわけです。というのも、その場所は常に一番上だからですね。スタックを高速にする要素は、 +> 他にもあり、それはスタック上のデータは全て既知の固定サイズにならなければならないということです。 > -> For data with a size unknown to us at compile time or a size that might change, -> we can store data on the heap instead. The heap is less organized: when we put -> data on the heap, we ask for some amount of space. The operating system finds -> an empty spot somewhere in the heap that is big enough, marks it as being in -> use, and returns to us a pointer to that location. This process is called -> *allocating on the heap*, and sometimes we abbreviate the phrase as just -> “allocating.” Pushing values onto the stack is not considered allocating. -> Because the pointer is a known, fixed size, we can store the pointer on the -> stack, but when we want the actual data, we have to follow the pointer. +> コンパイル時にサイズがわからなかったり、サイズが可変のデータについては、代わりにヒープに格納することができます。 +> ヒープは、もっとごちゃごちゃしています: ヒープにデータを置く時、私たちは、あるサイズのスペースを求めます。 +> OSはヒープ上に十分な大きさの空の領域を見つけ、使用中にし、その場所へのポインタを返してきます。 +> この過程は、*ヒープに領域を確保する*と呼ばれ、時としてそのフレーズを単に*allocateする*などと省略したりします。 +> (`脚注`: こちらもこなれた日本語訳はないでしょう。allocateはメモリを確保すると訳したいところですが) +> スタックに値を載せることは、メモリ確保とは考えられません。ポインタは、既知の固定サイズなので、スタックに +> 保管することができますが、実データが必要になったら、ポインタを追いかける必要があります。 > -> Think of being seated at a restaurant. When you enter, you state the number of -> people in your group, and the staff finds an empty table that fits everyone and -> leads you there. If someone in your group comes late, they can ask where you’ve -> been seated to find you. +> レストランで席を確保することを考えましょう。入店したら、グループの人数を告げ、店員が全員座れる +> 空いている席を探し、そこまで誘導します。もしグループの誰かが遅れて来るのなら、着いた席の場所を訪ねて +> あなたを発見することができます。 > -> Accessing data in the heap is slower than accessing data on the stack because -> we have to follow a pointer to get there. Contemporary processors are faster if -> they jump around less in memory. Continuing the analogy, consider a server at a -> restaurant taking orders from many tables. It’s most efficient to get all the -> orders at one table before moving on to the next table. Taking an order from -> table A, then an order from table B, then one from A again, and then one from B -> again would be a much slower process. By the same token, a processor can do its -> job better if it works on data that’s close to other data (as it is on the -> stack) rather than farther away (as it can be on the heap). Allocating a large -> amount of space on the heap can also take time. +> ヒープへのデータアクセスは、スタックのデータへのアクセスよりも低速です。ポインタを追って目的の場所に +> 到達しなければならないからです。現代のプロセッサは、メモリをあちこち行き来しなければ、より速くなります。 +> 似た例えを続けましょう。レストランで多くのテーブルから注文を受ける給仕人を考えましょう。最も効率的なのは、 +> 次のテーブルに移らずに、一つのテーブルで全部の注文を受け付けてしまうことです。テーブルAで注文を受け、 +> それからテーブルBの注文、さらにまたA、それからまたBと渡り歩くのは、かなり低速な過程になってしまいます。 +> 同じ意味で、プロセッサは、データが隔離されている(ヒープではそうなっている可能性がある)よりも近くにある +> (スタックではこうなる)ほうが、仕事をうまくこなせるのです。ヒープに大きな領域を確保する行為も時間が +> かかることがあります。 > -> When our code calls a function, the values passed into the function (including, -> potentially, pointers to data on the heap) and the function’s local variables -> get pushed onto the stack. When the function is over, those values get popped -> off the stack. +> コードが関数を呼び出すと、関数に渡された値(可能性として、ヒープのデータへのポインタも含めて)と関数の +> ローカル変数がスタックに載ります。関数の実行が終了すると、それらの値はスタックから取り除かれます。 > -> Keeping track of what parts of code are using what data on the heap, minimizing -> the amount of duplicate data on the heap, and cleaning up unused data on the -> heap so we don’t run out of space are all problems that ownership addresses. -> Once you understand ownership, you won’t need to think about the stack and the -> heap very often, but knowing that managing heap data is why ownership exists -> can help explain why it works the way it does. +> どの部分のコードがどのヒープ上のデータを使用しているか把握すること、ヒープ上の重複するデータを最小化すること、 +> メモリ不足にならないようにヒープ上の未使用のデータを掃除することは全て、所有権が解決する問題です。 +> 一度所有権を理解したら、あまり頻繁にスタックとヒープに関して考える必要はなくなるでしょうが、 +> ヒープデータを管理することが所有権の存在する理由だと知っていると、所有権がありのままで動作する理由を +> 説明するのに役立つこともあります。 > -### Ownership Rules + + +### 所有権規則 + + + -First, let’s take a look at the ownership rules. Keep these rules in mind as we -work through the examples that illustrate the rules: +まず、所有権のルールについて見ていきましょう。この規則を具体化する例を +扱っていく間もこれらのルールを肝に命じておいてください: -> 1. Each value in Rust has a variable that’s called its *owner*. -> 2. There can only be one owner at a time. -> 3. When the owner goes out of scope, the value will be dropped. + + + -### Variable Scope +> 1. Rustの各値は、*所有者*と呼ばれる変数と対応している。 +> 2. いかなる時も所有者は一つである。 +> 3. 所有者がスコープから外れたら、値は破棄される。 -We’ve walked through an example of a Rust program already in Chapter 2. Now -that we’re past basic syntax, we won’t include all the `fn main() {` code in -examples, so if you’re following along, you’ll have to put the following -examples inside a `main` function manually. As a result, our examples will be a -bit more concise, letting us focus on the actual details rather than -boilerplate code. + -As a first example of ownership, we’ll look at the *scope* of some variables. A -scope is the range within a program for which an item is valid. Let’s say we -have a variable that looks like this: +### 変数スコープ + + + + + + + + +第2章で、Rustプログラムの例はすでに見ています。もう基本的な記法は通り過ぎたので、`fn main() {` +というコードはもう例に含みません。従って、例をなぞっているなら、これからの例は`main`関数に手動で +入れ込まなければいけなくなるでしょう。結果的に、例は少々簡潔になり、定型コードよりも +具体的な詳細に集中しやすくなります。 + + + + + +所有権の最初の例として、何らかの変数の*スコープ*について見ていきましょう。スコープとは、要素が有効になる +プログラム内の範囲のことです。以下のような変数があるとしましょう: ```rust let s = "hello"; ``` -The variable `s` refers to a string literal, where the value of the string is -hardcoded into the text of our program. The variable is valid from the point at -which it’s declared until the end of the current *scope*. Listing 4-1 has -comments annotating where the variable `s` is valid: + + + + + +変数`s`は、文字列リテラルを参照し、ここでは、文字列の値はプログラムのテキストとしてハードコードされています。 +この変数は、宣言された地点から、現在の*スコープ*の終わりまで有効になります。リスト4-1には、変数`s`が +有効な場所に関する注釈がコメントで付記されています: + + + + + + + + ```rust -{ // 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は有効ではない ``` -Listing 4-1: A variable and the scope in which it is -valid + + +リスト4-1: 変数と有効なスコープ + + + +言い換えると、ここまでに重要な点は二つあります: + + + + +1. `s`が*スコープに入る*と、有効になる +1. *スコープを抜ける*まで、それは続く -In other words, there are two important points in time here: + + + -1. When `s` comes *into scope*, it is valid. -1. It remains so until it goes *out of scope*. +ここで、スコープと変数が有効になる期間の関係は、他の言語に類似しています。さて、この理解のもとに、 +`String`型を導入して構築していきましょう。 -At this point, the relationship between scopes and when variables are valid is -similar to other programming languages. Now we’ll build on top of this -understanding by introducing the `String` type. + -### The `String` Type +### `String`型 -To illustrate the rules of ownership, we need a data type that is more complex -than the ones we covered in Chapter 3. All the data types we’ve looked at -previously are stored on the stack and popped off the stack when their scope is -over, but we want to look at data that is stored on the heap and explore how -Rust knows when to clean up that data. + + + + + -We’ll use `String` as the example here and concentrate on the parts of `String` -that relate to ownership. These aspects also apply to other complex data types -provided by the standard library and that you create. We’ll discuss `String` in -more depth in Chapter 8. +所有権の規則を具体化するには、第3章で解説したものよりも、より複雑なデータ型が必要になります。 +以前見たデータ型は全てスタックに保管され、スコープが終わるとスタックから取り除かれますが、 +ヒープに確保されるデータ型を観察して、コンパイラがどうそのデータを掃除すべきタイミングを把握しているか +を掘り下げていきたいです。 -We’ve already seen string literals, where a string value is hardcoded into our -program. String literals are convenient, but they aren’t always suitable for -every situation in which you want to use text. One reason is that they’re -immutable. Another is that not every string value can be known when we write -our code: for example, what if we want to take user input and store it? For -these situations, Rust has a second string type, `String`. This type is -allocated on the heap and as such is able to store an amount of text that is -unknown to us at compile time. You can create a `String` from a string literal -using the `from` function, like so: + + + + + +ここでは、例として`String`型を使用し、`String`型の所有権にまつわる部分に着目しましょう。 +また、この観点は、標準ライブラリや自分で生成する他の複雑なデータ型にも適用されます。 +`String`型については、第8章でより深く議論します。 + + + + + + + + + + + +すでに文字列リテラルは見かけましたね。文字列リテラルでは、文字列の値はプログラムにハードコードされます。 +文字列リテラルは便利ですが、テキストを使いたい場面全てに最適なわけではありません。一因は、文字列リテラルが +不変であることに起因します。別の原因は、コードを書く際に、全ての文字列値が判明するわけではないからです: +例えば、ユーザ入力を受け付け、それを保持したいとしたらどうでしょうか?このような場面用に、Rustには、 +2種類目の文字列型、`String`型があります。この型はヒープにメモリを確保するので、コンパイル時には +サイズが不明なテキストも保持することができるのです。`from`関数を使用して、文字列リテラルから +`String`型を生成できます。以下のように: ```rust let s = String::from("hello"); ``` -The double colon (`::`) is an operator that allows us to namespace this -particular `from` function under the `String` type rather than using some sort -of name like `string_from`. We’ll discuss this syntax more in the “Method -Syntax” section of Chapter 5 and when we talk about namespacing with modules in -Chapter 7. + + + + + + +この二重コロンは、`string_from`などの名前を使うのではなく、`String`型直下の`from`関数を特定する働きをする +演算子です。この記法について詳しくは、第5章の「メソッド記法」節と、第7章のモジュールを使った名前空間分け +について話をするときに議論します。 + + -This kind of string *can* be mutated: +この種の文字列は、可変化することが*できます*: + + + + + + + + ```rust 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!`と出力する ``` -So, what’s the difference here? Why can `String` be mutated but literals -cannot? The difference is how these two types deal with memory. + + + +では、ここでの違いは何でしょうか?なぜ、`String`型は可変化できるのに、リテラルはできないのでしょうか? +違いは、これら二つの型がメモリを扱う方法にあります。 + + + +### メモリと確保 + + + + + + + + +文字列リテラルの場合、中身はコンパイル時に判明しているので、テキストは最終的なバイナリファイルに直接ハードコードされます。 +その結果、文字列リテラルは、高速で効率的になるのです。しかし、これらの要素は、その不変性にのみ +端を発するものです。残念なことに、コンパイル時にサイズが不明だったり、プログラム実行に合わせてサイズが +可変なテキスト片用に一塊のメモリをバイナリに確保しておくことは不可能です。 + + + + + +`String`型では、可変かつ伸長可能なテキスト破片をサポートするために、コンパイル時には不明な量のメモリを +ヒープに確保して内容を保持します。つまり: + + + + + +1. メモリは、実行時にOSに要求される。 +2. `String`型を使用し終わったら、OSにこのメモリを変換する方法が必要である。 -### Memory and Allocation + + + -In the case of a string literal, we know the contents at compile time so the -text is hardcoded directly into the final executable, making string literals -fast and efficient. But these properties only come from its immutability. -Unfortunately, we can’t put a blob of memory into the binary for each piece of -text whose size is unknown at compile time and whose size might change while -running the program. +この最初の部分は、すでにしています: `String::from`関数を読んだら、その実装が必要なメモリを要求するのです。 +これは、プログラミング言語において、極めて普遍的です。 -With the `String` type, in order to support a mutable, growable piece of text, -we need to allocate an amount of memory on the heap, unknown at compile time, -to hold the contents. This means: + + + + + + + + + -1. The memory must be requested from the operating system at runtime. -2. We need a way of returning this memory to the operating system when we’re -done with our `String`. + -That first part is done by us: when we call `String::from`, its implementation -requests the memory it needs. This is pretty much universal in programming -languages. +しかしながら、2番目の部分は異なります。*ガベージコレクタ*(GC)付きの言語では、GCがこれ以上、 +使用されないメモリを検知して片付けるため、私たちプログラマは、そのことを考慮する必要はありません。 +GCがないなら、メモリがもう使用されないことを見計らって、明示的に返還するコードを呼び出すのは、 +プログラマの責任になります。ちょうど要求の際にしたようにですね。これを正確にすることは、歴史的にも +難しいプログラミング問題の一つであり続けています。もし、忘れていたら、メモリを無駄にします。 +タイミングが早すぎたら、無効な変数を作ってしまいます。2回解放してしまっても、バグになるわけです。 +`allocate`と`free`は1対1対応にしなければならないのです。 -However, the second part is different. In languages with a *garbage collector -(GC)*, the GC keeps track and cleans up memory that isn’t being used anymore, -and we, as the programmer, don’t need to think about it. Without a GC, it’s the -programmer’s responsibility to identify when memory is no longer being used and -call code to explicitly return it, just as we did to request it. Doing this -correctly has historically been a difficult programming problem. If we forget, -we’ll waste memory. If we do it too early, we’ll have an invalid variable. If -we do it twice, that’s a bug too. We need to pair exactly one `allocate` with -exactly one `free`. + + + -Rust takes a different path: the memory is automatically returned once the -variable that owns it goes out of scope. Here’s a version of our scope example -from Listing 4-1 using a `String` instead of a string literal: +Rustは、異なる道を歩んでいます: ひとたび、メモリを所有している変数がスコープを抜けたら、 +メモリは自動的に返還されます。こちらの例は、リスト4-1のスコープ例を文字列リテラルから +`String`型を使うものに変更したバージョンになります: + + + + + + + + + ```rust { - 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は + // もう有効ではない ``` -There is a natural point at which we can return the memory our `String` needs -to the operating system: when `s` goes out of scope. When a variable goes out -of scope, Rust calls a special function for us. This function is called `drop`, -and it’s where the author of `String` can put the code to return the memory. -Rust calls `drop` automatically at the closing `}`. + + + + + + +`String`型が必要とするメモリをOSに返還することが自然な地点があります: `s`変数がスコープを抜ける時です。 +変数がスコープを抜ける時、Rustは特別な関数を呼んでくれます。この関数は、`drop`と呼ばれ、ここに`String`型の +書き手はメモリ返還するコードを配置することができます。Rustは、閉じ`}`で自動的に`drop`関数を呼び出します。 + + + + + + +> 注釈: C++では、要素の生存期間の終了地点でリソースを解放するこのパターンを時に、*RAII*(Resource Aquisition +> Is Initialization)と呼んだりします。Rustの`drop`関数は、あなたがRAIIパターンを使ったことがあれば、 +> 馴染み深いものでしょう。 + + + + + -> Note: In C++, this pattern of deallocating resources at the end of an item's -> lifetime is sometimes called *Resource Acquisition Is Initialization (RAII)*. -> The `drop` function in Rust will be familiar to you if you’ve used RAII -> patterns. +このパターンは、Rustコードの書かれ方に甚大な衝撃をもたらします。現状は簡単そうに見えるかもしれませんが、 +ヒープ上に確保されたデータを複数の変数に使用させるようなもっと複雑な場面では、コードの振る舞いは、 +予期しないものになる可能性もあります。 -This pattern has a profound impact on the way Rust code is written. It may seem -simple right now, but the behavior of code can be unexpected in more -complicated situations when we want to have multiple variables use the data -we’ve allocated on the heap. Let’s explore some of those situations now. + -#### Ways Variables and Data Interact: Move +#### 変数とデータの相互作用法: ムーブ -Multiple variables can interact with the same data in different ways in Rust. -Let’s look at an example using an integer in Listing 4-2: + + + +Rustにおいては、複数の変数が同じデータに対して異なる手段で相互作用することができます。 +整数を使用したリスト4-2の例を見てみましょう: ```rust let x = 5; let y = x; ``` -Listing 4-2: Assigning the integer value of variable `x` -to `y` + + +リスト4-2: 変数`x`の整数値を`y`に代入する + + + + + + -We can probably guess what this is doing based on our experience with other -languages: “Bind the value `5` to `x`; then make a copy of the value in `x` and -bind it to `y`.” We now have two variables, `x` and `y`, and both equal `5`. -This is indeed what is happening because integers are simple values with a -known, fixed size, and these two `5` values are pushed onto the stack. +もしかしたら、他の言語の経験に基づいて、これが何をしているのか予想することができるでしょう: +「値`5`を`x`に束縛する; それから`x`の値をコピーして`y`に束縛する。」これで、二つの変数(`x`と +`y`)が存在し、両方、値は`5`になりました。これは確かに起こっている現象を説明しています。 +なぜなら、整数は既知の固定サイズの単純な値で、これら二つの`5`という値は、スタックに積まれるからです。 -Now let’s look at the `String` version: + + +では、`String`バージョンを見ていきましょう: ```rust let s1 = String::from("hello"); let s2 = s1; ``` -This looks very similar to the previous code, so we might assume that the way -it works would be the same: that is, the second line would make a copy of the -value in `s1` and bind it to `s2`. But this isn’t quite what happens. + + + + +このコードは先ほどのコードに酷似していますので、動作方法も同じだと思い込んでしまうかもしれません: +要するに、2行目で`s1`の値をコピーし、`s2`に束縛するということです。ところが、これは全く起こることを +言い当てていません。 -To explain this more thoroughly, let’s look at what `String` looks like under -the covers in Figure 4-3. A `String` is made up of three parts, shown on the -left: a pointer to the memory that holds the contents of the string, a length, -and a capacity. This group of data is stored on the stack. On the right is the -memory on the heap that holds the contents. + + + + + + +これをもっと徹底的に説明するために、図4-3を見て`String`型のベールを剥がしてみましょう。 +`String`型は、左側に示されているように、3つの部品でできています: 文字列の中身を保持する +メモリへのポインタと長さ、そして、許容量です。この種のデータは、スタックに保持されます。 +右側には、ヒープ上の中身を保持したメモリがあります。 String in memory -Figure 4-3: Representation in memory of a `String` -holding the value `"hello"` bound to `s1` + + +図4-3: `s1`に束縛された`"hello"`という値を保持する`String` + のメモリ上の表現 + + + + + + -The length is how much memory, in bytes, the contents of the `String` is -currently using. The capacity is the total amount of memory, in bytes, that the -`String` has received from the operating system. The difference between length -and capacity matters, but not in this context, so for now, it’s fine to ignore -the capacity. +長さは、`String`型の中身が現在使用しているメモリ量をバイトで表したものです。許容量は、`String`型が +OSから受け取った全メモリ量をバイトで表したものです。長さと許容量の違いは問題になることですが、 +この文脈では違うので、とりあえずは、許容量を無視しても構わないでしょう。 -When we assign `s1` to `s2`, the `String` data is copied, meaning we copy the -pointer, the length, and the capacity that are on the stack. We do not copy the -data on the heap that the pointer refers to. In other words, the data -representation in memory looks like Figure 4-4. + + + + + +`s1`を`s2`に代入すると、`String`型のデータがコピーされます。つまり、スタックにあるポインタ、長さ、許容量を +コピーするということです。ポインタが指すヒープ上のデータはコピーしません。言い換えると、メモリ上のデータ表現は +図4-4のようになるということです。 s1 and s2 pointing to the same value -Figure 4-4: Representation in memory of the variable `s2` -that has a copy of the pointer, length, and capacity of `s1` + + +図4-4: `s1`のポインタ、長さ、許容量のコピーを保持する変数`s2`の + メモリ上での表現 + + + + + -The representation does *not* look like Figure 4-5, which is what memory would -look like if Rust instead copied the heap data as well. If Rust did this, the -operation `s2 = s1` could potentially be very expensive in terms of runtime -performance if the data on the heap was large. +メモリ上の表現は、図4-5のようにはなり*ません*。これは、Rustが代わりにヒープデータもコピーする +という選択をしていた場合のメモリ表現ですね。Rustがこれをしていたら、ヒープ上のデータが大きい時に +`s2 = s1`という処理の実行時性能がとても悪くなっていた可能性があるでしょう。 s1 and s2 to two places -Figure 4-5: Another possibility of what `s2 = s1` might -do if Rust copied the heap data as well + -Earlier, we said that when a variable goes out of scope, Rust automatically -calls the `drop` function and cleans up the heap memory for that variable. But -Figure 4-4 shows both data pointers pointing to the same location. This is a -problem: when `s2` and `s1` go out of scope, they will both try to free the -same memory. This is known as a *double free* error and is one of the memory -safety bugs we mentioned previously. Freeing memory twice can lead to memory -corruption, which can potentially lead to security vulnerabilities. +図4-5: Rustがヒープデータもコピーしていた場合に`s2 = s1`という + 処理が行なった可能性のあること -To ensure memory safety, there’s one more detail to what happens in this -situation in Rust. Instead of trying to copy the allocated memory, Rust -considers `s1` to no longer be valid and therefore, Rust doesn’t need to free -anything when `s1` goes out of scope. Check out what happens when you try to -use `s1` after `s2` is created: + + + + + + + + +先ほど、変数がスコープを抜けたら、Rustは自動的に`drop`関数を呼び出し、その変数が使っていた +ヒープメモリを片付けると述べました。しかし、図4-4は、両方のデータポインタが同じ場所を指していることを +示しています。これは問題です: `s2`と`s1`がスコープを抜けたら、両方とも同じメモリを解放しようとします。 +これは*二重解放*エラーとして知られ、以前触れたメモリ安全性上のバグの一つになります。 +メモリを2回解放することは、メモリの退廃につながり、さらにセキュリティ上の脆弱性を生む可能性があります。 + + + + + + + + + +メモリ安全性を保証するために、Rustにおいてこの場面で知っておきたい起こる事の詳細がもう一つあります。 +確保されたメモリをコピーしようとする代わりに、コンパイラは、`s1`が最早有効ではないと考え、故に +`s1`がスコープを抜けた際に何も解放する必要がなくなるわけです。`s2`の生成後に`s1`を使用しようとしたら、 +どうなるかを確認してみましょう: ```rust,ignore let s1 = String::from("hello"); @@ -330,49 +582,78 @@ let s2 = s1; println!("{}, world!", s1); ``` -You’ll get an error like this because Rust prevents you from using the -invalidated reference: + + + +コンパイラが無効化された参照は使用させてくれないので、以下のようなエラーが出るでしょう: ```text error[E0382]: use of moved value: `s1` + (ムーブされた値の使用: `s1`) --> src/main.rs:4:27 | 3 | let s2 = s1; | -- value moved here 4 | 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`トレイトを実装していない型だからです) ``` -If you’ve heard the terms “shallow copy” and “deep copy” while working with -other languages, the concept of copying the pointer, length, and capacity -without copying the data probably sounds like a shallow copy. But because Rust -also invalidates the first variable, instead of calling this a shallow copy, -it’s known as a *move*. Here we would read this by saying that `s1` was *moved* -into `s2`. So what actually happens is shown in Figure 4-6. + + + + + + + +他の言語を触っている間に"shallow copy"と"deep copy"という用語を耳にしたことがあるなら、 +データのコピーなしにポインタと長さ、許容量をコピーするという概念は、shallow copyのように思えるかもしれません。 +ですが、コンパイラは最初の変数を無効化するので、これをshallow copyと呼ぶ代わりに、 +ムーブとして知られているわけです。ここでは、`s1`は`s2`に*ムーブ*されたと解読します。 +以上より、実際に起きることを図4-6に示してみました。 s1 moved to s2 -Figure 4-6: Representation in memory after `s1` has been -invalidated + -That solves our problem! With only `s2` valid, when it goes out of scope, it -alone will free the memory, and we’re done. +図4-6: `s1`が無効化された後のメモリ表現 -In addition, there’s a design choice that’s implied by this: Rust will never -automatically create “deep” copies of your data. Therefore, any *automatic* -copying can be assumed to be inexpensive in terms of runtime performance. + + -#### Ways Variables and Data Interact: Clone +これにて一件落着です。`s2`だけが有効なので、スコープを抜けたら、それだけがメモリを解放して、 +終わりになります。 -If we *do* want to deeply copy the heap data of the `String`, not just the -stack data, we can use a common method called `clone`. We’ll discuss method -syntax in Chapter 5, but because methods are a common feature in many -programming languages, you’ve probably seen them before. + + + -Here’s an example of the `clone` method in action: +付け加えると、これにより暗示されるデザイン上の選択があります: Rustでは、自動的にデータの"deep copy"が +行われることは絶対にないわけです。それ故に、あらゆる*自動*コピーは、実行時性能の観点で言うと、 +悪くないと考えてよいことになります。 + + + +#### 変数とデータの相互作用法: クローン + + + + + + +仮に、スタック上のデータだけでなく、本当に`String`型のヒープデータのdeep copyが必要ならば、 +`clone`と呼ばれるよくあるメソッドを使うことができます。メソッド記法については第5章で議論しますが、 +メソッドは多くのプログラミング言語に見られる機能なので、以前に見かけたこともあるんじゃないでしょうか。 + + + +こちらで、`clone`メソッドの稼働例をご覧ください: ```rust let s1 = String::from("hello"); @@ -381,17 +662,28 @@ let s2 = s1.clone(); println!("s1 = {}, s2 = {}", s1, s2); ``` -This works just fine and is how you can explicitly produce the behavior shown -in Figure 4-5, where the heap data *does* get copied. + + -When you see a call to `clone`, you know that some arbitrary code is being -executed and that code may be expensive. It’s a visual indicator that something -different is going on. +これは単純にうまく動き、図4-5で示した動作を明示的に生み出す手段です。ここでは、 +ヒープデータが*実際に*コピーされています。 -#### Stack-Only Data: Copy + + + -There’s another wrinkle we haven’t talked about yet. This code using integers, -part of which was shown earlier in Listing 4-2, works and is valid: +`clone`メソッドの呼び出しを見かけたら、何らかの任意のコードが実行され、その実行コストは高いと把握できます。 +何か違うことが起こっているなと見た目でわかるわけです。 + + + +#### スタックのみのデータ: コピー + + + + +まだ話題にしていない別のしわ(`脚注`: 「気になるもの」程度の意味と思われる)の話があります。 +この整数を使用したコードは、一部を先ほどリスト4-2で示しましたが、うまく動作し、有効です: ```rust let x = 5; @@ -400,132 +692,261 @@ let y = x; println!("x = {}, y = {}", x, y); ``` -But this code seems to contradict what we just learned: we don’t have a call to -`clone`, but `x` is still valid and wasn’t moved into `y`. - -The reason is that types like integers that have a known size at compile time -are stored entirely on the stack, so copies of the actual values are quick to -make. That means there’s no reason we would want to prevent `x` from being -valid after we create the variable `y`. In other words, there’s no difference -between deep and shallow copying here, so calling `clone` wouldn’t do anything -differently from the usual shallow copying and we can leave it out. - -Rust has a special annotation called the `Copy` trait that we can place on -types like integers that are stored on the stack (we’ll talk more about traits -in Chapter 10). If a type has the `Copy` trait, an older variable is still -usable after assignment. Rust won’t let us annotate a type with the `Copy` -trait if the type, or any of its parts, has implemented the `Drop` trait. If -the type needs something special to happen when the value goes out of scope and -we add the `Copy` annotation to that type, we’ll get a compile time error. To -learn about how to add the `Copy` annotation to your type, see Appendix C on -Derivable Traits. - -So what types are `Copy`? You can check the documentation for the given type to -be sure, but as a general rule, any group of simple scalar values can be -`Copy`, and nothing that requires allocation or is some form of resource is -`Copy`. Here are some of the types that are `Copy`: - -* All the integer types, like `u32`. -* The boolean type, `bool`, with values `true` and `false`. -* All the floating point types, like `f64`. -* Tuples, but only if they contain types that are also `Copy`. `(i32, i32)` is -`Copy`, but `(i32, String)` is not. - -### Ownership and Functions - -The semantics for passing a value to a function are similar to assigning a -value to a variable. Passing a variable to a function will move or copy, just -like assignment. Listing 4-7 has an example with some annotations showing where -variables go into and out of scope: - -Filename: src/main.rs + + + +ですが、このコードは一見、今学んだことと矛盾しているように見えます: `clone`メソッドの呼び出しが +ないのに、`x`は有効で、`y`にムーブされませんでした。 + + + + + + + + +その理由は、整数のようなコンパイル時に既知のサイズを持つ型は、スタック上にすっぽり保持されるので、 +実際の値を生成するのも高速だからです。これは、変数`y`を生成した後にも`x`を無効化したくなる +理由がないことを意味します。換言すると、ここでは、shallow copyとdeep copyの違いがないことになり、 +`clone`メソッドを呼び出しても、一般的なshallow copy以上のことをしなくなり、そのまま放置しておける +ということです。 + + + + + + + + + + + +Rustには`Copy`トレイトと呼ばれる特別な注釈があり、整数のようなスタックに保持される型に対して +配置することができます(トレイトについては第10章でもっと詳しく話します)。型が`Copy`トレイトに +適合していれば、代入後も古い変数が使用可能になります。コンパイラは、型やその一部分でも`Drop` +トレイトを実装している場合、`Copy`トレイトによる注釈をさせてくれません。型の値がスコープを外れた時に +何か特別なことを起こす必要がある場合に、`Copy`注釈を追加すると、コンパイルエラーが出ます。 +型に`Copy`注釈をつける方法について学ぶには、付録Cの継承可能トレイト(Derivable Traits)についてを +ご覧ください。 + + + + + + +では、どの型が`Copy`なのでしょうか?ある型について、ドキュメントをチェックすればいいのですが、 +一般規則として、単純なスカラー値の集合は何でも`Copy`であり、メモリ確保が必要だったり、 +何らかの携帯のリソースだったりするものは`Copy`ではありません。ここに`Copy`の型を並べておきます。 + + + + + + + +* 全部の整数型。`u32`など。 +* 論理値型、`bool`、`true`と`false`という値がある。 +* 全部の浮動小数点型、`f64`など。 +* タプル。ただ、`Copy`の型だけを含む場合。`(i32, i32)`は`Copy`だが +`(i32, String)`は違う。 + + + +### 所有権と関数 + + + + + + +意味論的に、関数に値を渡すことと、値を変数に代入することは似ています。関数に変数を渡すと、 +代入のようにムーブやコピーされます。リスト4-7は変数がスコープに入ったり、抜けたりする地点に +ついて注釈してある例です: + + + +ファイル名: src/main.rs + + + + + + + + + + + + + + + + + + + + + + + + + ```rust 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. - let x = 5; // x comes into scope. + takes_ownership(s); // sの値が関数にムーブされ... + // ... ここではもう有効ではない。 + 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 since 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がスコープを抜ける。何も特別なことはない。 ``` -Listing 4-7: Functions with ownership and scope -annotated + + +リスト4-7: 所有権とスコープが注釈された関数群 -If we tried to use `s` after the call to `takes_ownership`, Rust would throw a -compile time error. These static checks protect us from mistakes. Try adding -code to `main` that uses `s` and `x` to see where you can use them and where -the ownership rules prevent you from doing so. + + + + -### Return Values and Scope +`takes_ownership`の呼び出し後に`s`を呼び出そうとすると、コンパイラは、コンパイルエラーを投げるでしょう。 +これらの静的チェックにより、ミスを犯さないでいられます。`s`や`x`を使用するコードを`main`に追加してみて、 +どこで使えて、そして、所有権規則により、どこで使えないかを確認してください。 -Returning values can also transfer ownership. Here’s an example with similar -annotations to those in Listing 4-7: + -Filename: src/main.rs +### 戻り値とスコープ + + + + +値を返すことでも、所有権は移動します。リスト4-7と似た注釈のついた例です: + + + +ファイル名: src/main.rs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ```rust 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が返され、呼び出し元関数にムーブされる。 } ``` -The ownership of a variable follows the same pattern every time: assigning a -value to another variable moves it. When a variable that includes data on the -heap goes out of scope, the value will be cleaned up by `drop` unless the data -has been moved to be owned by another variable. + + + + + +変数の所有権は、毎回同じパターンを辿っています: 別の変数に値を代入すると、ムーブされます。 +ヒープにデータを含む変数がスコープを抜けると、データが別の変数に所有されるようムーブされていない +限り、`drop`により片付けられるでしょう。 + + + + + + + +所有権を得ては返すを全ての関数でしていたら、ちょっとめんどくさいですね。関数に値を使わせたいけど、 +所有権は保持させたくない場合はどうすればいいのでしょうか?返したいと思うかもしれない関数本体で発生した +あらゆるデータとともに再利用したかったら、渡されたものをまた返さなきゃいけないのは、 +非常に煩わしいことです。 + + + +タプルで、複数の値を返すことは可能です。このように: -Taking ownership and then returning ownership with every function is a bit -tedious. What if we want to let a function use a value but not take ownership? -It’s quite annoying that anything we pass in also needs to be passed back if we -want to use it again, in addition to any data resulting from the body of the -function that we might want to return as well. + -It’s possible to return multiple values using a tuple, like this: +ファイル名: src/main.rs -Filename: src/main.rs + + + + + + + + + + + + + + + ```rust fn main() { @@ -533,16 +954,20 @@ 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) } ``` -But this is too much ceremony and a lot of work for a concept that should be -common. Luckily for us, Rust has a feature for this concept, and it’s called -*references*. + + + + +でも、これでは、大袈裟すぎますし、ありふれているはずの概念に対して、作業量が多すぎます。私たちにとって +幸運なことにRustにはこの概念に対する機能があり、それは*参照*と呼ばれます。 From e1df3025e542329296e8c200d33986fe2e463f4e Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 15 Jul 2017 16:06:56 +0900 Subject: [PATCH 006/428] First draft of chapter 4-2 --- .../src/ch04-02-references-and-borrowing.md | 405 +++++++++++++----- 1 file changed, 288 insertions(+), 117 deletions(-) diff --git a/second-edition/src/ch04-02-references-and-borrowing.md b/second-edition/src/ch04-02-references-and-borrowing.md index d42229b64..43ccba322 100644 --- a/second-edition/src/ch04-02-references-and-borrowing.md +++ b/second-edition/src/ch04-02-references-and-borrowing.md @@ -1,15 +1,25 @@ -## References and Borrowing + -The issue with the tuple code at the end of the preceding section 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`. +## 参照と借用 -Here is how you would define and use a `calculate_length` function that has a -*reference* to an object as a parameter instead of taking ownership of the -value: + + + + -Filename: src/main.rs +前節最後のタプルコードの問題は、`String`型を呼び出し元の関数に戻さないと、`calculate_length`を呼び出した後に、 +`String`オブジェクトが使えなくなることであり、これは`String`オブジェクトが`calculate_length`にムーブされてしまうためでした。 + + + + + +ここで、値の所有権をもらう代わりに引数としてオブジェクトへの*参照*を取る`calculate_length`関数を定義し、 +使う方法を見てみましょう: + + + +ファイル名: src/main.rs ```rust fn main() { @@ -17,6 +27,7 @@ fn main() { let len = calculate_length(&s1); + // '{}'の長さは、{}です println!("The length of '{}' is {}.", s1, len); } @@ -25,19 +36,29 @@ fn calculate_length(s: &String) -> usize { } ``` -First, notice that all the tuple code in the variable declaration and the -function return value is gone. Second, note that we pass `&s1` into -`calculate_length`, and in its definition, we take `&String` rather than -`String`. + + + + -These ampersands are *references*, and they allow you to refer to some value -without taking ownership of it. Figure 4-8 shows a diagram. +まず、変数宣言と関数の戻り値にあったタプルコードは全てなくなったことに気付いてください。 +2番目に、`&s1`を`calcuate_length`に渡し、その定義では、`String`型ではなく、`&String`を受け取っていることに注目してください。 + + + + +これらのアンド記号が参照であり、これのおかげで所有権をもらうことなく値を参照することができるのです。 +図4-8はその図解です。 &String s pointing at String s1 -Figure 4-8: `&String s` pointing at `String s1` + + +図4-8: `String s1`を指す`&String` + + -Let’s take a closer look at the function call here: +ここの関数呼び出しについてついてもっと詳しく見てみましょう: ```rust # fn calculate_length(s: &String) -> usize { @@ -48,34 +69,59 @@ let s1 = String::from("hello"); let len = calculate_length(&s1); ``` -The `&s1` syntax lets us create a reference that *refers* to the value of `s1` -but does not own it. Because it does not own it, the value it points to will -not be dropped when the reference goes out of scope. + + + -Likewise, the signature of the function uses `&` to indicate that the type of -the parameter `s` is a reference. Let’s add some explanatory annotations: +この`&s1`という記法により、`s1`の値を*参照する*参照を生成することができますが、これを所有することはありません。 +所有してないということは、指している値は、参照がスコープを抜けてもドロップされないということです。 + + + + +同様に、関数のシグニチャでも、`&`を使用して引数`s`の型が参照であることを示しています。 +説明的な注釈を加えてみましょう: + + + + + + + ```rust -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はスコープ外になる。けど、参照しているものの所有権を持っているわけではないので + // 何も起こらない ``` -The scope in which the variable `s` is valid is the same as any function -parameter's scope, but we don’t drop what the reference points to when it goes -out of scope because we don’t have ownership. Functions that have references as -parameters instead of the actual values mean we won’t need to return the values -in order to give back ownership, since we never had ownership. + + + + + + +変数`s`が有効なスコープは、あらゆる関数の引数のものと同じですが、所有権はないので、`s`がスコープを抜けても、 +参照が指しているものをドロップすることはありません。実際の値の代わりに参照を引数に取る関数は、 +所有権をもらわないので、所有権を返す目的で値を返す必要はないことを意味します。 + + + + + +関数の引数に参照を取ることを*借用*と呼びます。現実生活のように、誰かが何かを所有していたら、 +それを借りることができます。用が済んだら、返さなきゃいけないわけです。 + + + -We call having references as function parameters *borrowing*. As in real life, -if a person owns something, you can borrow it from them. When you’re done, you -have to give it back. +では、借用した何かを変更しようとしたら、どうなるのでしょうか?リスト4-9のコードを試してください。 +ネタバレ注意: 動きません! -So what happens if we try to modify something we’re borrowing? Try the code in -Listing 4-9. Spoiler alert: it doesn’t work! + -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -89,26 +135,39 @@ fn change(some_string: &String) { } ``` -Listing 4-9: Attempting to modify a borrowed value + -Here’s the error: +リスト4-9: 借用した値を変更しようと試みる + + + +これがエラーです: ```text error: cannot borrow immutable borrowed content `*some_string` as mutable +(エラー: 不変な借用した中身`*some_string`を可変で借用できません) --> error.rs:8:5 | 8 | some_string.push_str(", world"); | ^^^^^^^^^^^ ``` -Just as variables are immutable by default, so are references. We’re not -allowed to modify something we have a reference to. + + + +変数が標準で不変なのと全く同様に、参照も不変なのです。参照している何かを変更することは叶わないわけです。 + + -### Mutable References +### 可変な参照 -We can fix the error in the code from Listing 4-9 with just a small tweak: + -Filename: src/main.rs +一捻り加えるだけでリスト4-9のコードのエラーは解決します: + + + +ファイル名: src/main.rs ```rust fn main() { @@ -122,15 +181,23 @@ fn change(some_string: &mut String) { } ``` -First, we had to change `s` to be `mut`. Then we had to create a mutable -reference with `&mut s` and accept a mutable reference with `some_string: &mut -String`. + + + + +始めに、`s`を`mut`に変えなければなりませんでした。そして、`&mut s`で可変な参照を生成し、 +`some_string: &mut String`で可変な参照を受け入れなければなりませんでした。 -But mutable references have one big restriction: you can only have one mutable -reference to a particular piece of data in a particular scope. This code will -fail: + + + -Filename: src/main.rs +ところが、可変な参照には大きな制約が一つあります: 特定のスコープである特定のデータに対しては、 +一つしか可変な参照を持てないことです。こちらのコードは失敗します: + + + +ファイル名: src/main.rs ```rust,ignore let mut s = String::from("hello"); @@ -139,38 +206,70 @@ let r1 = &mut s; let r2 = &mut s; ``` -Here’s the error: + + +これがエラーです: ```text error[E0499]: cannot borrow `s` as mutable more than once at a time +(エラー: 一度に`s`を可変として2回以上借用することはできません) --> borrow_twice.rs:5:19 | 4 | let r1 = &mut s; | - first mutable borrow occurs here + | (最初の可変な参照はここ) 5 | let r2 = &mut s; | ^ second mutable borrow occurs here + | (二つ目の可変な参照はここ) 6 | } | - first borrow ends here + | (最初の借用はここで終わり) ``` -This restriction allows for mutation but in a very controlled fashion. It’s -something that new Rustaceans struggle with, because most languages let you -mutate whenever you’d like. The benefit of having this restriction is that Rust -can prevent data races at compile time. + + + + + +この制約は、可変化を許可するものの、それを非常に統制の取れた形で行えます。これは、新たなRust市民にとっては、 +壁です。なぜなら、多くの言語では、いつでも好きな時に可変化できるからです。この制約がある利点は、 +コンパイラがコンパイル時にデータ競合を防ぐことができる点です。 + + + + +データ競合とは、これら3つの振る舞いが起きる特定のタイプの競合条件です: + + + + -A *data race* is a particular type of race condition in which these three -behaviors occur: +1. 2つ以上のポインタが同じデータに同時にアクセスする。 +1. 少なくとも一つのポインタがデータに書き込みを行っている。 +1. データへのアクセスを同期する機構が使用されていない。 -1. Two or more pointers access the same data at the same time. -1. At least one of the pointers is being used to write to the data. -1. There’s no mechanism being used to synchronize access to the data. + + + -Data races cause undefined behavior and can be difficult to diagnose and fix -when you’re trying to track them down at runtime; Rust prevents this problem -from happening because it won’t even compile code with data races! +データ競合は未定義の振る舞いを引き起こし、実行時に追いかけようとした時に特定し解決するのが難しい問題です。 +しかし、Rustは、データ競合が起こるコードをコンパイルさえしないので、この問題が発生しないようにしてくれるわけです。 -As always, we can use curly brackets to create a new scope, allowing for -multiple mutable references, just not *simultaneous* ones: + + + +いつものように、波かっこを使って新しいスコープを生成し、*同時並行*なものでなく、複数の可変な参照を作ることができます。 + + + + + + + + + + + ```rust let mut s = String::from("hello"); @@ -178,27 +277,40 @@ let mut s = String::from("hello"); { 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; ``` -A similar rule exists for combining mutable and immutable references. This code -results in an error: + + + +可変と不変な参照を組み合わせることに関しても、似たような規則が存在しています。このコードはエラーになります: + + + + + + + + ```rust,ignore 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; // 大問題! ``` -Here’s the error: + + +これがエラーです: ```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 @@ -210,30 +322,49 @@ immutable | - immutable borrow ends here ``` -Whew! We *also* cannot have a mutable reference while we have an immutable one. -Users of an immutable reference don’t expect the values to suddenly change out -from under them! However, multiple immutable references are okay because no one -who is just reading the data has the ability to affect anyone else’s reading of -the data. + + + + + + +ふう!*さらに*不変な参照をしている間は、可変な参照をすることはできません。不変参照の使用者は、 +それ以降に値が突然変わることなんて予想してません!しかしながら、複数の不変参照をすることは可能です。 +データを読み込んでいるだけの人に、他人がデータを読み込むことに対して影響を与える能力はないからです。 + + + + + + +これらのエラーは、時としてイライラするものではありますが、Rustコンパイラがバグの可能性を早期に指摘してくれ(それも実行時ではなくコンパイル時に)、 +時々想定通りにデータが変わらない理由を追いかけさせる代わりに、問題の発生箇所をズバリ示してくれるのだと覚えておいてください。 + + + +### 宙に浮いた参照 -Even though these errors may be frustrating at times, remember that it’s the -Rust compiler pointing out a potential bug early (at compile time rather than -at runtime) and showing you exactly where the problem is instead of you having -to track down why sometimes your data isn’t what you thought it should be. + + + + + + + -### Dangling References +ポインタのある言語では、誤ってダングリングポインタを生成してしまいやすいです。ダングリングポインタとは、 +他人に渡されてしまった可能性のあるメモリを指すポインタのことであり、その箇所へのポインタを保持している間に、 +メモリを解放してしまうことで発生します。対照的にRustでは、コンパイラが、 +参照がダングリング参照に絶対ならないよう保証しくれます:つまり、何らかのデータへの参照があったら、 +コンパイラは参照がスコープを抜けるまで、データがスコープを抜けることがないよう確認してくれるわけです。 -In languages with pointers, it’s easy to erroneously create a *dangling -pointer*, a pointer that references a location in memory that may have been -given to someone else, by freeing some memory while preserving a pointer to -that memory. In Rust, by contrast, the compiler guarantees that references will -never be dangling references: if we have a reference to some data, the compiler -will ensure that the data will not go out of scope before the reference to the -data does. + -Let’s try to create a dangling reference: +ダングリング参照作りを試してみましょう: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -247,10 +378,13 @@ fn dangle() -> &String { } ``` -Here’s the error: + + +こちらがエラーです: ```text error[E0106]: missing lifetime specifier +(エラー: ライフタイム指定子がありません) --> dangle.rs:5:16 | 5 | fn dangle() -> &String { @@ -258,40 +392,64 @@ error[E0106]: missing lifetime specifier | = 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 lifetimeを与えることを考慮してみてください) error: aborting due to previous error ``` -This error message refers to a feature we haven’t covered yet: *lifetimes*. -We’ll discuss lifetimes in detail in Chapter 10. But, if you disregard the -parts about lifetimes, the message does contain the key to why this code is a -problem: + + + + + +このエラーメッセージは、まだ解説していない機能について触れています: *ライフタイム*です。 +ライフタイムについては第10章で詳しく議論しますが、ライフタイムに関する部分を無視すれば、 +このメッセージは、このコードが問題になる理由に関する鍵を握っています。 ```text this function's return type contains a borrowed value, but there is no value for it to be borrowed from. ``` -Let’s take a closer look at exactly what’s happening at each stage of our -`dangle` code: + + + +`dangle`コードの各段階で一体何が起きているのかを詳しく見ていきましょう: + + + + + + + + + + ```rust,ignore -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はスコープを抜け、ドロップされる。そのメモリは吹き飛ばされる。 + // 危険だ ``` -Because `s` is created inside `dangle`, when the code of `dangle` is finished, -`s` will be deallocated. But we tried to return a reference to it. That means -this reference would be pointing to an invalid `String`! That’s no good. Rust -won’t let us do this. + + + + -The solution here is to return the `String` directly: +`s`は、`dangle`関数内で生成されているので、`dangle`関数のコードが終わったら、`s`は解放されてしまいますが、 +そこへの参照を返そうとしました。つまり、この参照は無効な`String`を指していると思われるのです。 +よくないことです。コンパイラは、これを阻止してくれるのです。 + + + +ここでの解決策は、`String`を直接返すことです: ```rust fn no_dangle() -> String { @@ -301,16 +459,29 @@ fn no_dangle() -> String { } ``` -This works without any problems. Ownership is moved out, and nothing is -deallocated. + + + +これは何の問題もなく動きます。所有権はムーブされ、何も解放されることはありません。 + + + +### 参照の規則 + + + +参照について議論したことを再確認しましょう: -### The Rules of References + + + + -Let’s recap what we’ve discussed about references: +1. 任意のタイミングで、以下の両方ではなくどちらかを行える: + * 一つの可変参照 + * 不変な参照いくつでも +2. 参照は常に有効でなければならない -1. At any given time, you can have *either* but not both of: - * One mutable reference. - * Any number of immutable references. -2. References must always be valid. + -Next, we’ll look at a different kind of reference: slices. +次は、違う種類の参照を見ていきましょう: スライスです。 From 8689158260974f142b2d001d2c2a87b70a25241a Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 15 Jul 2017 18:16:20 +0900 Subject: [PATCH 007/428] First draft of the chapter 4-3 --- second-edition/src/ch04-03-slices.md | 508 +++++++++++++++++++-------- 1 file changed, 361 insertions(+), 147 deletions(-) diff --git a/second-edition/src/ch04-03-slices.md b/second-edition/src/ch04-03-slices.md index b60560af7..5d75311fa 100644 --- a/second-edition/src/ch04-03-slices.md +++ b/second-edition/src/ch04-03-slices.md @@ -1,26 +1,42 @@ -## Slices + -Another data type that does not have ownership is the *slice*. Slices let you -reference a contiguous sequence of elements in a collection rather than the -whole collection. +## スライス -Here’s a small programming problem: write a function that takes a string and -returns the first word it finds in that string. If the function doesn’t find a -space in the string, it means the whole string is one word, so the entire -string should be returned. + + + -Let’s think about the signature of this function: +所有権のない別のデータ型は、*スライス*です。スライスにより、コレクション全体というより、 +その内の一連の要素を参照することができます。 + + + + + + +ここに小さなプログラミング問題があります: 文字列を受け取って、その文字列中の最初の単語を返す関数を書いてください。 +関数が文字列中に空白を見つけなかったら、文字列全体が一つの単語であることになり、文字列全体が返されるはずです。 + + + +この関数のシグニチャについて考えてみましょう: ```rust,ignore fn first_word(s: &String) -> ? ``` -This function, `first_word`, has a `&String` as a parameter. We don’t want -ownership, so this is fine. But what should we return? We don’t really have a -way to talk about *part* of a string. However, we could return the index of the -end of the word. Let’s try that as shown in Listing 4-10: + + + + -Filename: src/main.rs +この関数、`first_word`は引数に`&String`をとります。所有権はいらないので、これで十分です。 +ですが、何を返すべきでしょうか?文字列の一部について語る方法が全くありません。しかし、 +単語の終端の番号を返すことができますね。リスト4-10に示したように、その方法を試してみましょう: + + + +ファイル名: src/main.rs ```rust fn first_word(s: &String) -> usize { @@ -36,39 +52,58 @@ fn first_word(s: &String) -> usize { } ``` -Listing 4-10: The `first_word` function that returns a -byte index value into the `String` parameter + + -Let’s break down this code a bit. Because we need to go through the `String` -element by element and check whether a value is a space, we’ll convert our -`String` to an array of bytes using the `as_bytes` method: +リスト4-10: `String`引数へのバイト数で表された番号を返す`first_word`関数 + + + + + +このコードを少し噛み砕いていきましょう。`String`の値を要素ごとに見て、空白かどうかを確かめる必要があるので、 +`as_bytes`メソッドを使って、`String`オブジェクトをバイト配列に変換しました。 ```rust,ignore let bytes = s.as_bytes(); ``` -Next, we create an iterator over the array of bytes using the `iter` method : + + +次に、そのバイト配列に対して、`iter`メソッドを使用してイテレータを生成しています: ```rust,ignore for (i, &item) in bytes.iter().enumerate() { ``` -We’ll discuss iterators in more detail in Chapter 13. For now, know that `iter` -is a method that returns each element in a collection, and `enumerate` wraps -the result of `iter` and returns each element as part of a tuple instead. The -first element of the returned tuple is the index, and the second element is a -reference to the element. This is a bit more convenient than calculating the -index ourselves. + + + + + + + +イテレータについて詳しくは、第13章で議論します。今は、`iter`は、コレクション内の各要素を返す関数であること、 +`enumerate`が`iter`の結果を包んで、代わりにタプルの一部として各要素を返すことを知っておいてください。 +戻り値のタプルの第1要素は、番号であり、2番目の要素は、(コレクションの)要素への参照になります。 +これは、手動で番号を計算するよりも少しだけ便利です。 -Because the `enumerate` method returns a tuple, we can use patterns to -destructure that tuple, just like everywhere else in Rust. So in the `for` -loop, we specify a pattern that has `i` for the index in the tuple and `&item` -for the single byte in the tuple. Because we get a reference to the element -from `.iter().enumerate()`, we use `&` in the pattern. + + + + + -We search for the byte that represents the space by using the byte literal -syntax. If we find a space, we return the position. Otherwise, we return the -length of the string by using `s.len()`: +`enumerate`メソッドがタプルを返すので、Rustのあらゆる場所同様、パターンを使って、そのタプルを分解できます。 +従って、`for`ループ内で、タプルの番号に対する`i`とタプルの1バイトに対応する`&item`を含むパターンを指定しています。 +`.iter().enumerate()`から要素への参照を取得するので、パターンにも`&`を使っています。 + + + + + +バイトリテラル表記を使用して空白を表すバイトを検索しています。空白が見つかったら、その位置を返します。 +それ以外の場合、`s.len()`を使って文字列の長さを返します。 ```rust,ignore if item == b' ' { @@ -78,14 +113,46 @@ length of the string by using `s.len()`: s.len() ``` -We now have a way to find out the index of the end of the first word in the -string, but there’s a problem. We’re returning a `usize` on its own, but it’s -only a meaningful number in the context of the `&String`. In other words, -because it’s a separate value from the `String`, there’s no guarantee that it -will still be valid in the future. Consider the program in Listing 4-11 that -uses the `first_word` function from Listing 4-10: - -Filename: src/main.rs + + + + + + + +さて、文字列内の最初の単語の終端の番号を見つけ出せるようになりましたが、問題があります。 +`usize`型を単独で返していますが、これは`&String`の文脈でのみ意味を持つ数値です。 +言い換えると、`String`から切り離された値なので、将来的にも有効である保証がないのです。 +リスト4-10の`first_word`関数を使用するリスト4-11のプログラムを考えてください: + + + +ファイル名: src/main.rs + + + + + + + + + + + + + + + + + + + + + + + + + ```rust # fn first_word(s: &String) -> usize { @@ -103,42 +170,62 @@ uses the `first_word` function from Listing 4-10: fn main() { let mut s = String::from("hello world"); - let word = first_word(&s); // word will get the value 5. + let word = first_word(&s); // wordの中身は、値5になる。 - s.clear(); // This empties the String, making it equal to "". + s.clear(); // Stringを空にする。つまり、""と等しくする。 - // word still has the value 5 here, but there's no more string that - // we could meaningfully use the value 5 with. word is now totally invalid! + // wordはまだ値5を保持しているが、もうこの値を有効に使用できる文字列は存在しない。 + // wordは完全に無効なのだ! } ``` -Listing 4-11: Storing the result from calling the -`first_word` function then changing the `String` contents + + + +リスト4-11: `first_word`関数の呼び出し結果を保持し、`String`の中身を変更する + + + + + + + +このプログラムは何のエラーもなくコンパイルが通り、`word`を`s.clear()`の呼び出し後に使用しても、 +コンパイルが通ります。`word`は`s`の状態に全く関連づけられていないので、その中身はまだ値`5`のままです。 +その値`5`を変数`s`に使用し、最初の単語を取り出そうとすることはできますが、これはバグでしょう。 +というのも、`s`の中身は、`5`を`word`に保存してから変わってしまったからです。 -This program compiles without any errors and also would if we used `word` after -calling `s.clear()`. `word` isn’t connected to the state of `s` at all, so -`word` still contains the value `5`. We could use that value `5` with the -variable `s` to try to extract the first word out, but this would be a bug -because the contents of `s` have changed since we saved `5` in `word`. + + + -Having to worry about the index in `word` getting out of sync with the data in -`s` is tedious and error prone! Managing these indices is even more brittle if -we write a `second_word` function. Its signature would have to look like this: +`word`内の番号が`s`に格納されたデータと同期されなくなるのを心配することは、面倒ですし間違いになりやすいです! +これらの番号を管理するのは、`second_word`関数を書いたら、さらに脆くなります。 +そのシグニチャは以下のようにならなければおかしいです: ```rust,ignore fn second_word(s: &String) -> (usize, usize) { ``` -Now we’re tracking a start *and* an ending index, and we have even more values -that were calculated from data in a particular state but aren’t tied to that -state at all. We now have three unrelated variables floating around that need -to be kept in sync. + + + + + +今、私たちは開始*と*終端の番号を追うようになりました。特定の状態のデータから計算されたけど、 +その状態に全く紐付かない値が増えました。同期を取る必要のある宙に浮いた関連性のない変数が3つになってしまいました。 + + + +運のいいことに、Rustにはこの問題への解決策が用意されています: 文字列スライスです。 -Luckily, Rust has a solution to this problem: string slices. + -### String Slices +### 文字列スライス -A *string slice* is a reference to part of a `String`, and looks like this: + + +文字列スライスとは、`String`の一部への参照で、こんな見た目をしています: ```rust let s = String::from("hello world"); @@ -147,28 +234,45 @@ let hello = &s[0..5]; let world = &s[6..11]; ``` -This is similar to taking a reference to the whole `String` but with the extra -`[0..5]` bit. Rather than a reference to the entire `String`, it’s a reference -to a portion of the `String`. The `start..end` syntax is a range that begins at -`start` and continues up to, but not including, `end`. + + + + + +これは、`String`全体への参照を取ることに似ていますが、余計な`[0..5]`という部分が付いています。 +`String`全体への参照というよりも、`String`の一部への参照です。`開始..終点`という記法は、`開始`から始まり、 +`終端`未満までずっと続く範囲です。 + + + + + + + + + +`[starting_index..ending_index`と指定することで、角かっこに範囲を使い、スライスを生成できます。 +ここで、`starting_index`はスライスに含まれる最初の位置、`ending_index`はスライスに含まれる終端位置よりも、 +1大きくなります。内部的には、スライスデータは、開始地点とスライスの長さを保持しており、 +スライスの長さは`ending_index`から`starting_index`を引いたものに対応します。以上より、 +`let world = &s[6..11];`の場合には、`world`は`s`の6バイト目へのポインタと5という長さを保持するスライスになるでしょう。 -We can create slices using a range within brackets by specifying -`[starting_index..ending_index]`, where `starting_index` is the first position -included in the slice and `ending_index` is one more than the last position -included in the slice. Internally, the slice data structure stores the starting -position and the length of the slice, which corresponds to `ending_index` minus -`starting_index`. So in the case of `let world = &s[6..11];`, `world` would be -a slice that contains a pointer to the 6th byte of `s` and a length value of 5. + -Figure 4-12 shows this in a diagram. +図4-12は、これを図解しています。 world containing a pointer to the 6th byte of String s and a length 5 -Figure 4-12: String slice referring to part of a -`String` + + -With Rust’s `..` range syntax, if you want to start at the first index (zero), -you can drop the value before the two periods. In other words, these are equal: +`String`オブジェクトの一部を参照する文字列スライス + + + + +Rustの`..`という範囲記法で、最初の番号(ゼロ)から始めたければ、2連ピリオドの前に値を書かなければいいのです。 +換言すれば、これらは等価です: ```rust let s = String::from("hello"); @@ -177,8 +281,11 @@ let slice = &s[0..2]; let slice = &s[..2]; ``` -By the same token, if your slice includes the last byte of the `String`, you -can drop the trailing number. That means these are equal: + + + +同様の意味で、`String`の最後のバイトをスライスが含むのならば、末尾の数値を書かなければいいのです。 +つまり、これらは等価になります: ```rust let s = String::from("hello"); @@ -189,8 +296,10 @@ let slice = &s[3..len]; let slice = &s[3..]; ``` -You can also drop both values to take a slice of the entire string. So these -are equal: + + + +さらに、両方の値を省略すると、文字列全体のスライスを得られます。故に、これらは等価です: ```rust let s = String::from("hello"); @@ -201,10 +310,15 @@ let slice = &s[0..len]; let slice = &s[..]; ``` -With all this information in mind, let’s rewrite `first_word` to return a -slice. The type that signifies “string slice” is written as `&str`: + + -Filename: src/main.rs +これら全ての情報を心に留めて、`first_word`を書き直してスライスを返すようにしましょう。 +文字列スライスを意味する型は、`&str`と記述します: + + + +ファイル名: src/main.rs ```rust fn first_word(s: &String) -> &str { @@ -220,32 +334,50 @@ fn first_word(s: &String) -> &str { } ``` -We get the index for the end of the word in the same way as we did in Listing -4-10, by looking for the first occurrence of a space. When we find a space, we -return a string slice using the start of the string and the index of the space -as the starting and ending indices. + + + + + +リスト4-10で取った手段と同じ方法で単語の終端番号を取得しています。つまり、最初の空白を探すことです。 +空白を発見したら、文字列の最初と、空白の番号を開始、終了地点として使用して文字列スライスを返しています。 + + + + + +これで、`first_word`を呼び出すと、元のデータに紐付けられた単独の値を得られるようになりました。 +この値は、スライスの開始地点への参照とスライス中の要素数から構成されています。 -Now when we call `first_word`, we get back a single value that is tied to the -underlying data. The value is made up of a reference to the starting point of -the slice and the number of elements in the slice. + -Returning a slice would also work for a `second_word` function: +`second_word`関数についても、スライスを返すことでうまくいくでしょう: ```rust,ignore fn second_word(s: &String) -> &str { ``` -We now have a straightforward API that’s much harder to mess up, since the -compiler will ensure the references into the `String` remain valid. Remember -the bug in the program in Listing 4-11, when we got the index to the end of the -first word but then cleared the string so our index was invalid? That code was -logically incorrect but didn’t show any immediate errors. The problems would -show up later if we kept trying to use the first word index with an emptied -string. Slices make this bug impossible and let us know we have a problem with -our code much sooner. Using the slice version of `first_word` will throw a -compile time error: + + + + + + + + + -Filename: src/main.rs +これで、ずっと混乱しにくい素直なAPIになりました。なぜなら、`String`への参照が有効なままであることをコンパイラが、 +保証してくれるからです。最初の単語の終端番号を得た時に、 +文字列を空っぽにして先ほどの番号が無効になってしまったリスト4-11のプログラムのバグを覚えていますか? +そのコードは、論理的に正しくないのですが、即座にエラーにはなりませんでした。問題は後になってから発生し、 +それは空の文字列に対して、最初の単語の番号を使用し続けようとした時でした。スライスならこんなバグはあり得ず、 +コードに問題があるなら、もっと迅速に判明します。スライスバージョンの`first_word`を使用すると、 +コンパイルエラーが発生します: + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -257,66 +389,125 @@ fn main() { } ``` -Here’s the compiler error: + + +こちらがコンパイルエラーです: ```text 17:6 error: cannot borrow `s` as mutable because it is also borrowed as immutable [E0502] + (エラー: 不変として借用されているので、`s`を可変として借用できません) s.clear(); // Error! ^ 15:29 note: previous borrow of `s` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `s` until the borrow ends + (注釈: 前の`s`の借用はここで発生しています; 不変借用すると、借用が終わるまで、 + 他のムーブや可変借用を`s`に行うことはできません) let word = first_word(&s); ^ 18:2 note: previous borrow ends here + (注釈: 前の借用は、ここで終わっています) fn main() { } ^ ``` -Recall from the borrowing rules that if we have an immutable reference to -something, we cannot also take a mutable reference. Because `clear` needs to -truncate the `String`, it tries to take a mutable reference, which fails. Not -only has Rust made our API easier to use, but it has also eliminated an entire -class of errors at compile time! + + + + + + +借用規則から、何かへの不変な参照がある時、さらに可変な参照を得ることはできないことを思い出してください。 +`clear`が`String`を切り詰める必要があるので、可変な参照を得ようとして失敗しているわけです。 +RustのおかげでAPIが使いやすくなるだけでなく、ある種のエラー全てを完全にコンパイル時に排除してくれるのです! + + + +#### 文字列リテラルはスライスである -#### String Literals Are Slices + + -Recall that we talked about string literals being stored inside the binary. Now -that we know about slices, we can properly understand string literals: +文字列は、バイナリに埋め込まれると話したことを思い出してください。今やスライスのことを知ったので、 +文字列リテラルを正しく理解することができます。 ```rust let s = "Hello, world!"; ``` -The type of `s` here is `&str`: it’s a slice pointing to that specific point of -the binary. This is also why string literals are immutable; `&str` is an -immutable reference. + + + -#### String Slices as Parameters +ここでの`s`の型は、`&str`です: バイナリのその特定の位置を指すスライスです。 +これは、文字列が不変である理由にもなっています。要するに、`&str`は不変な参照なのです。 -Knowing that you can take slices of literals and `String`s leads us to one more -improvement on `first_word`, and that’s its signature: + + +#### 引数としての文字列スライス + + + + +リテラルや`String`のスライスを得ることができると知ると、`first_word`に対して、もう一つ改善点を見出すことができます。 +それはシグニチャです: ```rust,ignore fn first_word(s: &String) -> &str { ``` -A more experienced Rustacean would write the following line instead because it -allows us to use the same function on both `String`s and `&str`s: + + + +もっと経験を積んだRust市民なら、代わりに以下のように書くでしょう。というのも、こうすると、 +同じ関数を`String`と`&str`両方に使えるようになるからです: ```rust,ignore fn first_word(s: &str) -> &str { ``` -If we have a string slice, we can pass that directly. If we have a `String`, we -can pass a slice of the entire `String`. Defining a function to take a string -slice instead of a reference to a String makes our API more general and useful -without losing any functionality: + + + + + +もし、文字列スライスがあるなら、それを直接渡せます。`String`オブジェクトがあるなら、 +その`String`全体のスライスを渡せます。Stringへの参照の代わりに文字列リテラルを取るよう関数を定義すると、 +何も機能を失うことなくAPIをより一般的で便利なものにできるのです。 Filename: src/main.rs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ```rust # fn first_word(s: &str) -> &str { # let bytes = s.as_bytes(); @@ -332,31 +523,39 @@ without losing any functionality: fn main() { let my_string = String::from("hello world"); - // first_word works on slices of `String`s + // first_wordは`String`のスライスに対して機能する let word = first_word(&my_string[..]); let my_string_literal = "hello world"; - // first_word works on slices of string literals + // first_wordは文字列リテラルのスライスに対して機能する let word = first_word(&my_string_literal[..]); - // since string literals *are* string slices already, - // this works too, without the slice syntax! + // 文字列リテラルは、すでに文字列リテラル*なの*で、 + // こちらも、スライス記法なしで機能するのだ! let word = first_word(my_string_literal); } ``` -### Other Slices + + +### 他のスライス -String slices, as you might imagine, are specific to strings. But there’s a -more general slice type, too. Consider this array: + + + +文字列リテラルは、想像通り、文字列に特化したものです。ですが、もっと一般的なスライス型も存在します。 +この配列を考えてください: ```rust let a = [1, 2, 3, 4, 5]; ``` -Just like we might want to refer to a part of a string, we might want to refer -to part of an array and would do so like this: + + + +文字列の一部を参照したくなる可能性があるのと同様、配列の一部を参照したくなる可能性もあり、 +以下のようにすれば、参照することができます: ```rust let a = [1, 2, 3, 4, 5]; @@ -364,19 +563,34 @@ let a = [1, 2, 3, 4, 5]; let slice = &a[1..3]; ``` -This slice has the type `&[i32]`. It works the same way as string slices do, by -storing a reference to the first element and a length. You’ll use this kind of -slice for all sorts of other collections. We’ll discuss these collections in -detail when we talk about vectors in Chapter 8. + + + + + +このスライスは、`&[i32]`という型になります。これも文字列リテラルと全く同じ方法で動作しています。 +つまり、最初の要素への参照と長さを保持することです。他のすべての種類のコレクションに対して、 +この種のスライスは使用することができるでしょう。これらのコレクションについて詳しくは、 +第8章でベクタ型について話すときに議論します。 + + + +## まとめ + + + + + + -## Summary +所有権、借用、スライスの概念は、コンパイル時にRustプログラムにおいて、メモリ安全性を確保するものです。 +Rust言語も他のシステムプログラミング言語同様、メモリの使用法について制御させてくれるわけですが、 +データの所有者に所有者がスコープを抜けたときに自動的にデータを片付けさせることは、この制御を得るために、 +余計なコードを書いてデバッグする必要がないことを意味します。 -The concepts of ownership, borrowing, and slices are what ensure memory safety -in Rust programs at compile time. The Rust language gives you control over your -memory usage like other systems programming languages, but having the owner of -data automatically clean up that data when the owner goes out of scope means -you don’t have to write and debug extra code to get this control. + + + -Ownership affects how lots of other parts of Rust work, so we’ll talk about -these concepts further throughout the rest of the book. Let’s move on to the -next chapter and look at grouping pieces of data together in a `struct`. +所有権は、Rustの他のいろんな部分が動作する方法に影響を与えるので、これ以降もこれらの概念についてさらに語っていく予定です。 +次の章に移って、`struct`でデータをグループ化することについて見ていきましょう。 From 5cbc52f4a3ec56f1f7d50dda368f7caef9f2e732 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 16 Jul 2017 16:55:51 +0900 Subject: [PATCH 008/428] First drafts of the chapter 6-0 and 6-1 --- second-edition/src/ch06-00-enums.md | 44 +- .../src/ch06-01-defining-an-enum.md | 611 ++++++++++++------ 2 files changed, 436 insertions(+), 219 deletions(-) diff --git a/second-edition/src/ch06-00-enums.md b/second-edition/src/ch06-00-enums.md index f88f4ed7a..1a636114c 100644 --- a/second-edition/src/ch06-00-enums.md +++ b/second-edition/src/ch06-00-enums.md @@ -1,15 +1,29 @@ -# Enums and Pattern Matching - -In this chapter we’ll look at *enumerations*, also referred to as *enums*. -Enums allow you to define a type by enumerating its possible values. First, -we’ll define and use an enum to show how an enum can encode meaning along with -data. Next, we’ll explore a particularly useful enum, called `Option`, which -expresses that a value can be either something or nothing. Then we’ll look at -how pattern matching in the `match` expression makes it easy to run different -code for different values of an enum. Finally, we’ll cover how the `if let` -construct is another convenient and concise idiom available to you to handle -enums in your code. - -Enums are a feature in many languages, but their capabilities differ in each -language. Rust’s enums are most similar to *algebraic data types* in functional -languages like F#, OCaml, and Haskell. + + +# Enumとパターンマッチング + + + + + + + + + + + + + +この章では、*列挙型*について見ていきます。列挙型は、*enum*とも称されます。enumは、取りうる値を列挙することで、 +型を定義させてくれます。最初に、enumを定義し、使用して、enumがデータとともに意味をエンコードする方法を示します。 +次に、特別に便利なenumである`Option`について掘り下げていきましょう。この型は、 +値が何かかなんでもないかを表現します。それから、`match`式のパターンマッチングにより、 +どうenumの異なる値に対して異なるコードを走らせやすくなるかを見ます。最後に、`if let`文法要素も、 +どうenumをコードで扱う際に使用可能な便利で簡潔な慣用句であることを解説します。 + + + + + +enumは多くの言語に存在する機能ですが、その能力は言語ごとに異なります。Rustのenumは、F#、OCaml、Haskellなどの、 +関数型言語にある*数学的データ型*に非常に酷似しています。 diff --git a/second-edition/src/ch06-01-defining-an-enum.md b/second-edition/src/ch06-01-defining-an-enum.md index bd24fd6ce..a8a40067a 100644 --- a/second-edition/src/ch06-01-defining-an-enum.md +++ b/second-edition/src/ch06-01-defining-an-enum.md @@ -1,22 +1,38 @@ -## Defining an Enum - -Let’s look at a situation we might want to express in code and see why enums -are useful and more appropriate than structs in this case. Say we need to work -with IP addresses. Currently, two major standards are used for IP addresses: -version four and version six. These are the only possibilities for an IP -address that our program will come across: we can *enumerate* all possible -values, which is where enumeration gets its name. - -Any IP address can be either a version four or a version six address but not -both at the same time. That property of IP addresses makes the enum data -structure appropriate for this case, because enum values can only be one of the -variants. Both version four and version six addresses are still fundamentally -IP addresses, so they should be treated as the same type when the code is -handling situations that apply to any kind of IP address. - -We can express this concept in code by defining an `IpAddrKind` enumeration and -listing the possible kinds an IP address can be, `V4` and `V6`. These are known -as the *variants* of the enum: + + +## Enumを定義する + + + + + + + + +コードで表現したくなるかもしれない場面を見て、enumが便利でこの場合、構造体よりも適切である理由を確認しましょう。 +IPアドレスを扱う必要が出たとしましょう。現在、IPアドレスの規格は二つあります: バージョン4とバージョン6です。 +これらは、プログラムが遭遇するIPアドレスのすべての可能性です: 列挙型は、取りうる値をすべて*列挙*でき、 +これが列挙型の名前の由来です。 + + + + + + + + +どんなIPアドレスも、バージョン4かバージョン6のどちらかになりますが、同時に両方にはなり得ません。 +今回の場合、IPアドレスのその要素によりenumデータ構造が適切なものになります。というのも、 +enumの値は、そのバリアントのいずれか一つにしかなり得ないからです。バージョン4とバージョン6のアドレスは、 +どちらも根源的にはIPアドレスですから、コードがいかなる種類のIPアドレスにも適用される場面を扱う際には、 +同じ型として扱われるべきです。 + + + + + +この概念をコードでは、`IpAddrKind`列挙型を定義し、IPアドレスがなりうる種類、`V4`と`V6`を列挙することで、 +表現できます。これらは、enumの*バリアント*として知られています: ```rust enum IpAddrKind { @@ -25,11 +41,17 @@ enum IpAddrKind { } ``` -`IpAddrKind` is now a custom data type that we can use elsewhere in our code. + -### Enum Values +これで、`IpAddrKind`はコードの他の場所で使用できるカスタマイズされたデータ型になります。 -We can create instances of each of the two variants of `IpAddrKind` like this: + + +### Enumの値 + + + +以下のようにして、`IpAddrKind`の各バリアントのインスタンスは生成できます: ```rust # enum IpAddrKind { @@ -41,11 +63,16 @@ let four = IpAddrKind::V4; let six = IpAddrKind::V6; ``` -Note that the variants of the enum are namespaced under its identifier, and we -use a double colon to separate the two. The reason this is useful is that now -both values `IpAddrKind::V4` and `IpAddrKind::V6` are of the same type: -`IpAddrKind`. We can then, for instance, define a function that takes any -`IpAddrKind`: + + + + + + +enumのバリアントは、その識別子の元に名前空間わけされていることと、 +2連コロンを使ってその二つを区別していることに注意してください。 +これが便利な理由は、こうすることで、値`IpAddrKind::V4`と`IpAddrKind::V6`という値は両方とも、 +同じ型`IpAddrKind`になったことです。そうしたら、例えば、どんな`IpAddrKind`を取る関数も定義できるようになります。 ```rust # enum IpAddrKind { @@ -56,7 +83,9 @@ both values `IpAddrKind::V4` and `IpAddrKind::V6` are of the same type: fn route(ip_type: IpAddrKind) { } ``` -And we can call this function with either variant: + + +そして、この関数をどちらのバリアント対しても呼び出せます: ```rust # enum IpAddrKind { @@ -70,10 +99,14 @@ route(IpAddrKind::V4); route(IpAddrKind::V6); ``` -Using enums has even more advantages. Thinking more about our IP address type, -at the moment we don’t have a way to store the actual IP address *data*; we -only know what *kind* it is. Given that you just learned about structs in -Chapter 5, you might tackle this problem as shown in Listing 6-1: + + + + + +enumの利用には、さらなる利点さえもあります。このIPアドレス型についてもっと考えてみると、現状では、 +実際のIPアドレスの*データ*を保持する方法がありません。つまり、どんな種類であるかを知っているだけです。 +構造体について第5章で学んだばっかりとすると、この問題に対しては、リスト6-1のように対処するかもしれません。 ```rust enum IpAddrKind { @@ -97,22 +130,35 @@ let loopback = IpAddr { }; ``` -Listing 6-1: Storing the data and `IpAddrKind` variant of -an IP address using a `struct` + + + +リスト6-1: IPアドレスのデータと`IpAddrKind`のバリアントを`struct`を使って保持する + + + + + + + + + -Here, we’ve defined a struct `IpAddr` that has two fields: a `kind` field that -is of type `IpAddrKind` (the enum we defined previously) and an `address` field -of type `String`. We have two instances of this struct. The first, `home`, has -the value `IpAddrKind::V4` as its `kind` with associated address data of -`127.0.0.1`. The second instance, `loopback`, has the other variant of -`IpAddrKind` as its `kind` value, `V6`, and has address `::1` associated with -it. We’ve used a struct to bundle the `kind` and `address` values together, so -now the variant is associated with the value. +ここでは、二つのフィールドを持つ`IpAddr`という構造体を定義しています: `IpAddrKind`型(先ほど定義したenumですね)の`kind`フィールドと、 +`String`型の`address`フィールドです。この構造体のインスタンスが2つあります。最初のインスタンス、 +`home`には`kind`として`IpAddrKind::V4`があり、紐付けられたアドレスデータは`127.0.0.1`です。 +2番目のインスタンス、`loopback`には、`kind`の値として、`IpAddrKind`のもう一つのバリアント、`V6`があり、 +アドレス`::1`が紐付いています。構造体を使って`kind`と`address`値を一緒に包んだので、 +もうバリアントは値と紐付けられています。 -We can represent the same concept in a more concise way using just an enum -rather than an enum as part of a struct by putting data directly into each enum -variant. This new definition of the `IpAddr` enum says that both `V4` and `V6` -variants will have associated `String` values: + + + + + +各enumのバリアントに直接データを格納して、enumを構造体の一部というよりもenumだけを使って、 +同じ概念をもっと簡潔な方法で表現することができます。この新しい`IpAddr`の定義は、 +`V4`と`V6`バリアント両方に`String`値が紐付けられていることを述べています。 ```rust enum IpAddr { @@ -125,15 +171,22 @@ let home = IpAddr::V4(String::from("127.0.0.1")); let loopback = IpAddr::V6(String::from("::1")); ``` -We attach data to each variant of the enum directly, so there is no need for an -extra struct. + + + +enumの各バリアントにデータを直接添加できるので、余計な構造体を作る必要は全くありません。 -There’s another advantage to using an enum rather than a struct: each variant -can have different types and amounts of associated data. Version four type IP -addresses will always have four numeric components that will have values -between 0 and 255. If we wanted to store `V4` addresses as four `u8` values but -still express `V6` addresses as one `String` value, we wouldn’t be able to with -a struct. Enums handle this case with ease: + + + + + + + +構造体よりもenumを使うことには、別の利点もあります: 各バリアントに紐付けるデータの型と量は、異なってもいいのです。 +バージョン4のIPアドレスには、常に0から255の値を持つ4つの数値があります。`V4`のアドレスは、4つの`u8`型の値として、 +格納するけれども、`V6`のアドレスは引き続き、単独の`String`型の値で格納したかったとしても、構造体では不可能です。 +enumなら、こんなケースも容易に対応できます: ```rust enum IpAddr { @@ -146,24 +199,45 @@ let home = IpAddr::V4(127, 0, 0, 1); let loopback = IpAddr::V6(String::from("::1")); ``` -We’ve shown several different possibilities that we could define in our code -for storing IP addresses of the two different varieties using an enum. However, -as it turns out, wanting to store IP addresses and encode which kind they are -is so common that [the standard library has a definition we can -use!][IpAddr] Let’s look at how the standard library defines -`IpAddr`: it has the exact enum and variants that we’ve defined and used, but -it embeds the address data inside the variants in the form of two different -structs, which are defined differently for each variant: + + + + + + + + + +enumを使用して、コード内で二つの異なるバラエティを持つIPアドレスを定義するいくつかの異なる可能性を示してきました。 +しかしながら、蓋を開けてみれば、IPアドレスを格納してその種類をエンコードしたくなるということは一般的なので、 +[標準ライブラリに使用可能な定義があります!][IpAddr] 標準ライブラリでの`IpAddr`の定義のされ方を見てみましょう。 +私たちが定義し、使用したのと全く同じenumとバリアントがありますが、アドレスデータを二種の異なる構造体の形でバリアントに埋め込み、 +この構造体は各バリアント用に異なる形で定義されています。 [IpAddr]: ../../std/net/enum.IpAddr.html + + + + + + + + + + + + + + + ```rust struct Ipv4Addr { - // details elided + // 省略 } struct Ipv6Addr { - // details elided + // 省略 } enum IpAddr { @@ -172,18 +246,28 @@ enum IpAddr { } ``` -This code illustrates that you can put any kind of data inside an enum variant: -strings, numeric types, or structs, for example. You can even include another -enum! Also, standard library types are often not much more complicated than -what you might come up with. + + + + + +このコードは、enumバリアント内にいかなる種類のデータでも格納できることを描き出しています: +例を挙げれば、文字列、数値型、構造体などです。他のenumを含むことさえできます!また、 +標準ライブラリの型は、あなたが思い付いたよりも複雑ではないことがしばしばあります。 + + + + + -Note that even though the standard library contains a definition for `IpAddr`, -we can still create and use our own definition without conflict because we -haven’t brought the standard library’s definition into our scope. We’ll talk -more about importing types in Chapter 7. +標準ライブラリに`IpAddr`に対する定義は含まれるものの、標準ライブラリの定義をスコープに導入していないので、 +まだ、干渉することなく自分自身の定義を生成して使用できることに注意してください。型のインポートについては、 +第7章でもっと詳しく言及します。 -Let’s look at another example of an enum in Listing 6-2: this one has a wide -variety of types embedded in its variants: + + + +リスト6-2でenumの別の例を見てみましょう: 今回のコードは、幅広い種類の型がバリアントに埋め込まれています: ```rust enum Message { @@ -194,40 +278,70 @@ enum Message { } ``` -Listing 6-2: A `Message` enum whose variants each store -different amounts and types of values + + + +リスト6-2: バリアント各々が異なる型と量の値を格納する`Message`enum + + + +このenumには、異なる型のバリアントが4つあります: -This enum has four variants with different types: + + + + -* `Quit` has no data associated with it at all. -* `Move` includes an anonymous struct inside it. -* `Write` includes a single `String`. -* `ChangeColor` includes three `i32`s. +* `Quit`には紐付けられたデータは全くなし。 +* `Move`は、中に匿名構造体を含む。 +* `Write`は、単独の`String`オブジェクトを含む。 +* `ChangeColor`は、3つの`i32`を含む。 -Defining an enum with variants like the ones in Listing 6-2 is similar to -defining different kinds of struct definitions except the enum doesn’t use the -`struct` keyword and all the variants are grouped together under the `Message` -type. The following structs could hold the same data that the preceding enum -variants hold: + + + + + + +リスト6-2のようなバリアントを含むenumを定義することは、enumの場合、`struct`キーワードを使わず、 +全部のバリアントが`Message`型の元に分類される点を除いて、異なる種類の構造体定義を定義するのと類似しています。 + + + + + + + + + + ```rust -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); // タプル構造体 ``` -But if we used the different structs, which each have their own type, we -wouldn’t be able to as easily define a function that could take any of these -kinds of messages as we could with the `Message` enum defined in Listing 6-2, -which is a single type. + + + + + + + +ですが、異なる構造体を使っていたら、各々、それ自身の型があるので、単独の型になるリスト6-2で定義した`Message`enumでするほど、 +これらの種のメッセージいずれもとる関数を簡単に定義することはできないでしょう。 -There is one more similarity between enums and structs: just as we’re able to -define methods on structs using `impl`, we’re also able to define methods on -enums. Here’s a method named `call` that we could define on our `Message` enum: + + + + +enumと構造体にはもう1点似通っているところがあります: `impl`を使って構造体にメソッドを定義できるのと全く同様に、 +enumにもメソッドを定義することができるのです。こちらは、`Message`enum上に定義できる`call`という名前のメソッドです: ```rust # enum Message { @@ -240,6 +354,7 @@ enums. Here’s a method named `call` that we could define on our `Message` enum impl Message { fn call(&self) { // method body would be defined here + // メソッド本体はここに定義される } } @@ -247,56 +362,93 @@ let m = Message::Write(String::from("hello")); m.call(); ``` -The body of the method would use `self` to get the value that we called the -method on. In this example, we’ve created a variable `m` that has the value -`Message::Write("hello")`, and that is what `self` will be in the body of the -`call` method when `m.call()` runs. - -Let’s look at another enum in the standard library that is very common and -useful: `Option`. - -### The `Option` Enum and Its Advantages Over Null Values - -In the previous section, we looked at how the `IpAddr` enum let us use Rust’s -type system to encode more information than just the data into our program. -This section explores a case study of `Option`, which is another enum defined -by the standard library. The `Option` type is used in many places because it -encodes the very common scenario in which a value could be something or it -could be nothing. Expressing this concept in terms of the type system means the -compiler can check that you’ve handled all the cases you should be handling, -which can prevent bugs that are extremely common in other programming languages. - -Programming language design is often thought of in terms of which features you -include, but the features you exclude are important too. Rust doesn’t have the -null feature that many other languages have. *Null* is a value that means there -is no value there. In languages with null, variables can always be in one of -two states: null or not-null. - -In “Null References: The Billion Dollar Mistake,” Tony Hoare, the inventor of -null, has this to say: - -> I call it my billion-dollar mistake. At that time, I was designing the first -> comprehensive type system for references in an object-oriented language. My -> goal was to ensure that all use of references should be absolutely safe, with -> checking performed automatically by the compiler. But I couldn't resist the -> temptation to put in a null reference, simply because it was so easy to -> implement. This has led to innumerable errors, vulnerabilities, and system -> crashes, which have probably caused a billion dollars of pain and damage in -> the last forty years. - -The problem with null values is that if you try to actually use a value that’s -null as if it is a not-null value, you’ll get an error of some kind. Because -this null or not-null property is pervasive, it’s extremely easy to make this -kind of error. - -However, the concept that null is trying to express is still a useful one: a -null is a value that is currently invalid or absent for some reason. - -The problem isn’t with the actual concept but with the particular -implementation. As such, Rust does not have nulls, but it does have an enum -that can encode the concept of a value being present or absent. This enum is -`Option`, and it is [defined by the standard library][option] -as follows: + + + + + +メソッドの本体では、`self`を使用して、メソッドを呼び出した相手の値を取得できます。この例では、 +`Message::Write("hello")`という値を持つ、変数`m`を生成したので、これが`m.call()`を走らせた時に、 +`call`メソッドの本体内で`self`が表す値になります。 + + + + +非常に一般的で便利な別の標準ライブラリのenumを見てみましょう: `Option`です。 + + + +### `Option`enumとNull値に勝る利点 + + + + + + + + + + +前節で、`IpAddr`enumがRustの型システムを使用して、プログラムにデータ以上の情報をエンコードできる方法を見ました。 +この節では、`Option`のケーススタディを掘り下げていきます。この型も標準ライブラリにより定義されているenumです。 +この`Option`型はいろんな箇所で使用されます。なぜなら、値が何かかそうでないかという非常に一般的な筋書きをコード化するからです。 +この概念を型システムの観点で表現することは、コンパイラが、プログラマが処理すべき場面全てを処理していることをチェックできることを意味し、 +これにより、他の言語において、究極的にありふれたバグを阻止することができます。 + + + + + + + +プログラミング言語のデザインは、しばしばどの機能を入れるかという観点で考えられるが、 +除いた機能も重要なのです。Rustには、他の多くの言語にはあるnull機能がありません。 +*null*とはそこに何も値がないことを意味する値です。nullのある言語において、 +変数は常に二者択一どちらかの状態になります: nullかそうでないかです。 + + + + +nullの開発者であるTony Hoareの著書"Null References: The Billion Dollar Mistake"では、こんなことが語られています。 + + + + + + + + + + +> 私はそれを10億ドルの失敗と呼んでいます。その頃、私は、オブジェクト指向言語の参照に対する、 +> 最初のわかりやすい型システムをデザインしていました。私の目標は、 +> どんな参照の使用も全て完全に安全であるべきことを、コンパイラにそのチェックを自動で行ってもらって保証することだったのです。 +> しかし、null参照を入れるという誘惑に打ち勝つことができませんでした。それは、単純に実装が非常に容易だったからです。 +> これが無数のエラーや脆弱性、システムクラッシュにつながり、過去40年で10億ドルの苦痛や損害を引き起こしたであろうということなのです。 + + + + + + +null値の問題は、nullの値をnullでない値のように実際に使用しようとしたら、何らかの種類のエラーが出ることです。 +このnullかそうでないかという特性は広く存在するので、この種の間違いを大変犯しやすいのです。 + + + + +しかしながら、nullが表現しようとしている概念は、それでも便利なものです: nullは、 +何らかの理由で現在無効または存在しない値のことなのです。 + + + + + + + +問題は、実際の概念にあるのではなく、特定の実装にあるのです。そんな感じなので、Rustにはnullがありませんが、 +値が存在するか不在かという概念をコード化するenumならあります。このenumが`Option`で、 +以下のように[標準ライブラリに定義][option]されています。 [option]: ../../std/option/enum.Option.html @@ -307,17 +459,26 @@ enum Option { } ``` -The `Option` enum is so useful that it’s even included in the prelude; you -don’t need to import it explicitly. In addition, so are its variants: you can -use `Some` and `None` directly without prefixing them with `Option::`. -`Option` is still just a regular enum, and `Some(T)` and `None` are still -variants of type `Option`. + + + + + + +`Option`は便利すぎて、初期化処理(prelude)にさえ含まれています。つまり、明示的にインポートする必要がないのです。 +さらに、バリアントもそうなっています: `Some`と`None`を`Option::`と接頭辞をつけることなく直接使えるわけです。 +ただ、`Option`は普通のenumであり、`Some(T)`と`None`は`Option`型のバリアントです。 -The `` syntax is a feature of Rust we haven’t talked about yet. It’s a -generic type parameter, and we’ll cover generics in more detail in Chapter 10. -For now, all you need to know is that `` means the `Some` variant of the -`Option` enum can hold one piece of data of any type. Here are some examples of -using `Option` values to hold number types and string types: + + + + + + +``という記法は、まだ語っていないRustの機能です。これは、ジェネリック型引数であり、ジェネリクスについて詳しくは、 +第10章で解説します。とりあえず、知っておく必要があることは、``は、`Option`enumの`Some`バリアントが、 +あらゆる型のデータを1つだけ持つことができることを意味していることだけです。こちらは、 +`Option`値を使って、数値型や文字列型を保持する例です。 ```rust let some_number = Some(5); @@ -326,19 +487,30 @@ let some_string = Some("a string"); let absent_number: Option = None; ``` -If we use `None` rather than `Some`, we need to tell Rust what type of -`Option` we have, because the compiler can't infer the type that the `Some` -variant will hold by looking only at a `None` value. + + + + +`Some`ではなく、`None`を使ったら、コンパイラに`Option`の型が何になるかを教えなければいけません。 +というのも、`None`値を見ただけでは、`Some`バリアントが保持する型をコンパイラが推論できないからです。 -When we have a `Some` value, we know that a value is present, and the value is -held within the `Some`. When we have a `None` value, in some sense, it means -the same thing as null: we don’t have a valid value. So why is having -`Option` any better than having null? + + + + -In short, because `Option` and `T` (where `T` can be any type) are different -types, the compiler won’t let us use an `Option` value as if it was -definitely a valid value. For example, this code won’t compile because it’s -trying to add an `i8` to an `Option`: +`Some`値がある時、値が存在するとわかり、その値は、`Some`に保持されています。`None`値がある場合、 +ある意味、nullと同じことを意図します: 有効な値がないのです。では、なぜ`Option`の方が、 +nullよりも好ましいのでしょうか? + + + + + + +簡潔に述べると、`Option`と`T`(ここで`T`はどんな型でもいい)は異なる型なので、 +コンパイラが`Option`値を確実に有効な値かのようには使用させてくれません。 +例えば、このコードは`i8`を`Option`に足そうとしているので、コンパイルできません。 ```rust,ignore let x: i8 = 5; @@ -347,11 +519,14 @@ let y: Option = Some(5); let sum = x + y; ``` -If we run this code, we get an error message like this: + + +このコードを動かしたら、以下のようなエラーメッセージが出ます。 ```text error[E0277]: the trait bound `i8: std::ops::Add>` is not satisfied +(エラー: `i8: std::ops::Add>`というトレイト境界が満たされていません) --> | 7 | let sum = x + y; @@ -359,42 +534,70 @@ not satisfied | ``` -Intense! In effect, this error message means that Rust doesn’t understand how -to add an `Option` and an `i8`, because they’re different types. When we -have a value of a type like `i8` in Rust, the compiler will ensure that we -always have a valid value. We can proceed confidently without having to check -for null before using that value. Only when we have an `Option` (or -whatever type of value we’re working with) do we have to worry about possibly -not having a value, and the compiler will make sure we handle that case before -using the value. - -In other words, you have to convert an `Option` to a `T` before you can -perform `T` operations with it. Generally, this helps catch one of the most -common issues with null: assuming that something isn’t null when it actually -is. - -Not having to worry about missing an assumption of having a not-null value -helps you to be more confident in your code. In order to have a value that can -possibly be null, you must explicitly opt in by making the type of that value -`Option`. Then, when you use that value, you are required to explicitly -handle the case when the value is null. Everywhere that a value has a type that -isn’t an `Option`, you *can* safely assume that the value isn’t null. This -was a deliberate design decision for Rust to limit null’s pervasiveness and -increase the safety of Rust code. - -So, how do you get the `T` value out of a `Some` variant when you have a value -of type `Option` so you can use that value? The `Option` enum has a large -number of methods that are useful in a variety of situations; you can check -them out in [its documentation][docs]. Becoming familiar with -the methods on `Option` will be extremely useful in your journey with Rust. + + + + + + + + + +なんて強烈な!実際に、このエラーメッセージは、`Option`と`i8`が異なる型なので、 +足し合わせる方法がコンパイラにはわからないことを意味します。Rustにおいて、`i8`のような型の値がある場合、 +コンパイラが常に有効な値であることを確認してくれます。この値を使う前にnullであることをチェックする必要なく、 +自信を持って先に進むことができるのです。`Option`がある時(あるいはどんな型を扱おうとしていても)のみ、 +値を保持していない可能性を心配する必要はないわけであり、 +コンパイラはプログラマが値を使用する前にそのような場面を扱っているか確かめてくれます。 + + + + + + +言い換えると、`T`型の処理を行うには、`Option`を`T`に変換する必要があるわけです。一般的に、 +これにより、nullの最もありふれた問題の一つを捕捉できます: 実際にはnullなのに、 +そうでないかのように想定することです。 + + + + + + + + + + +nullでない値があるという想定を見逃す心配をしなくてもよいということは、コード内でより自信を持てることになります。 +nullになる可能性のある値を保持するには、その値の型を`Option`にすることで明示的に同意しなければなりません。 +それからその値を使用する際には、値がnullである場合を明示的に処理する必要があります。 +値が`Option`以外の型であるとこ全てにおいて、値がnullでないと安全に想定することが*できます*。 +これは、Rustにとって、意図的なデザイン決定であり、nullの普遍性を制限し、Rustコードの安全性を向上させます。 + + + + + + + +では、`Option`型の値がある時、その値を使えるようにするには、どのように`Some`バリアントから`T`型の値を取り出せばいいのでしょうか? +`Option`には様々な場面で有効に活用できる非常に多くのメソッドが用意されています; +[ドキュメント][docs]でそれらを確認できます。`Option`のメソッドに馴染むと、 +Rustの旅が極めて便利になるでしょう。 [docs]: ../../std/option/enum.Option.html -In general, in order to use an `Option` value, we want to have code that -will handle each variant. We want some code that will run only when we have a -`Some(T)` value, and this code is allowed to use the inner `T`. We want some -other code to run if we have a `None` value, and that code doesn’t have a `T` -value available. The `match` expression is a control flow construct that does -just this when used with enums: it will run different code depending on which -variant of the enum it has, and that code can use the data inside the matching -value. + + + + + + + + + +一般的に、`Option`値を使うには、各バリアントを処理するコードが欲しくなります。 +`Some(T)`値がある時だけ走る何らかのコードが欲しくなり、このコードが内部の`T`を使用できます。 +`None`値があった場合に走る別のコードが欲しくなり、そちらのコードは`T`値は使用できない状態になります。 +`match`式が、enumとともに使用した時にこれだけをするフロー制御文法要素になります: enumのバリアントによって、 +違うコードが走り、そのコードがマッチした値の中のデータを使用できるのです。 From b38f6fd4bbc333302d46b0abfe1cb83c9fe8e106 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 16 Jul 2017 16:55:51 +0900 Subject: [PATCH 009/428] First drafts of the chapter 6-0 and 6-1 --- .../src/ch02-00-guessing-game-tutorial.md | 2 +- .../src/ch03-01-variables-and-mutability.md | 8 +- second-edition/src/ch03-02-data-types.md | 2 +- second-edition/src/ch03-04-comments.md | 2 +- second-edition/src/ch03-05-control-flow.md | 4 +- second-edition/src/ch04-03-slices.md | 2 +- second-edition/src/ch06-00-enums.md | 44 +- .../src/ch06-01-defining-an-enum.md | 611 ++++++++++++------ second-edition/src/ch06-02-match.md | 426 ++++++++---- 9 files changed, 732 insertions(+), 369 deletions(-) diff --git a/second-edition/src/ch02-00-guessing-game-tutorial.md b/second-edition/src/ch02-00-guessing-game-tutorial.md index f54f0da76..52848c973 100644 --- a/second-edition/src/ch02-00-guessing-game-tutorial.md +++ b/second-edition/src/ch02-00-guessing-game-tutorial.md @@ -870,7 +870,7 @@ fn main() { -コードに追加した2行目は、秘密の数字を出力してくれます。これは、プログラムをテストする構築中には便利ですが、 +コードに追加した2行目は、秘密の数字を出力してくれます。これは、プログラムをテストする構築中には役立ちますが、 最終版からは削除する予定です。プログラムがスタートと同時に答えを出力しちゃったら、ゲームにならないからですね! diff --git a/second-edition/src/ch03-01-variables-and-mutability.md b/second-edition/src/ch03-01-variables-and-mutability.md index e6ab6bd8d..783f07510 100644 --- a/second-edition/src/ch03-01-variables-and-mutability.md +++ b/second-edition/src/ch03-01-variables-and-mutability.md @@ -100,7 +100,7 @@ Rustでは、値が不変であると宣言したら、本当に変わらない -しかし、可変性は時として非常に便利なこともあります。変数は、標準でのみ、不変です。つまり、変数名の前に +しかし、可変性は時として非常に有益なこともあります。変数は、標準でのみ、不変です。つまり、変数名の前に `mut`キーワードを付ければ、可変にできるわけです。この値が変化できるようにするとともに、未来の読者に対して コードの別の部分がこの変数の値を変えることを示すことで、その意図を汲ませることができるのです。 @@ -186,7 +186,7 @@ The value of x is: 6 定数はどんなスコープでも定義できます。グローバルスコープも含めてね。なので、いろんなところで使用される可能性のある値を -定義するのに便利です。 +定義するのに役に立ちます。 @@ -212,7 +212,7 @@ const MAX_POINTS: u32 = 100_000; 定数は、プログラムが走る期間、定義されたスコープ内でずっと有効です。従って、プログラムのいろんなところで -使用される可能性のあるアプリケーション空間の値を定義するのに便利な選択肢になります。例えば、 +使用される可能性のあるアプリケーション空間の値を定義するのに有益な選択肢になります。例えば、 ゲームでプレイヤーが取得可能なポイントの最高値や、光速度などですね。 @@ -221,7 +221,7 @@ const MAX_POINTS: u32 = 100_000; プログラム中で使用されるハードコードされた値に対して、定数として名前付けすることは、コードの将来的な -管理者にとって値の意味を汲むのに便利です。将来、ハードコードされた値を変える必要が出た時に、 +管理者にとって値の意味を汲むのに役に立ちます。将来、ハードコードされた値を変える必要が出た時に、 たった1箇所を変更するだけで済むようにもしてくれます。 diff --git a/second-edition/src/ch03-02-data-types.md b/second-edition/src/ch03-02-data-types.md index 576e2e5e4..a129c4140 100644 --- a/second-edition/src/ch03-02-data-types.md +++ b/second-edition/src/ch03-02-data-types.md @@ -493,7 +493,7 @@ fn main() { 配列は、ヒープよりもスタック(スタックとヒープについては第4章で詳らかに議論します)にデータのメモリを確保したい時、 -または、常に固定長の要素があることを確認したい時に便利です。ただ、配列は、ベクタ型ほどは柔軟ではありません。 +または、常に固定長の要素があることを確認したい時に役に立ちます。ただ、配列は、ベクタ型ほどは柔軟ではありません。 ベクタ型も、標準ライブラリによって提供されている似たようなコレクション型で、こちらは、 サイズを伸縮させることが*できます*。配列とベクタ型、どちらを使うべきか確信が持てない時は、 おそらくベクタ型を使うべきです: 第8章でベクタ型について詳細に議論します。 diff --git a/second-edition/src/ch03-04-comments.md b/second-edition/src/ch03-04-comments.md index aea0d9271..8d9383df1 100644 --- a/second-edition/src/ch03-04-comments.md +++ b/second-edition/src/ch03-04-comments.md @@ -9,7 +9,7 @@ 全プログラマは、自分のコードがわかりやすくなるよう努めますが、時として追加の説明が許されることもあります。 このような場合、プログラマは注釈または*コメント*をソースコードに残し、コメントをコンパイラは無視しますが、 -ソースコードを読む人間には便利なものと思えるでしょう。 +ソースコードを読む人間には有益なものと思えるでしょう。 diff --git a/second-edition/src/ch03-05-control-flow.md b/second-edition/src/ch03-05-control-flow.md index c3d2b3b8c..24be3717a 100644 --- a/second-edition/src/ch03-05-control-flow.md +++ b/second-edition/src/ch03-05-control-flow.md @@ -360,7 +360,7 @@ error[E0308]: if and else have incompatible types -一連のコードを1回以上実行できることは、しばしば便利です。この作業用に、Rustにはいくつかの +一連のコードを1回以上実行できることは、しばしば役に立ちます。この作業用に、Rustにはいくつかの *ループ*が用意されています。ループは、本体内のコードを最後まで実行し、直後にまた最初から開始します。 ループを試してみるのに、*loops*という名の新プロジェクトを作りましょう。 @@ -441,7 +441,7 @@ again! -プログラムにとってループ内で条件式を評価できると、便利なことがしばしばあります。条件が真の間、 +プログラムにとってループ内で条件式を評価できると、有益なことがしばしばあります。条件が真の間、 ループが走るわけです。条件が真でなくなった時に`break`を呼び出し、ループを終了します。 このタイプのループは、`loop`、`if`、`else`、`break`を組み合わせることで実装できます; なんならプログラムで試してみるのもいいでしょう。 diff --git a/second-edition/src/ch04-03-slices.md b/second-edition/src/ch04-03-slices.md index 5d75311fa..3a6327c9b 100644 --- a/second-edition/src/ch04-03-slices.md +++ b/second-edition/src/ch04-03-slices.md @@ -475,7 +475,7 @@ fn first_word(s: &str) -> &str { もし、文字列スライスがあるなら、それを直接渡せます。`String`オブジェクトがあるなら、 その`String`全体のスライスを渡せます。Stringへの参照の代わりに文字列リテラルを取るよう関数を定義すると、 -何も機能を失うことなくAPIをより一般的で便利なものにできるのです。 +何も機能を失うことなくAPIをより一般的で有益なものにできるのです。 Filename: src/main.rs diff --git a/second-edition/src/ch06-00-enums.md b/second-edition/src/ch06-00-enums.md index f88f4ed7a..3a3e6676a 100644 --- a/second-edition/src/ch06-00-enums.md +++ b/second-edition/src/ch06-00-enums.md @@ -1,15 +1,29 @@ -# Enums and Pattern Matching - -In this chapter we’ll look at *enumerations*, also referred to as *enums*. -Enums allow you to define a type by enumerating its possible values. First, -we’ll define and use an enum to show how an enum can encode meaning along with -data. Next, we’ll explore a particularly useful enum, called `Option`, which -expresses that a value can be either something or nothing. Then we’ll look at -how pattern matching in the `match` expression makes it easy to run different -code for different values of an enum. Finally, we’ll cover how the `if let` -construct is another convenient and concise idiom available to you to handle -enums in your code. - -Enums are a feature in many languages, but their capabilities differ in each -language. Rust’s enums are most similar to *algebraic data types* in functional -languages like F#, OCaml, and Haskell. + + +# Enumとパターンマッチング + + + + + + + + + + + + + +この章では、*列挙型*について見ていきます。列挙型は、*enum*とも称されます。enumは、取りうる値を列挙することで、 +型を定義させてくれます。最初に、enumを定義し、使用して、enumがデータとともに意味をエンコードする方法を示します。 +次に、特別に有効なenumである`Option`について掘り下げていきましょう。この型は、 +値が何かかなんでもないかを表現します。それから、`match`式のパターンマッチングにより、 +どうenumの異なる値に対して異なるコードを走らせやすくなるかを見ます。最後に、`if let`文法要素も、 +どうenumをコードで扱う際に使用可能な便利で簡潔な慣用句であることを解説します。 + + + + + +enumは多くの言語に存在する機能ですが、その能力は言語ごとに異なります。Rustのenumは、F#、OCaml、Haskellなどの、 +関数型言語にある*数学的データ型*に非常に酷似しています。 diff --git a/second-edition/src/ch06-01-defining-an-enum.md b/second-edition/src/ch06-01-defining-an-enum.md index bd24fd6ce..31599a8ec 100644 --- a/second-edition/src/ch06-01-defining-an-enum.md +++ b/second-edition/src/ch06-01-defining-an-enum.md @@ -1,22 +1,38 @@ -## Defining an Enum - -Let’s look at a situation we might want to express in code and see why enums -are useful and more appropriate than structs in this case. Say we need to work -with IP addresses. Currently, two major standards are used for IP addresses: -version four and version six. These are the only possibilities for an IP -address that our program will come across: we can *enumerate* all possible -values, which is where enumeration gets its name. - -Any IP address can be either a version four or a version six address but not -both at the same time. That property of IP addresses makes the enum data -structure appropriate for this case, because enum values can only be one of the -variants. Both version four and version six addresses are still fundamentally -IP addresses, so they should be treated as the same type when the code is -handling situations that apply to any kind of IP address. - -We can express this concept in code by defining an `IpAddrKind` enumeration and -listing the possible kinds an IP address can be, `V4` and `V6`. These are known -as the *variants* of the enum: + + +## Enumを定義する + + + + + + + + +コードで表現したくなるかもしれない場面を見て、enumが有効でこの場合、構造体よりも適切である理由を確認しましょう。 +IPアドレスを扱う必要が出たとしましょう。現在、IPアドレスの規格は二つあります: バージョン4とバージョン6です。 +これらは、プログラムが遭遇するIPアドレスのすべての可能性です: 列挙型は、取りうる値をすべて*列挙*でき、 +これが列挙型の名前の由来です。 + + + + + + + + +どんなIPアドレスも、バージョン4かバージョン6のどちらかになりますが、同時に両方にはなり得ません。 +今回の場合、IPアドレスのその要素によりenumデータ構造が適切なものになります。というのも、 +enumの値は、そのバリアントのいずれか一つにしかなり得ないからです。バージョン4とバージョン6のアドレスは、 +どちらも根源的にはIPアドレスですから、コードがいかなる種類のIPアドレスにも適用される場面を扱う際には、 +同じ型として扱われるべきです。 + + + + + +この概念をコードでは、`IpAddrKind`列挙型を定義し、IPアドレスがなりうる種類、`V4`と`V6`を列挙することで、 +表現できます。これらは、enumの*バリアント*として知られています: ```rust enum IpAddrKind { @@ -25,11 +41,17 @@ enum IpAddrKind { } ``` -`IpAddrKind` is now a custom data type that we can use elsewhere in our code. + -### Enum Values +これで、`IpAddrKind`はコードの他の場所で使用できるカスタマイズされたデータ型になります。 -We can create instances of each of the two variants of `IpAddrKind` like this: + + +### Enumの値 + + + +以下のようにして、`IpAddrKind`の各バリアントのインスタンスは生成できます: ```rust # enum IpAddrKind { @@ -41,11 +63,16 @@ let four = IpAddrKind::V4; let six = IpAddrKind::V6; ``` -Note that the variants of the enum are namespaced under its identifier, and we -use a double colon to separate the two. The reason this is useful is that now -both values `IpAddrKind::V4` and `IpAddrKind::V6` are of the same type: -`IpAddrKind`. We can then, for instance, define a function that takes any -`IpAddrKind`: + + + + + + +enumのバリアントは、その識別子の元に名前空間わけされていることと、 +2連コロンを使ってその二つを区別していることに注意してください。 +これが有効な理由は、こうすることで、値`IpAddrKind::V4`と`IpAddrKind::V6`という値は両方とも、 +同じ型`IpAddrKind`になったことです。そうしたら、例えば、どんな`IpAddrKind`を取る関数も定義できるようになります。 ```rust # enum IpAddrKind { @@ -56,7 +83,9 @@ both values `IpAddrKind::V4` and `IpAddrKind::V6` are of the same type: fn route(ip_type: IpAddrKind) { } ``` -And we can call this function with either variant: + + +そして、この関数をどちらのバリアント対しても呼び出せます: ```rust # enum IpAddrKind { @@ -70,10 +99,14 @@ route(IpAddrKind::V4); route(IpAddrKind::V6); ``` -Using enums has even more advantages. Thinking more about our IP address type, -at the moment we don’t have a way to store the actual IP address *data*; we -only know what *kind* it is. Given that you just learned about structs in -Chapter 5, you might tackle this problem as shown in Listing 6-1: + + + + + +enumの利用には、さらなる利点さえもあります。このIPアドレス型についてもっと考えてみると、現状では、 +実際のIPアドレスの*データ*を保持する方法がありません。つまり、どんな種類であるかを知っているだけです。 +構造体について第5章で学んだばっかりとすると、この問題に対しては、リスト6-1のように対処するかもしれません。 ```rust enum IpAddrKind { @@ -97,22 +130,35 @@ let loopback = IpAddr { }; ``` -Listing 6-1: Storing the data and `IpAddrKind` variant of -an IP address using a `struct` + + + +リスト6-1: IPアドレスのデータと`IpAddrKind`のバリアントを`struct`を使って保持する + + + + + + + + + -Here, we’ve defined a struct `IpAddr` that has two fields: a `kind` field that -is of type `IpAddrKind` (the enum we defined previously) and an `address` field -of type `String`. We have two instances of this struct. The first, `home`, has -the value `IpAddrKind::V4` as its `kind` with associated address data of -`127.0.0.1`. The second instance, `loopback`, has the other variant of -`IpAddrKind` as its `kind` value, `V6`, and has address `::1` associated with -it. We’ve used a struct to bundle the `kind` and `address` values together, so -now the variant is associated with the value. +ここでは、二つのフィールドを持つ`IpAddr`という構造体を定義しています: `IpAddrKind`型(先ほど定義したenumですね)の`kind`フィールドと、 +`String`型の`address`フィールドです。この構造体のインスタンスが2つあります。最初のインスタンス、 +`home`には`kind`として`IpAddrKind::V4`があり、紐付けられたアドレスデータは`127.0.0.1`です。 +2番目のインスタンス、`loopback`には、`kind`の値として、`IpAddrKind`のもう一つのバリアント、`V6`があり、 +アドレス`::1`が紐付いています。構造体を使って`kind`と`address`値を一緒に包んだので、 +もうバリアントは値と紐付けられています。 -We can represent the same concept in a more concise way using just an enum -rather than an enum as part of a struct by putting data directly into each enum -variant. This new definition of the `IpAddr` enum says that both `V4` and `V6` -variants will have associated `String` values: + + + + + +各enumのバリアントに直接データを格納して、enumを構造体の一部というよりもenumだけを使って、 +同じ概念をもっと簡潔な方法で表現することができます。この新しい`IpAddr`の定義は、 +`V4`と`V6`バリアント両方に`String`値が紐付けられていることを述べています。 ```rust enum IpAddr { @@ -125,15 +171,22 @@ let home = IpAddr::V4(String::from("127.0.0.1")); let loopback = IpAddr::V6(String::from("::1")); ``` -We attach data to each variant of the enum directly, so there is no need for an -extra struct. + + + +enumの各バリアントにデータを直接添加できるので、余計な構造体を作る必要は全くありません。 -There’s another advantage to using an enum rather than a struct: each variant -can have different types and amounts of associated data. Version four type IP -addresses will always have four numeric components that will have values -between 0 and 255. If we wanted to store `V4` addresses as four `u8` values but -still express `V6` addresses as one `String` value, we wouldn’t be able to with -a struct. Enums handle this case with ease: + + + + + + + +構造体よりもenumを使うことには、別の利点もあります: 各バリアントに紐付けるデータの型と量は、異なってもいいのです。 +バージョン4のIPアドレスには、常に0から255の値を持つ4つの数値があります。`V4`のアドレスは、4つの`u8`型の値として、 +格納するけれども、`V6`のアドレスは引き続き、単独の`String`型の値で格納したかったとしても、構造体では不可能です。 +enumなら、こんなケースも容易に対応できます: ```rust enum IpAddr { @@ -146,24 +199,45 @@ let home = IpAddr::V4(127, 0, 0, 1); let loopback = IpAddr::V6(String::from("::1")); ``` -We’ve shown several different possibilities that we could define in our code -for storing IP addresses of the two different varieties using an enum. However, -as it turns out, wanting to store IP addresses and encode which kind they are -is so common that [the standard library has a definition we can -use!][IpAddr] Let’s look at how the standard library defines -`IpAddr`: it has the exact enum and variants that we’ve defined and used, but -it embeds the address data inside the variants in the form of two different -structs, which are defined differently for each variant: + + + + + + + + + +enumを使用して、コード内で二つの異なるバラエティを持つIPアドレスを定義するいくつかの異なる可能性を示してきました。 +しかしながら、蓋を開けてみれば、IPアドレスを格納してその種類をエンコードしたくなるということは一般的なので、 +[標準ライブラリに使用可能な定義があります!][IpAddr] 標準ライブラリでの`IpAddr`の定義のされ方を見てみましょう。 +私たちが定義し、使用したのと全く同じenumとバリアントがありますが、アドレスデータを二種の異なる構造体の形でバリアントに埋め込み、 +この構造体は各バリアント用に異なる形で定義されています。 [IpAddr]: ../../std/net/enum.IpAddr.html + + + + + + + + + + + + + + + ```rust struct Ipv4Addr { - // details elided + // 省略 } struct Ipv6Addr { - // details elided + // 省略 } enum IpAddr { @@ -172,18 +246,28 @@ enum IpAddr { } ``` -This code illustrates that you can put any kind of data inside an enum variant: -strings, numeric types, or structs, for example. You can even include another -enum! Also, standard library types are often not much more complicated than -what you might come up with. + + + + + +このコードは、enumバリアント内にいかなる種類のデータでも格納できることを描き出しています: +例を挙げれば、文字列、数値型、構造体などです。他のenumを含むことさえできます!また、 +標準ライブラリの型は、あなたが思い付いたよりも複雑ではないことがしばしばあります。 + + + + + -Note that even though the standard library contains a definition for `IpAddr`, -we can still create and use our own definition without conflict because we -haven’t brought the standard library’s definition into our scope. We’ll talk -more about importing types in Chapter 7. +標準ライブラリに`IpAddr`に対する定義は含まれるものの、標準ライブラリの定義をスコープに導入していないので、 +まだ、干渉することなく自分自身の定義を生成して使用できることに注意してください。型のインポートについては、 +第7章でもっと詳しく言及します。 -Let’s look at another example of an enum in Listing 6-2: this one has a wide -variety of types embedded in its variants: + + + +リスト6-2でenumの別の例を見てみましょう: 今回のコードは、幅広い種類の型がバリアントに埋め込まれています: ```rust enum Message { @@ -194,40 +278,70 @@ enum Message { } ``` -Listing 6-2: A `Message` enum whose variants each store -different amounts and types of values + + + +リスト6-2: バリアント各々が異なる型と量の値を格納する`Message`enum + + + +このenumには、異なる型のバリアントが4つあります: -This enum has four variants with different types: + + + + -* `Quit` has no data associated with it at all. -* `Move` includes an anonymous struct inside it. -* `Write` includes a single `String`. -* `ChangeColor` includes three `i32`s. +* `Quit`には紐付けられたデータは全くなし。 +* `Move`は、中に匿名構造体を含む。 +* `Write`は、単独の`String`オブジェクトを含む。 +* `ChangeColor`は、3つの`i32`を含む。 -Defining an enum with variants like the ones in Listing 6-2 is similar to -defining different kinds of struct definitions except the enum doesn’t use the -`struct` keyword and all the variants are grouped together under the `Message` -type. The following structs could hold the same data that the preceding enum -variants hold: + + + + + + +リスト6-2のようなバリアントを含むenumを定義することは、enumの場合、`struct`キーワードを使わず、 +全部のバリアントが`Message`型の元に分類される点を除いて、異なる種類の構造体定義を定義するのと類似しています。 + + + + + + + + + + ```rust -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); // タプル構造体 ``` -But if we used the different structs, which each have their own type, we -wouldn’t be able to as easily define a function that could take any of these -kinds of messages as we could with the `Message` enum defined in Listing 6-2, -which is a single type. + + + + + + + +ですが、異なる構造体を使っていたら、各々、それ自身の型があるので、単独の型になるリスト6-2で定義した`Message`enumでするほど、 +これらの種のメッセージいずれもとる関数を簡単に定義することはできないでしょう。 -There is one more similarity between enums and structs: just as we’re able to -define methods on structs using `impl`, we’re also able to define methods on -enums. Here’s a method named `call` that we could define on our `Message` enum: + + + + +enumと構造体にはもう1点似通っているところがあります: `impl`を使って構造体にメソッドを定義できるのと全く同様に、 +enumにもメソッドを定義することができるのです。こちらは、`Message`enum上に定義できる`call`という名前のメソッドです: ```rust # enum Message { @@ -240,6 +354,7 @@ enums. Here’s a method named `call` that we could define on our `Message` enum impl Message { fn call(&self) { // method body would be defined here + // メソッド本体はここに定義される } } @@ -247,56 +362,93 @@ let m = Message::Write(String::from("hello")); m.call(); ``` -The body of the method would use `self` to get the value that we called the -method on. In this example, we’ve created a variable `m` that has the value -`Message::Write("hello")`, and that is what `self` will be in the body of the -`call` method when `m.call()` runs. - -Let’s look at another enum in the standard library that is very common and -useful: `Option`. - -### The `Option` Enum and Its Advantages Over Null Values - -In the previous section, we looked at how the `IpAddr` enum let us use Rust’s -type system to encode more information than just the data into our program. -This section explores a case study of `Option`, which is another enum defined -by the standard library. The `Option` type is used in many places because it -encodes the very common scenario in which a value could be something or it -could be nothing. Expressing this concept in terms of the type system means the -compiler can check that you’ve handled all the cases you should be handling, -which can prevent bugs that are extremely common in other programming languages. - -Programming language design is often thought of in terms of which features you -include, but the features you exclude are important too. Rust doesn’t have the -null feature that many other languages have. *Null* is a value that means there -is no value there. In languages with null, variables can always be in one of -two states: null or not-null. - -In “Null References: The Billion Dollar Mistake,” Tony Hoare, the inventor of -null, has this to say: - -> I call it my billion-dollar mistake. At that time, I was designing the first -> comprehensive type system for references in an object-oriented language. My -> goal was to ensure that all use of references should be absolutely safe, with -> checking performed automatically by the compiler. But I couldn't resist the -> temptation to put in a null reference, simply because it was so easy to -> implement. This has led to innumerable errors, vulnerabilities, and system -> crashes, which have probably caused a billion dollars of pain and damage in -> the last forty years. - -The problem with null values is that if you try to actually use a value that’s -null as if it is a not-null value, you’ll get an error of some kind. Because -this null or not-null property is pervasive, it’s extremely easy to make this -kind of error. - -However, the concept that null is trying to express is still a useful one: a -null is a value that is currently invalid or absent for some reason. - -The problem isn’t with the actual concept but with the particular -implementation. As such, Rust does not have nulls, but it does have an enum -that can encode the concept of a value being present or absent. This enum is -`Option`, and it is [defined by the standard library][option] -as follows: + + + + + +メソッドの本体では、`self`を使用して、メソッドを呼び出した相手の値を取得できます。この例では、 +`Message::Write("hello")`という値を持つ、変数`m`を生成したので、これが`m.call()`を走らせた時に、 +`call`メソッドの本体内で`self`が表す値になります。 + + + + +非常に一般的で有効な別の標準ライブラリのenumを見てみましょう: `Option`です。 + + + +### `Option`enumとNull値に勝る利点 + + + + + + + + + + +前節で、`IpAddr`enumがRustの型システムを使用して、プログラムにデータ以上の情報をエンコードできる方法を見ました。 +この節では、`Option`のケーススタディを掘り下げていきます。この型も標準ライブラリにより定義されているenumです。 +この`Option`型はいろんな箇所で使用されます。なぜなら、値が何かかそうでないかという非常に一般的な筋書きをコード化するからです。 +この概念を型システムの観点で表現することは、コンパイラが、プログラマが処理すべき場面全てを処理していることをチェックできることを意味し、 +これにより、他の言語において、究極的にありふれたバグを阻止することができます。 + + + + + + + +プログラミング言語のデザインは、しばしばどの機能を入れるかという観点で考えられるが、 +除いた機能も重要なのです。Rustには、他の多くの言語にはあるnull機能がありません。 +*null*とはそこに何も値がないことを意味する値です。nullのある言語において、 +変数は常に二者択一どちらかの状態になります: nullかそうでないかです。 + + + + +nullの開発者であるTony Hoareの著書"Null References: The Billion Dollar Mistake"では、こんなことが語られています。 + + + + + + + + + + +> 私はそれを10億ドルの失敗と呼んでいます。その頃、私は、オブジェクト指向言語の参照に対する、 +> 最初のわかりやすい型システムをデザインしていました。私の目標は、 +> どんな参照の使用も全て完全に安全であるべきことを、コンパイラにそのチェックを自動で行ってもらって保証することだったのです。 +> しかし、null参照を入れるという誘惑に打ち勝つことができませんでした。それは、単純に実装が非常に容易だったからです。 +> これが無数のエラーや脆弱性、システムクラッシュにつながり、過去40年で10億ドルの苦痛や損害を引き起こしたであろうということなのです。 + + + + + + +null値の問題は、nullの値をnullでない値のように実際に使用しようとしたら、何らかの種類のエラーが出ることです。 +このnullかそうでないかという特性は広く存在するので、この種の間違いを大変犯しやすいのです。 + + + + +しかしながら、nullが表現しようとしている概念は、それでも役に立つものです: nullは、 +何らかの理由で現在無効または存在しない値のことなのです。 + + + + + + + +問題は、実際の概念にあるのではなく、特定の実装にあるのです。そんな感じなので、Rustにはnullがありませんが、 +値が存在するか不在かという概念をコード化するenumならあります。このenumが`Option`で、 +以下のように[標準ライブラリに定義][option]されています。 [option]: ../../std/option/enum.Option.html @@ -307,17 +459,26 @@ enum Option { } ``` -The `Option` enum is so useful that it’s even included in the prelude; you -don’t need to import it explicitly. In addition, so are its variants: you can -use `Some` and `None` directly without prefixing them with `Option::`. -`Option` is still just a regular enum, and `Some(T)` and `None` are still -variants of type `Option`. + + + + + + +`Option`は有益すぎて、初期化処理(prelude)にさえ含まれています。つまり、明示的にインポートする必要がないのです。 +さらに、バリアントもそうなっています: `Some`と`None`を`Option::`と接頭辞をつけることなく直接使えるわけです。 +ただ、`Option`は普通のenumであり、`Some(T)`と`None`は`Option`型のバリアントです。 -The `` syntax is a feature of Rust we haven’t talked about yet. It’s a -generic type parameter, and we’ll cover generics in more detail in Chapter 10. -For now, all you need to know is that `` means the `Some` variant of the -`Option` enum can hold one piece of data of any type. Here are some examples of -using `Option` values to hold number types and string types: + + + + + + +``という記法は、まだ語っていないRustの機能です。これは、ジェネリック型引数であり、ジェネリクスについて詳しくは、 +第10章で解説します。とりあえず、知っておく必要があることは、``は、`Option`enumの`Some`バリアントが、 +あらゆる型のデータを1つだけ持つことができることを意味していることだけです。こちらは、 +`Option`値を使って、数値型や文字列型を保持する例です。 ```rust let some_number = Some(5); @@ -326,19 +487,30 @@ let some_string = Some("a string"); let absent_number: Option = None; ``` -If we use `None` rather than `Some`, we need to tell Rust what type of -`Option` we have, because the compiler can't infer the type that the `Some` -variant will hold by looking only at a `None` value. + + + + +`Some`ではなく、`None`を使ったら、コンパイラに`Option`の型が何になるかを教えなければいけません。 +というのも、`None`値を見ただけでは、`Some`バリアントが保持する型をコンパイラが推論できないからです。 -When we have a `Some` value, we know that a value is present, and the value is -held within the `Some`. When we have a `None` value, in some sense, it means -the same thing as null: we don’t have a valid value. So why is having -`Option` any better than having null? + + + + -In short, because `Option` and `T` (where `T` can be any type) are different -types, the compiler won’t let us use an `Option` value as if it was -definitely a valid value. For example, this code won’t compile because it’s -trying to add an `i8` to an `Option`: +`Some`値がある時、値が存在するとわかり、その値は、`Some`に保持されています。`None`値がある場合、 +ある意味、nullと同じことを意図します: 有効な値がないのです。では、なぜ`Option`の方が、 +nullよりも好ましいのでしょうか? + + + + + + +簡潔に述べると、`Option`と`T`(ここで`T`はどんな型でもいい)は異なる型なので、 +コンパイラが`Option`値を確実に有効な値かのようには使用させてくれません。 +例えば、このコードは`i8`を`Option`に足そうとしているので、コンパイルできません。 ```rust,ignore let x: i8 = 5; @@ -347,11 +519,14 @@ let y: Option = Some(5); let sum = x + y; ``` -If we run this code, we get an error message like this: + + +このコードを動かしたら、以下のようなエラーメッセージが出ます。 ```text error[E0277]: the trait bound `i8: std::ops::Add>` is not satisfied +(エラー: `i8: std::ops::Add>`というトレイト境界が満たされていません) --> | 7 | let sum = x + y; @@ -359,42 +534,70 @@ not satisfied | ``` -Intense! In effect, this error message means that Rust doesn’t understand how -to add an `Option` and an `i8`, because they’re different types. When we -have a value of a type like `i8` in Rust, the compiler will ensure that we -always have a valid value. We can proceed confidently without having to check -for null before using that value. Only when we have an `Option` (or -whatever type of value we’re working with) do we have to worry about possibly -not having a value, and the compiler will make sure we handle that case before -using the value. - -In other words, you have to convert an `Option` to a `T` before you can -perform `T` operations with it. Generally, this helps catch one of the most -common issues with null: assuming that something isn’t null when it actually -is. - -Not having to worry about missing an assumption of having a not-null value -helps you to be more confident in your code. In order to have a value that can -possibly be null, you must explicitly opt in by making the type of that value -`Option`. Then, when you use that value, you are required to explicitly -handle the case when the value is null. Everywhere that a value has a type that -isn’t an `Option`, you *can* safely assume that the value isn’t null. This -was a deliberate design decision for Rust to limit null’s pervasiveness and -increase the safety of Rust code. - -So, how do you get the `T` value out of a `Some` variant when you have a value -of type `Option` so you can use that value? The `Option` enum has a large -number of methods that are useful in a variety of situations; you can check -them out in [its documentation][docs]. Becoming familiar with -the methods on `Option` will be extremely useful in your journey with Rust. + + + + + + + + + +なんて強烈な!実際に、このエラーメッセージは、`Option`と`i8`が異なる型なので、 +足し合わせる方法がコンパイラにはわからないことを意味します。Rustにおいて、`i8`のような型の値がある場合、 +コンパイラが常に有効な値であることを確認してくれます。この値を使う前にnullであることをチェックする必要なく、 +自信を持って先に進むことができるのです。`Option`がある時(あるいはどんな型を扱おうとしていても)のみ、 +値を保持していない可能性を心配する必要はないわけであり、 +コンパイラはプログラマが値を使用する前にそのような場面を扱っているか確かめてくれます。 + + + + + + +言い換えると、`T`型の処理を行うには、`Option`を`T`に変換する必要があるわけです。一般的に、 +これにより、nullの最もありふれた問題の一つを捕捉できます: 実際にはnullなのに、 +そうでないかのように想定することです。 + + + + + + + + + + +nullでない値があるという想定を見逃す心配をしなくてもよいということは、コード内でより自信を持てることになります。 +nullになる可能性のある値を保持するには、その値の型を`Option`にすることで明示的に同意しなければなりません。 +それからその値を使用する際には、値がnullである場合を明示的に処理する必要があります。 +値が`Option`以外の型であるとこ全てにおいて、値がnullでないと安全に想定することが*できます*。 +これは、Rustにとって、意図的なデザイン決定であり、nullの普遍性を制限し、Rustコードの安全性を向上させます。 + + + + + + + +では、`Option`型の値がある時、その値を使えるようにするには、どのように`Some`バリアントから`T`型の値を取り出せばいいのでしょうか? +`Option`には様々な場面で有効に活用できる非常に多くのメソッドが用意されています; +[ドキュメント][docs]でそれらを確認できます。`Option`のメソッドに馴染むと、 +Rustの旅が極めて有益になるでしょう。 [docs]: ../../std/option/enum.Option.html -In general, in order to use an `Option` value, we want to have code that -will handle each variant. We want some code that will run only when we have a -`Some(T)` value, and this code is allowed to use the inner `T`. We want some -other code to run if we have a `None` value, and that code doesn’t have a `T` -value available. The `match` expression is a control flow construct that does -just this when used with enums: it will run different code depending on which -variant of the enum it has, and that code can use the data inside the matching -value. + + + + + + + + + +一般的に、`Option`値を使うには、各バリアントを処理するコードが欲しくなります。 +`Some(T)`値がある時だけ走る何らかのコードが欲しくなり、このコードが内部の`T`を使用できます。 +`None`値があった場合に走る別のコードが欲しくなり、そちらのコードは`T`値は使用できない状態になります。 +`match`式が、enumとともに使用した時にこれだけをするフロー制御文法要素になります: enumのバリアントによって、 +違うコードが走り、そのコードがマッチした値の中のデータを使用できるのです。 diff --git a/second-edition/src/ch06-02-match.md b/second-edition/src/ch06-02-match.md index b7ce42ea7..02cdd9df5 100644 --- a/second-edition/src/ch06-02-match.md +++ b/second-edition/src/ch06-02-match.md @@ -1,23 +1,37 @@ -## The `match` Control Flow Operator - -Rust has an extremely powerful control-flow operator called `match` that allows -us to compare a value against a series of patterns and then execute code based -on which pattern matches. Patterns can be made up of literal values, variable -names, wildcards, and many other things; Chapter 18 will cover all the -different kinds of patterns and what they do. The power of `match` comes from -the expressiveness of the patterns and the compiler checks that make sure all -possible cases are handled. - -Think of a `match` expression kind of like a coin sorting machine: coins slide -down a track with variously sized holes along it, and each coin falls through -the first hole it encounters that it fits into. In the same way, values go -through each pattern in a `match`, and at the first pattern the value “fits,” -the value will fall into the associated code block to be used during execution. - -Because we just mentioned coins, let’s use them as an example using `match`! We -can write a function that can take an unknown United States coin and, in a -similar way as the counting machine, determine which coin it is and return its -value in cents, as shown here in Listing 6-3: + + +## `match`フロー制御演算子 + + + + + + + + + +Rustには、一連のパターンに対して値を比較し、マッチしたパターンに応じてコードを実行させてくれる`match`と呼ばれる、 +非常に強力なフロー制御演算子があります。パターンは、リテラル値、変数名、ワイルドカードや他の多くのもので構成することができます; +第18章で、全ての種類のパターンと、その目的については解説します。`match`のパワーは、 +パターンの表現力に由来し、コンパイラが全てのありうるパターンを処理しているかを確認してくれます。 + + + + + + + +`match`式をコイン並べ替え装置のようなものと考えてください: コインは、様々なサイズの穴が空いた通路を流れ落ち、 +各コインは、サイズのあった最初の穴に落ちます。同様に、値は`match`の各パターンを通り抜け、値が適合する最初のパターンで、 +値は紐付けられたコードブロックに落ち、実行中に使用されるわけです。 + + + + + + +コインについて話したので、それを`match`を使用する例にとってみましょう!数え上げ装置と同じ要領で未知のアメリカコインを一枚取り、 +どの種類のコインなのか決定し、その価値をセントで返す関数をリスト6-3で示したように記述することができます: ```rust enum Coin { @@ -37,36 +51,58 @@ fn value_in_cents(coin: Coin) -> u32 { } ``` -Listing 6-3: An enum and a `match` expression that has -the variants of the enum as its patterns. - -Let’s break down the `match` in the `value_in_cents` function. First, we list -the `match` keyword followed by an expression, which in this case is the value -`coin`. This seems very similar to an expression used with `if`, but there’s a -big difference: with `if`, the expression needs to return a boolean value. -Here, it can be any type. The type of `coin` in this example is the `Coin` enum -that we defined in Listing 6-3. - -Next are the `match` arms. An arm has two parts: a pattern and some code. The -first arm here has a pattern that is the value `Coin::Penny` and then the `=>` -operator that separates the pattern and the code to run. The code in this case -is just the value `1`. Each arm is separated from the next with a comma. - -When the `match` expression executes, it compares the resulting value against -the pattern of each arm, in order. If a pattern matches the value, the code -associated with that pattern is executed. If that pattern doesn’t match the -value, execution continues to the next arm, much like a coin sorting machine. -We can have as many arms as we need: in Listing 6-3, our `match` has four arms. - -The code associated with each arm is an expression, and the resulting value of -the expression in the matching arm is the value that gets returned for the -entire `match` expression. - -Curly braces typically aren’t used if the match arm code is short, as it is in -Listing 6-3 where each arm just returns a value. If you want to run multiple -lines of code in a match arm, you can use curly braces. For example, the -following code would print out “Lucky penny!” every time the method was called -with a `Coin::Penny` but would still return the last value of the block, `1`: + + + +リスト6-3: enumとそのenumのバリアントをパターンにした`match`式 + + + + + + + + +`value_in_cents`関数内の`match`を掘り下げてみましょう。まず、`match`キーワードに続けて式を並べています。 +この式は今回の場合、値`coin`です。`if`で使用した式と非常に酷似していますね。しかし、大きな違いがあります: +`if`では、式は論理値を返す必要があります。ここでは、どんな型でも構いません。この例における`coin`の型は、 +リスト6-3で定義した`Coin`enumです。 + + + + + + +次は、`match`アームです。一本のアームには2つの部品があります: パターンと何らかのコードです。 +今回の最初のアームは`Coin::Penny`という値のパターンであり、パターンと動作するコードを区別する`=>`演算子が続きます。 +この場合のコードは、ただの値`1`です。各アームは次のアームとカンマで区切られています。 + + + + + + + +この`match`式が実行されると、結果の値を各アームのパターンと順番に比較します。パターンに値がマッチしたら、 +そのコードに紐付けられたコードが実行されます。パターンが値にマッチしなければ、コイン並べ替え装置と全く同じように、 +次のアームが継続して実行されます。必要なだけパターンは存在できます: リスト6-3では、`match`は4本のアームを持っています。 + + + + + +各アームに紐付けられるコードは式であり、マッチしたアームの式の結果が`match`式全体の戻り値になります。 + + + + + + + +典型的には、アームのコードが短い場合、波かっこは使用されません。リスト6-3では、各アームが値を返すだけなので、 +これに倣っています。マッチのアームで複数行のコードを走らせたいのなら、波かっこを使用することができます。 +例えば、以下のコードは、メソッドが`Coin::Penny`とともに呼び出されるたびに「ラッキーなペニー」と表示しつつ、 +ブロックの最後の値、`1`を返すでしょう。 ```rust # enum Coin { @@ -89,25 +125,52 @@ fn value_in_cents(coin: Coin) -> u32 { } ``` -### Patterns that Bind to Values - -Another useful feature of match arms is that they can bind to parts of the -values that match the pattern. This is how we can extract values out of enum -variants. - -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 `State` value stored -inside it, which we've done here in Listing 6-4: + + +### 値に束縛されるパターン + + + + + +マッチのアームの別の便利な機能は、パターンにマッチした値の一部に束縛できる点です。これにより、 +enumのバリアントから値を取り出すことができます。 + + + + + + + + +例として、enumのバリアントの一つを中にデータを保持するように変えましょう。1999年から2008年まで、 +アメリカは、片側に50の州それぞれで異なるデザインをしたクォータコインを鋳造していました。 +他のコインは州のデザインがなされることはなかったので、クォータだけがこのおまけの値を保持します。 +`Quarter`バリアントを変更して、`State`値が中に保持されるようにすることでenumにこの情報を追加でき、 +それをしたのがリスト6-4のコードになります: + + + + + + + + + + + + + + + + ```rust -#[derive(Debug)] // So we can inspect the state in a minute +#[derive(Debug)] // すぐに州を点検できるように enum UsState { Alabama, Alaska, - // ... etc + // ... などなど } enum Coin { @@ -118,18 +181,29 @@ enum Coin { } ``` -Listing 6-4: A `Coin` enum where the `Quarter` variant -also holds a `UsState` value + + + +リスト6-4: `Quarter`バリアントが`UsState`の値も保持する`Coin`enum + + + + + + + + +友人の一人が50州全部のクォータコインを収集しようとしているところを想像しましょう。コインの種類で緩い変更を並べ替える間、 +各クォータに関連した州の名前を叫ぶことになるので、友人が持っていない種類だったら、コレクションに追加することができます。 -Let’s imagine that a friend of ours is trying to collect all 50 state quarters. -While we sort our loose change by coin type, we’ll also call out the name of -the state associated with each quarter so if it’s one our friend doesn’t have, -they can add it to their collection. + + + + -In the match expression for this code, we add a variable called `state` to the -pattern that matches values of the variant `Coin::Quarter`. When a -`Coin::Quarter` matches, the `state` variable will bind to the value of that -quarter’s state. Then we can use `state` in the code for that arm, like so: +このコードのmatch式では、`Coin::Quarter`バリアントの値にマッチする`state`という名の変数をパターンに追加します。 +`Coin::Quarter`がマッチすると、`state`変数はそのクォータのstateの値に束縛されます。それから、 +`state`をそのアームのコードで使用できます。以下のようにですね: ```rust # #[derive(Debug)] @@ -158,28 +232,45 @@ fn value_in_cents(coin: Coin) -> u32 { } ``` -If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska))`, `coin` -would be `Coin::Quarter(UsState::Alaska)`. When we compare that value with each -of the match arms, none of them match until we reach `Coin::Quarter(state)`. At -that point, the binding for `state` will be the value `UsState::Alaska`. We can -then use that binding in the `println!` expression, thus getting the inner -state value out of the `Coin` enum variant for `Quarter`. + + + + + + -### Matching with `Option` +`value_in_cents(Coin::Quarter(UsState::Alaska))`と呼び出すつもりだったなら、`coin`は +`Coin::Quarter(UsState::Alaska)`になります。その値をmatchの各アームと比較すると、 +`Coin::Quater(state)`に到達するまで、どれにもマッチしません。その時に、`state`に束縛されるのは、 +`UsState::Alaska`という値です。そして、`println!`式でその束縛を使用することができ、 +そのため、`Coin`enumのバリアントから`Quarter`に対する中身のstateの値を取得できたわけです。 -In the previous section we wanted to get the inner `T` value out of the `Some` -case when using `Option`; we can also handle `Option` using `match` as we -did with the `Coin` enum! Instead of comparing coins, we’ll compare the -variants of `Option`, but the way that the `match` expression works remains -the same. + -Let’s say we want to write a function that takes an `Option`, and if -there’s a value inside, adds one to that value. If there isn’t a value inside, -the function should return the `None` value and not attempt to perform any -operations. +### `Option`とのマッチ -This function is very easy to write, thanks to `match`, and will look like -Listing 6-5: + + + + + + +前節では、`Option`を使用する際に、`Some`ケースから中身の`T`の値を取得したくなりました。要するに、 +`Coin`enumに対して行ったように、`match`を使って`Option`を扱うこともできるというわけです! +コインを比較する代わりに、`Option`のバリアントを比較するのですが、`match`式の動作の仕方は同じになったままです。 + + + + + + +`Option`をとる関数を書きたくなったとし、中に値があったら、その値に1を足すことにしましょう。 +中に値がなければ、関数は`None`値を返し、何も処理すべきではありません。 + + + + +`match`のおかげで、この関数は大変書きやすく、リスト6-5のような見た目になります: ```rust fn plus_one(x: Option) -> Option { @@ -194,54 +285,85 @@ let six = plus_one(five); let none = plus_one(None); ``` -Listing 6-5: A function that uses a `match` expression on -an `Option` + + + +リスト6-5: `Option`に`match`式を使う関数 -#### Matching `Some(T)` + -Let’s examine the first execution of `plus_one` in more detail. When we call -`plus_one(five)`, the variable `x` in the body of `plus_one` will have the -value `Some(5)`. We then compare that against each match arm. +#### `Some(T)にマッチする` + + + + + +`plus_one`の最初の実行についてもっと詳しく検証しましょう。`plus_one(five)`と呼び出した時、 +`plus_one`の本体の変数`x`は`Some(5)`になります。そして、これを各マッチのアームに比較します。 ```rust,ignore None => None, ``` -The `Some(5)` value doesn’t match the pattern `None`, so we continue to the -next arm. + + + +`Some(5)`という値は、`None`というパターンにはマッチしませんので、次のアームに処理が移ります。 ```rust,ignore Some(i) => Some(i + 1), ``` -Does `Some(5)` match `Some(i)`? Why yes it does! We have the same variant. -The `i` binds to the value contained in `Some`, so `i` takes the value `5`. The -code in the match arm is then executed, so we add one to the value of `i` and -create a new `Some` value with our total `6` inside. + + + + + +`Some(5)`は`Some(i)`にマッチしますか?もちろん、します!バリアントが同じです。`i`は`Some`に含まれる値に束縛されるので、 +`i`は値`5`になります。それから、このマッチのアームのコードが実行されるので、`i`の値に1を足し、 +合計の`6`を中身にした新しい`Some`値を生成します。 + + + +#### `None`とマッチする -#### Matching `None` + + -Now let’s consider the second call of `plus_one` in Listing 6-5 where `x` is -`None`. We enter the `match` and compare to the first arm. +さて、`x`が`None`になるリスト6-5の2回目の`plus_pne`の呼び出しを考えましょう。`match`に入り、 +最初のアームと比較します。 ```rust,ignore None => None, ``` -It matches! There’s no value to add to, so the program stops and returns the -`None` value on the right side of `=>`. Because the first arm matched, no other -arms are compared. + + + -Combining `match` and enums is useful in many situations. You’ll see this -pattern a lot in Rust code: `match` against an enum, bind a variable to the -data inside, and then execute code based on it. It’s a bit tricky at first, but -once you get used to it, you’ll wish you had it in all languages. It’s -consistently a user favorite. +マッチします!足し算する値がないので、プログラムは停止し、`=>`の右辺にある`None`値が返ります。 +最初のアームがマッチしたため、他のアームは比較されません。 -### Matches Are Exhaustive + + + + + -There’s one other aspect of `match` we need to discuss. Consider this version -of our `plus_one` function: +`match`とenumの組み合わせは、多くの場面で有効です。Rustコードにおいて、このパターンはよく見かけるでしょう: +enumに対し`match`し、内部のデータに変数を束縛させ、それに基づいたコードを実行します。一目にはちょっと巧妙ですが、 +一旦慣れてしまえば、全ての言語にあってほしいと願うことになるでしょう。一貫してユーザのお気に入りなのです。 + + + + + +### マッチは包括的 + + + + +もう一つ議論する必要のある`match`の観点があります。こんなバージョンの`plus_one`関数を考えてください: ```rust,ignore fn plus_one(x: Option) -> Option { @@ -251,32 +373,48 @@ fn plus_one(x: Option) -> Option { } ``` -We didn’t handle the `None` case, so this code will cause a bug. Luckily, it’s -a bug Rust knows how to catch. If we try to compile this code, we’ll get this -error: + + + + +`None`の場合を扱っていないため、このコードはバグを生みます。幸い、コンパイラが捕捉できるバグです。 +このコードのコンパイルを試みると、こんなエラーが出ます: ```text error[E0004]: non-exhaustive patterns: `None` not covered +(エラー: 包括的でないパターン: `None`がカバーされてません) --> | 6 | match x { | ^ pattern `None` not covered ``` -Rust knows that we didn’t cover every possible case and even knows which -pattern we forgot! Matches in Rust are *exhaustive*: we must exhaust every last -possibility in order for the code to be valid. Especially in the case of -`Option`, when Rust prevents us from forgetting to explicitly handle the -`None` case, it protects us from assuming that we have a value when we might -have null, thus making the billion dollar mistake discussed earlier. + + + + + + -### The `_` Placeholder +全可能性を網羅していないことをコンパイラは検知しています。もっと言えば、どのパターンを忘れているかさえ知っているのです。 +Rustにおけるマッチは、*包括的*です: 全てのあらゆる可能性を消費し尽くさなければ、コードは有効にならないのです。 +特に`Option`の場合には、コンパイラが明示的に`None`の場合を扱うのを忘れないようにする時、 +nullになるかもしれない値があることを想定しないように、つまり、前に議論した10億ドルの失敗を犯さないよう、 +保護してくれるわけです。 -Rust also has a pattern we can use in situations when we don’t want to list all -possible values. For example, a `u8` can have valid values of 0 through 255. If -we only care about the values 1, 3, 5, and 7, we don’t want to have to list out -0, 2, 4, 6, 8, 9 all the way up to 255. Fortunately, we don’t have to: we can -use the special pattern `_` instead: + + +### `_`というプレースホルダー + + + + + + + +Rustには、全ての可能性を列挙したくない場合に使用できるパターンもあります。例えば、`u8`は、有効な値として、 +0から255までを取ります。1、3、5、7の値にだけ興味があったら、0、2、4、6、8、9と255までの数値を列挙する必要に迫られたくはないです。 +幸運なことに、する必要はありません: 代わりに特別なパターンの`_`を使用できます: ```rust let some_u8_value = 0u8; @@ -289,11 +427,19 @@ match some_u8_value { } ``` -The `_` pattern will match any value. By putting it after our other arms, the -`_` will match all the possible cases that aren’t specified before it. The `()` -is just the unit value, so nothing will happen in the `_` case. As a result, we -can say that we want to do nothing for all the possible values that we don’t -list before the `_` placeholder. + + + + + + +`_`というパターンは、どんな値にもマッチします。他のアームの後に記述することで、`_`は、 +それまでに指定されていない全ての可能性にマッチします。`()`は、ただのユニット値なので、`_`の場合には、 +何も起こりません。結果として、`_`プレースホルダーの前に列挙していない可能性全てに対しては、 +何もしたくないと言えるわけです。 + + + -However, the `match` expression can be a bit wordy in a situation in which we -only care about *one* of the cases. For this situation, Rust provides `if let`. +ですが、一つのケースにしか興味がないような場面では、`match`式はちょっと長ったらしすぎます。 +このような場面用に、Rustには、`if let`が用意されています。 From dc434cfffbe33d03dbb1d38c50b52a846a95e76c Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 17 Jul 2017 18:56:05 +0900 Subject: [PATCH 010/428] =?UTF-8?q?First=20draft=20of=20the=20chapter=206-?= =?UTF-8?q?3=20and=20replace=20all=20occurrences=20of=20"=E3=82=AF?= =?UTF-8?q?=E3=82=A9=E3=83=BC=E3=82=BF"=20with=20"=E3=82=AF=E3=82=A9?= =?UTF-8?q?=E3=83=BC=E3=82=BF=E3=83=BC"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- second-edition/src/ch06-02-match.md | 10 +- second-edition/src/ch06-03-if-let.md | 142 ++++++++++++++++++--------- 2 files changed, 101 insertions(+), 51 deletions(-) diff --git a/second-edition/src/ch06-02-match.md b/second-edition/src/ch06-02-match.md index 02cdd9df5..b24991aaf 100644 --- a/second-edition/src/ch06-02-match.md +++ b/second-edition/src/ch06-02-match.md @@ -144,8 +144,8 @@ enumのバリアントから値を取り出すことができます。 例として、enumのバリアントの一つを中にデータを保持するように変えましょう。1999年から2008年まで、 -アメリカは、片側に50の州それぞれで異なるデザインをしたクォータコインを鋳造していました。 -他のコインは州のデザインがなされることはなかったので、クォータだけがこのおまけの値を保持します。 +アメリカは、片側に50の州それぞれで異なるデザインをしたクォーターコインを鋳造していました。 +他のコインは州のデザインがなされることはなかったので、クォーターだけがこのおまけの値を保持します。 `Quarter`バリアントを変更して、`State`値が中に保持されるようにすることでenumにこの情報を追加でき、 それをしたのがリスト6-4のコードになります: @@ -193,8 +193,8 @@ enum Coin { -友人の一人が50州全部のクォータコインを収集しようとしているところを想像しましょう。コインの種類で緩い変更を並べ替える間、 -各クォータに関連した州の名前を叫ぶことになるので、友人が持っていない種類だったら、コレクションに追加することができます。 +友人の一人が50州全部のクォーターコインを収集しようとしているところを想像しましょう。コインの種類で緩い変更を並べ替える間、 +各クォーターに関連した州の名前を叫ぶことになるので、友人が持っていない種類だったら、コレクションに追加することができます。 @@ -202,7 +202,7 @@ enum Coin { このコードのmatch式では、`Coin::Quarter`バリアントの値にマッチする`state`という名の変数をパターンに追加します。 -`Coin::Quarter`がマッチすると、`state`変数はそのクォータのstateの値に束縛されます。それから、 +`Coin::Quarter`がマッチすると、`state`変数はそのクォーターのstateの値に束縛されます。それから、 `state`をそのアームのコードで使用できます。以下のようにですね: ```rust diff --git a/second-edition/src/ch06-03-if-let.md b/second-edition/src/ch06-03-if-let.md index b2c9afd05..93a198b84 100644 --- a/second-edition/src/ch06-03-if-let.md +++ b/second-edition/src/ch06-03-if-let.md @@ -1,9 +1,15 @@ -## Concise Control Flow with `if let` + -The `if let` syntax lets you combine `if` and `let` into a less verbose way to -handle values that match one pattern and ignore the rest. Consider the program -in Listing 6-6 that matches on an `Option` value but only wants to execute -code if the value is three: +## `if let`で完結なフロー制御 + + + + + + +`if let`記法で`if`と`let`をより冗長性の少ない方法で組み合わせ、一つのパターンにマッチし、 +残りを無視する値を扱うことができます。`Option`にマッチするけれど、値が3の時にだけコードを実行したい、 +リスト6-6のプログラムを考えてください: ```rust let some_u8_value = Some(0u8); @@ -13,16 +19,25 @@ match some_u8_value { } ``` -Listing 6-6: A `match` that only cares about executing -code when the value is `Some(3)` + + + +リスト6-6: 値が`Some(3)`の時だけコードを実行する`match` + + + + + -We want to do something with the `Some(3)` match but do nothing with any other -`Some` value or the `None` value. To satisfy the `match` expression, we -have to add `_ => ()` after processing just one variant, which is a lot of -boilerplate code to add. +`Some(3)`にマッチした時だけ何かをし、他の`Some`値や`None`値の時には何もしたくありません。 +`match`式を満たすためには、バリアントを一つだけ処理した後に`_ => ()`を追加しなければなりません。 +これでは、追加すべき典型コードが多すぎます。 -Instead, we could write this in a shorter way using `if let`. The following -code behaves the same as the `match` in Listing 6-6: + + + +その代わり、`if let`を使用してもっと短く書くことができます。以下のコードは、 +リスト6-6の`match`と全く同じように振る舞います: ```rust # let some_u8_value = Some(0u8); @@ -31,26 +46,42 @@ if let Some(3) = some_u8_value { } ``` -`if let` takes a pattern and an expression separated by an `=`. It works the -same way as a `match`, where the expression is given to the `match` and the -pattern is its first arm. + + + + +`if let`は`=`で区切られたパターンと式を取り、式が`match`に与えられ、パターンが最初のアームになった`match`と、 +同じ動作をします。 + + + + + + + +`if let`を使うと、タイプ数が減り、インデントも少なくなり、典型コードも減ります。しかしながら、 +`match`では強制された包括性チェックがなくなってしまいます。`match`か`if let`かの選択は、 +特定の場面でどんなことをしたいかと簡潔性を得ることが包括性チェックを失うのに適切な代償となるかによります。 -Using `if let` means you have less to type, less indentation, and less -boilerplate code. However, we’ve lost the exhaustive checking that `match` -enforces. Choosing between `match` and `if let` depends on what you’re doing in -your particular situation and if gaining conciseness is an appropriate -trade-off for losing exhaustive checking. + + -In other words, you can think of `if let` as syntax sugar for a `match` that -runs code when the value matches one pattern and then ignores all other values. +言い換えると、`if let`は値が一つのパターンにマッチした時にコードを走らせ、他は無視する`match`への糖衣構文と、 +考えることができます。 -We can include an `else` with an `if let`. The block of code that goes with the -`else` is the same as the block of code that would go with the `_` case in the -`match` expression that is equivalent to the `if let` and `else`. Recall the -`Coin` enum definition in Listing 6-4, where the `Quarter` variant also held a -`UsState` value. If we wanted to count all non-quarter coins we see while also -announcing the state of the quarters, we could do that with a `match` -expression like this: + + + + + + + + +`if let`では、`else`を含むこともできます。`else`に入るコードブロックは、 +`if let`と`else`に等価な`match`式の`_`の場合に入るコードブロックと同じになります。 +リスト6-4の`Coin`enum定義を思い出してください。ここでは、`Quarter`バリアントは、 +`UsState`の値も保持していましたね。クォーターコインの状態を告げつつ、 +見かけたクォーター以外のコインの枚数を数えたいなら、以下のように`match`式ですることができます: ```rust # #[derive(Debug)] @@ -68,12 +99,15 @@ expression like this: # let coin = Coin::Penny; let mut count = 0; match coin { + // {:?}州のクォーターコイン Coin::Quarter(state) => println!("State quarter from {:?}!", state), _ => count += 1, } ``` -Or we could use an `if let` and `else` expression like this: + + +または、以下のように`if let`と`else`を使うこともできます: ```rust # #[derive(Debug)] @@ -97,22 +131,38 @@ if let Coin::Quarter(state) = coin { } ``` -If you have a situation in which your program has logic that is too verbose to -express using a `match`, remember that `if let` is in your Rust toolbox as well. + + + +`match`を使って表現するには冗長的すぎるロジックがプログラムにあるようなシチュエーションに遭遇したら、 +`if let`もRust道具箱にあることを思い出してください。 + + + +## まとめ + + + + + + + +これで、enumを使用してワンセットの列挙された値のどれかになりうるカスタマイズされた型を生成する方法を解説しました。 +標準ライブラリの`Option`が型システムを使用して、エラーを回避する際に役立つ方法についても示しました。 +enumの値がデータを内部に含む場合、処理すべきケースの数に応じて、`match`か`if let`を使用して値を取り出し、 +使用できます。 -## Summary + + + + -We’ve now covered how to use enums to create custom types that can be one of a -set of enumerated values. We’ve shown how the standard library’s `Option` -type helps you use the type system to prevent errors. When enum values have -data inside them, you can use `match` or `if let` to extract and use those -values, depending on how many cases you need to handle. +もうRustプログラムで構造体とenumを使用して、自分の領域の概念を表現できます。API内で使用するためにカスタマイズされた型を生成することで、 +型安全性を保証することができます: コンパイラが、各関数の予期する型の値のみを関数が得ることを確かめてくれるのです。 -Your Rust programs can now express concepts in your domain using structs and -enums. Creating custom types to use in your API ensures type safety: the -compiler will make certain your functions only get values of the type each -function expects. + + + -In order to provide a well-organized API to your users that is straightforward -to use and only exposes exactly what your users will need, let’s now turn to -Rust’s modules. +使用するのに率直な整理整頓されたAPIをユーザに提供し、ユーザが必要とするものだけを公開するために、 +今度は、Rustのモジュールに目を向けてみましょう。 From 5a7bbc0dc9f0f92196f8fac10e0003f16885b6f6 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 17 Jul 2017 21:25:21 +0900 Subject: [PATCH 011/428] Add some statements on README.md --- README.md | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 506eb0ab2..31ca90500 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,57 @@ このリポジトリには、Rust本第1版と第2版両方がありますが、今回は第2版のみの翻訳です。 第1版以上に、量が多そうなので、大変そうですが、以下の2点を重視して翻訳していきます。 -* 逐語訳に拘らず、読者にとってわかりやすい訳を目指す(適宜、脚注を挟むなど) +* 逐語訳に拘らず、読者にとってわかりやすい訳を目指す(適宜、脚注を挟む、文意に沿った訳語を選択するなど) * 原文の語順を極力尊重する。(..., like so)みたいな句を文中に持っていかず、(...。こんな感じに) のような形で訳す。つまり、ですます調で訳しますが、あまり堅すぎる文章にはしたくないという意図です 僭越ながら、頑張りますので、よろしくお願いいたします。 +κeenさん作成の、第1版の[対訳表][translation-table]を参考に翻訳を進めますが、上記の方針により、 +その通りになるとは限りません。 + +以下、[κeenさんのCONTRIBUTING.md][contributing]より引用、加筆修正したものを掲載します。 + +## 翻訳時の指針 + +### 書式類 + +* `mdbook`の仕様上、英文をコメントアウトして直下に1行空けてから、和訳を書く + * ただし、先頭が%で始まるタイトルだけはrustbookの制約の関係上、原文を直下に置く +* 1パラグラフ単位で翻訳する +* ただし、rustのコードブロック(バッククォート3つで始まる別行立てのもの)中のコメントについてはコピペして原文をコメントアウトし、 +日本語訳が後に来るようにする。 + * コードのブロック内の文字列に含まれる英文は、1行上にコメント形式で和訳を記す + * テキストコードブロックは、基本的に1行下にカッコ書きで和訳を書き記す +* 標準ライブラリのリファレンスへのリンクは相対リンクのままとして、英語版から変更しない +* クォート(')やダブルクォート(")は鉤括弧(「」)にする + * ただし、原文をそのまま引用する場合は、`"`にする +* 句読点には、。を、感嘆符は全角のエクスクラメーションマーク(!)を、疑問符は全角のクエスチョンマーク(?)を用いる。 +これらの記号の後にスペースは入れない(See Issue #82)。 +* 括弧は基本的に半角の`(`と`)`を使用する +* どんなに1行が長くなっても日本語の文の途中で改行しない。レンダリングで余計な空白が入ってしまう。句点(。)、最悪でも読点(、)の後で改行する。 +* Markdownのマークアップ記法の前後は空白/空行を空けることを基本とするが、厳密でなくてもよい。 空白/空行を空けなくても処理出来るかはrustbookの気分にかなりよるので統一的に空白を空ける。 +* 訳注を入れる際はインラインなら(訳注: ...)のようにし、別行なら > 訳注: ... のように囲み形式にする +### 日本語 + +* 敬体を基本とする +* 用語の訳は対訳表に従う +* 用語や厳密な意味論を話してる部分以外はある程度は意訳でよい + * むしろ意訳の方が多いので、注意 + * 同じ単語の連続使用はカッコ悪く飽きる原因になるので、同じ単語でも訳が違う場合があります +* むしろ変に原文に忠実で、日本語として読みづらいよりも意味が伝わって日本語として分かりやすい方がいい。 + * ただし元の英文の意味と異なる場合(誤訳の場合)は修正が入る +* 継続用法の関係代名詞やコロン(:)、セミコロン(;)など日本語と対応取りづらい文は無理に1文に詰めず、2文に分けてもよい。 また、継続用法の関係代名詞でも限定修飾のように訳してもよい(日本語でどちらの意味にも読み取れるため。英語のテストでないので読み手の好意的解釈をあてにしてよい。) + * `..., ~ing ...`などの文は、文意によって2文に分けて訳しています + * 逆に原文では2文のものを、1文の和訳にしているケースもあります +* 英語だとit, thatなどの指示語が多用されるが日本語だと繰り返した方が自然なことが多いので無理に指示語を使わずに自然な方を使う +* theに関しては文意によって(`この`、`その`)などと訳出していることがあります。(`a`も同様) +* 逆にyou, your, we, ourなどの英語の文法上仕方なく出てくる人称代名詞は日本語には訳さない方が自然なことが多いので無理に訳に出さない。 特に、一般論を語る時のyouは 訳してはならない 参考 【雑談】"あなた"と訳さない"you" ~ einzelzelle + * (こんな訳し方はしないので、大丈夫です) + +[translation-table]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/TranslationTable.md +[contributing]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/CONTRIBUTING.md + # The Rust Programming Language [![Build Status](https://travis-ci.org/rust-lang/book.svg?branch=master)](https://travis-ci.org/rust-lang/book) From 12917b2ac2a950b07d37f131e6c7a1dd967103b6 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 17 Jul 2017 21:37:08 +0900 Subject: [PATCH 012/428] Fix some lines --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 31ca90500..5ae114c0b 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ これらの記号の後にスペースは入れない(See Issue #82)。 * 括弧は基本的に半角の`(`と`)`を使用する * どんなに1行が長くなっても日本語の文の途中で改行しない。レンダリングで余計な空白が入ってしまう。句点(。)、最悪でも読点(、)の後で改行する。 -* Markdownのマークアップ記法の前後は空白/空行を空けることを基本とするが、厳密でなくてもよい。 空白/空行を空けなくても処理出来るかはrustbookの気分にかなりよるので統一的に空白を空ける。 +* 空白/空行を空けなくても処理出来るかはrustbookの気分にかなりよるので統一的に空白を空ける。 * 訳注を入れる際はインラインなら(訳注: ...)のようにし、別行なら > 訳注: ... のように囲み形式にする ### 日本語 @@ -46,6 +46,7 @@ * 継続用法の関係代名詞やコロン(:)、セミコロン(;)など日本語と対応取りづらい文は無理に1文に詰めず、2文に分けてもよい。 また、継続用法の関係代名詞でも限定修飾のように訳してもよい(日本語でどちらの意味にも読み取れるため。英語のテストでないので読み手の好意的解釈をあてにしてよい。) * `..., ~ing ...`などの文は、文意によって2文に分けて訳しています * 逆に原文では2文のものを、1文の和訳にしているケースもあります + * `:`、`;`は基本的に変更せずそのままにするが、`;`は意味が伝わりづらいと考えられるので、可能ならば`つまり`などと訳出して、削除する * 英語だとit, thatなどの指示語が多用されるが日本語だと繰り返した方が自然なことが多いので無理に指示語を使わずに自然な方を使う * theに関しては文意によって(`この`、`その`)などと訳出していることがあります。(`a`も同様) * 逆にyou, your, we, ourなどの英語の文法上仕方なく出てくる人称代名詞は日本語には訳さない方が自然なことが多いので無理に訳に出さない。 特に、一般論を語る時のyouは 訳してはならない 参考 【雑談】"あなた"と訳さない"you" ~ einzelzelle From cd79b000bea48371d086c4a14a6f1300fca2c9db Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 6 Aug 2017 22:20:48 +0900 Subject: [PATCH 013/428] First draft of the chapter 5-0 --- second-edition/src/ch05-00-structs.md | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/second-edition/src/ch05-00-structs.md b/second-edition/src/ch05-00-structs.md index 46bc5a834..410b95b83 100644 --- a/second-edition/src/ch05-00-structs.md +++ b/second-edition/src/ch05-00-structs.md @@ -1,11 +1,19 @@ -# Using Structs to Structure Related Data + -A *struct*, or *structure*, is a custom data type that lets us name and package -together multiple related values that make up a meaningful group. If you’re -familiar with an object-oriented language, a *struct* is like an object’s data -attributes. In this chapter, we’ll compare and contrast tuples with structs, -demonstrate how to use structs, and discuss how to define methods and -associated functions on structs to specify behavior associated with a struct’s -data. The struct and *enum* (which is discussed in Chapter 6) concepts are the -building blocks for creating new types in your program’s domain to take full -advantage of Rust’s compile time type checking. +# 構造体を使用して関係のあるデータを構造化する + + + + + + + + + + + +*struct*または、*構造体*は、意味のあるグループを形成する複数の関連した値をまとめ、名前付けできる独自のデータ型です。 +オブジェクト指向言語に造詣が深いなら、*struct*はオブジェクトのデータ属性みたいなものです。 +この章では、タプルと構造体を対照的に比較し、構造体の使用法をデモし、構造体にメソッドや関連関数を定義して、 +構造体のデータに紐付く振る舞いを指定する方法について議論します。構造体と*enum*(こちらは第6章で議論します)の概念は、 +自分のプログラム領域で新しい型を定義し、Rustのコンパイル時型精査機能をフル活用する構成要素になります。 From 34b8c1380597a7fac707c00e310d570d9fad05ab Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 6 Aug 2017 23:51:16 +0900 Subject: [PATCH 014/428] First draft of the chapter 5-1 --- .../src/ch05-01-defining-structs.md | 329 ++++++++++++------ 1 file changed, 226 insertions(+), 103 deletions(-) diff --git a/second-edition/src/ch05-01-defining-structs.md b/second-edition/src/ch05-01-defining-structs.md index 5811fdc18..b02be58f0 100644 --- a/second-edition/src/ch05-01-defining-structs.md +++ b/second-edition/src/ch05-01-defining-structs.md @@ -1,16 +1,20 @@ -## Defining and Instantiating Structs + -Structs are similar to tuples, which were discussed in Chapter 3. Like tuples, -the pieces of a struct can be different types. Unlike tuples, we name each -piece of data so it’s clear what the values mean. As a result of these names, -structs are more flexible than tuples: we don’t have to rely on the order of -the data to specify or access the values of an instance. +## 構造体を定義し、インスタンス化する -To define a struct, we enter the keyword `struct` and name the entire struct. A -struct’s name should describe the significance of the pieces of data being -grouped together. Then, inside curly braces, we define the names and types of -the pieces of data, which we call *fields*. For example, Listing 5-1 shows a -struct to store information about a user account: + + + + + + + + + + + + + ```rust struct User { @@ -21,17 +25,26 @@ struct User { } ``` -Listing 5-1: A `User` struct definition + -To use a struct after we’ve defined it, we create an *instance* of that struct -by specifying concrete values for each of the fields. We create an instance by -stating the name of the struct, and then add curly braces containing `key: -value` pairs where the keys are the names of the fields and the values are the -data we want to store in those fields. We don’t have to specify the fields in -the same order in which we declared them in the struct. In other words, the -struct definition is like a general template for the type, and instances fill -in that template with particular data to create values of the type. For -example, we can declare a particular user as shown in Listing 5-2: +リスト5-1: `User`構造体定義 + + + + + + + + + + + +構造体を定義した後に使用するには、各フィールドに対して確固たる値を指定して構造体の*インスタンス*を生成します。 +インスタンスは、構造体名を記述し、`key: value`ペアを含む波かっこを付け加えることで生成します。 +ここで、キーはフィールド名、値はそのフィールドに格納したいデータになります。フィールドは、 +構造体で定義した時通りの順番に指定する必要はありません。換言すると、構造体定義とは、 +型に対する一般的な雛形のようなものであり、インスタンスは、その雛形を特定のデータで埋め、その型の値を生成するわけです。 +例えば、リスト5-2で示されたように特定のユーザを宣言することができます。 ```rust # struct User { @@ -49,14 +62,21 @@ let user1 = User { }; ``` -Listing 5-2: Creating an instance of the `User` -struct + + + +リスト5-2: `User`構造体のインスタンスを生成する -To get a specific value from a struct, we can use dot notation. If we wanted -just this user’s email address, we can use `user1.email` wherever we want to -use this value. To change a value in a struct, if the instance is mutable, we -can use the dot notation and assign into a particular field. Listing 5-3 shows -how to change the value in the `email` field of a mutable `User` instance: + + + + + + +構造体から特定の値を得るには、ドット記法が使えます。このユーザのEメールアドレスだけが欲しいなら、 +この値を使いたい場所全部で`user1.email`が使えます。構造体の値を変更するには、インスタンスが可変であれば、 +ドット記法を使い特定のフィールドに代入することができます。リスト5-3では、 +可変な`User`インスタンスの`email`フィールド値を変更する方法を示しています: ```rust # struct User { @@ -76,17 +96,26 @@ let mut user1 = User { user1.email = String::from("anotheremail@example.com"); ``` -Listing 5-3: Changing the value in the `email` field of a -`User` instance + + + +リスト5-3: ある`User`インスタンスの`email`フィールド値を変更する + + -### Field Init Shorthand when Variables Have the Same Name as Fields +### フィールドと同名の変数があるときのフィールド初期化省略記法 -If you have variables with the same names as struct fields, you can use *field -init shorthand*. This can make functions that create new instances of structs -more concise. First, let’s look at the more verbose way to initialize a struct -instance. The function named `build_user` shown here in Listing 5-4 has -parameters named `email` and `username`. The function creates and returns a -`User` instance: + + + + + + + +構造体のフィールドと同名の変数がある場合、*フィールド初期化省略記法*を使用することができます。 +これにより、構造体の新規インスタンスを生成する関数をより簡潔にすることができます。 +まず、構造体インスタンスを初期化する、より冗長的な方法を見てみましょう。リスト5-4で示されている`build_user`という名前の関数には、 +`email`と`username`という引数があります。この関数は、`User`インスタンスを生成して返します: ```rust # struct User { @@ -106,15 +135,22 @@ fn build_user(email: String, username: String) -> User { } ``` -Listing 5-4: A `build_user` function that takes an email -and username and returns a `User` instance + + + +リスト5-4: Eメールとユーザ名を取り、`User`インスタンスを返す`build_user`関数 + + + + + + + -Because the parameter names `email` and `username` are the same as the `User` -struct’s field names `email` and `username`, we can write `build_user` without -the repetition of `email` and `username` as shown in Listing 5-5. This version -of `build_user` behaves the same way as the one in Listing 5-4. The field init -syntax can make cases like this shorter to write, especially when structs have -many fields. +`email`と`username`という引数名と、`email`と`username`という`User`構造体のフィールド名が同じなので、 +リスト5-5に示したように、`email`と`username`を繰り返すことなく`build_user`を書くことができます。 +このバージョンの`build_user`もリスト5-4のものと同じように振る舞います。フィールド初期化記法は、 +今回のようなケース(特に構造体に多くのフィールドがあるとき)を短く書けるようにします。 ```rust # struct User { @@ -134,17 +170,26 @@ fn build_user(email: String, username: String) -> User { } ``` -Listing 5-5: A `build_user` function that uses field init -syntax since the `email` and `username` parameters have the same name as struct -fields + + + -### Creating Instances From Other Instances With Struct Update Syntax +リスト5-5: `email`と`username`引数が構造体のフィールドと同名なので、 +フィールド初期化記法を使用する`build_user`関数 -It’s often useful to create a new instance from an old instance, using most of -the old instance’s values but changing some. Listing 5-6 shows an example of -creating a new `User` instance in `user2` by setting the values of `email` and -`username` but using the same values for the rest of the fields from the -`user1` instance we created in Listing 5-2: + + +### 構造体更新記法で他のインスタンスからインスタンスを生成する + + + + + + + +多くは古いインスタンスの値を使いつつ、変更する箇所もある形で、古いインスタンスから新しいインスタンスを生成できると、 +しばしば有用なわけです。リスト5-6では、`email`と`username`の値をセットしつつ、残りのフィールドにはリスト5-2で生成した、 +`User1`インスタンスと同じ値を使って、`user2`に新規`User`インスタンスを生成する例を示しました。 ```rust # struct User { @@ -169,15 +214,23 @@ let user2 = User { }; ``` -Listing 5-6: Creating a new `User` instance, `user2`, and -setting some fields to the values of the same fields from `user1` + + -The *struct update syntax* achieves the same effect as the code in Listing 5-6 -using less code. The struct update syntax uses `..` to specify that the -remaining fields not set explicitly should have the same value as the fields in -the given instance. The code in Listing 5-7 also creates an instance in `user2` -that has a different value for `email` and `username` but has the same values -for the `active` and `sign_in_count` fields that `user1` has: +リスト5-6: 新しい`User`インスタンス、`user2`を生成し、 + 一部のフィールドを`user1`と同じ値にセットする + + + + + + + + +*構造体更新記法*は、リスト5-6のコードと同じ効果を達成しつつ、コード量を減らせます。構造体更新記法は、 +`..`を使い、明示的にセットされていない残りのフィールドが与えられたインスタンスの値と同じになるように指定します。 +リスト5-7のコードも、`email`と`username`の値は異なり、`active`と`sign_in_count`の値は、 +`user1`と同じになる`user2`というインスタンスを生成します。 ```rust # struct User { @@ -201,18 +254,27 @@ let user2 = User { }; ``` -Listing 5-7: Using struct update syntax to set a new -`email` and `username` values for a `User` instance but use the rest of the -values from the fields of the instance in the `user1` variable + + + + +リスト5-7: 構造体更新記法を使用して、新しい`User`インスタンス用の値に新しい`email`と`username`をセットしつつ、 +残りの値は、`user1`変数のフィールド値を使う -### Tuple Structs without Named Fields to Create Different Types + -We can also define structs that look similar to tuples, called *tuple structs*, -that have the added meaning the struct name provides, but don’t have names -associated with their fields, just the types of the fields. The definition of a -tuple struct still starts with the `struct` keyword and the struct name, which -are followed by the types in the tuple. For example, here are definitions and -usages of tuple structs named `Color` and `Point`: +### 異なる型を生成する名前付きフィールドのないタプル構造体 + + + + + + + + +構造体名により追加の意味を含むものの、フィールドに紐づけられた名前がなく、フィールドの型だけの*タプル構造体*と呼ばれる、 +タプルに似た構造体を定義することもできます。タプル構造体の定義も`struct`キーワードと構造体名から始まり、 +タプルに含まれる型が続きます。例として、こちらは、`Color`と`Point`という名前のタプル構造体の定義と使用法です: ```rust struct Color(i32, i32, i32); @@ -222,33 +284,95 @@ let black = Color(0, 0, 0); let origin = Point(0, 0, 0); ``` -Note that the `black` and `origin` values are different types, since they’re -instances of different tuple structs. Each struct we define is its own type, -even though the fields within the struct have the same types. Otherwise, tuple -struct instances behave like tuples, which we covered in Chapter 3. - -### Unit-Like Structs without Any Fields - -We can also define structs that don’t have any fields! These are called -*unit-like structs* since they behave similarly to `()`, the unit type. -Unit-like structs can be useful in situations such as when you need to -implement a trait on some type, but you don’t have any data that you want to -store in the type itself. We’ll be discussing traits in Chapter 10. - -> ### Ownership of Struct Data + + + + + +`black`と`origin`の値は、違う型であることに注目してください。これらは、異なるタプル構造体のインスタンスだからですね。 +定義された各構造体は、構造体内のフィールドが同じ型であっても、それ自身が独自の型になります。 +それ以外については、タプル構造体のインスタンスは、第3章で解説したタプルと同じように振る舞います。 + + + +### フィールドのないユニット様構造体 + + + + + + + +また、一切フィールドのない構造体を定義することもできます!これらは、`()`、ユニット型と似た様な振る舞いをすることから、 +*ユニット様(よう)構造体*と呼ばれます。ユニット様構造体は、ある型にトレイトを実装するけれども、 +型自体に保持させるデータは一切ないような場合に有効になります。トレイトについては第10章で議論します。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +> ### 構造体データの所有権 > -> In the `User` struct definition in Listing 5-1, we used the owned `String` -> type rather than the `&str` string slice type. This is a deliberate choice -> because we want instances of this struct to own all of its data and for that -> data to be valid for as long as the entire struct is valid. +> リスト5-1の`User`構造体定義において、`&str`文字列スライス型ではなく、所有権のある`String`型を使用しました。 +> これは意図的な選択であり、この構造体のインスタンスには全データを所有してもらう必要があり、 +> このデータは、構造体全体が有効な間はずっと有効である必要があるのです。 > -> It’s possible for structs to store references to data owned by something else, -> but to do so requires the use of *lifetimes*, a Rust feature that is discussed -> in Chapter 10. Lifetimes ensure that the data referenced by a struct is valid -> for as long as the struct is. Let’s say you try to store a reference in a -> struct without specifying lifetimes, like this: +> 構造体に、他の何かに所有されたデータへの参照を保持させることもできますが、 +> そうするには*ライフタイム*という第10章で議論されるRustの機能を使用しなければなりません。 +> ライフタイムのおかげで構造体に参照されたデータが、構造体自体が有効な間ずっと有効であることを保証してくれるのです。 +> ライフタイムを指定せずに構造体に参照を保持させようとしたとしましょう。このように: > -> Filename: src/main.rs +> ファイル名: src/main.rs > > ```rust,ignore > struct User { @@ -268,22 +392,21 @@ store in the type itself. We’ll be discussing traits in Chapter 10. > } > ``` > -> The compiler will complain that it needs lifetime specifiers: -> +> コンパイラは、ライフタイム指定子が必要だと怒るでしょう: > ```text > error[E0106]: missing lifetime specifier +> (エラー: ライフタイム指定子がありません) > --> -> | +> | > 2 | username: &str, > | ^ expected lifetime parameter > > error[E0106]: missing lifetime specifier > --> -> | +> | > 3 | email: &str, > | ^ expected lifetime parameter > ``` > -> We’ll discuss how to fix these errors so you can store references in structs -> in Chapter 10, but for now, we’ll fix errors like these using owned types like -> `String` instead of references like `&str`. +> これらのエラーを解消して構造体に参照を保持する方法については、第10章で議論しますが、 +> 当面、今回のようなエラーは、`&str`のような参照の代わりに、`String`のような所有された型を使うことで解消します。 From 4ae66ff50bc44fee1e57eb7e8f4c57f71597f10c Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 7 Aug 2017 20:32:54 +0900 Subject: [PATCH 015/428] First drafts of the chapters 5-2 and 5-3 --- .../src/ch05-01-defining-structs.md | 18 +- second-edition/src/ch05-02-example-structs.md | 349 ++++++++++----- second-edition/src/ch05-03-method-syntax.md | 423 ++++++++++++------ 3 files changed, 539 insertions(+), 251 deletions(-) diff --git a/second-edition/src/ch05-01-defining-structs.md b/second-edition/src/ch05-01-defining-structs.md index b02be58f0..7bec3fda0 100644 --- a/second-edition/src/ch05-01-defining-structs.md +++ b/second-edition/src/ch05-01-defining-structs.md @@ -8,7 +8,10 @@ - +構造体は第3章で議論したタプルと似ています。タプル同様、構造体の一部を異なる型にできます。 +一方タプルとは違って、各データ片には名前をつけるので、値の意味が明確になります。 +この名前のおかげで、構造体はタプルに比して、より柔軟になるわけです: データの順番に頼って、 +インスタンスの値を指定したり、アクセスしたりする必要がないのです。 @@ -16,6 +19,11 @@ +構造体の定義は、`struct`キーワードを入れ、構造体全体に名前を付けます。構造体名は、 +一つにグループ化されるデータ片の意義を表すものであるべきです。そして、波かっこ内に、 +データ片の名前と型を定義し、これは*フィールド*と呼ばれます。例えば、リスト5-1では、 +ユーザアカウントに関する情報を保持する構造体を示しています: + ```rust struct User { username: String, @@ -39,7 +47,7 @@ struct User { -構造体を定義した後に使用するには、各フィールドに対して確固たる値を指定して構造体の*インスタンス*を生成します。 +構造体を定義した後に使用するには、各フィールドに対して具体的な値を指定して構造体の*インスタンス*を生成します。 インスタンスは、構造体名を記述し、`key: value`ペアを含む波かっこを付け加えることで生成します。 ここで、キーはフィールド名、値はそのフィールドに格納したいデータになります。フィールドは、 構造体で定義した時通りの順番に指定する必要はありません。換言すると、構造体定義とは、 @@ -187,7 +195,7 @@ fn build_user(email: String, username: String) -> User { -多くは古いインスタンスの値を使いつつ、変更する箇所もある形で、古いインスタンスから新しいインスタンスを生成できると、 +大部分は古いインスタンスの値を使いつつ、変更する箇所もある形で、古いインスタンスから新しいインスタンスを生成できると、 しばしば有用なわけです。リスト5-6では、`email`と`username`の値をセットしつつ、残りのフィールドにはリスト5-2で生成した、 `User1`インスタンスと同じ値を使って、`user2`に新規`User`インスタンスを生成する例を示しました。 @@ -303,7 +311,7 @@ let origin = Point(0, 0, 0); -また、一切フィールドのない構造体を定義することもできます!これらは、`()`、ユニット型と似た様な振る舞いをすることから、 +また、一切フィールドのない構造体を定義することもできます!これらは、`()`、ユニット型と似たような振る舞いをすることから、 *ユニット様(よう)構造体*と呼ばれます。ユニット様構造体は、ある型にトレイトを実装するけれども、 型自体に保持させるデータは一切ないような場合に有効になります。トレイトについては第10章で議論します。 @@ -364,7 +372,7 @@ let origin = Point(0, 0, 0); > ### 構造体データの所有権 > > リスト5-1の`User`構造体定義において、`&str`文字列スライス型ではなく、所有権のある`String`型を使用しました。 -> これは意図的な選択であり、この構造体のインスタンスには全データを所有してもらう必要があり、 +> これは意図的な選択です。というのも、この構造体のインスタンスには全データを所有してもらう必要があり、 > このデータは、構造体全体が有効な間はずっと有効である必要があるのです。 > > 構造体に、他の何かに所有されたデータへの参照を保持させることもできますが、 diff --git a/second-edition/src/ch05-02-example-structs.md b/second-edition/src/ch05-02-example-structs.md index 70e4b1e21..edb659619 100644 --- a/second-edition/src/ch05-02-example-structs.md +++ b/second-edition/src/ch05-02-example-structs.md @@ -1,21 +1,33 @@ -## An Example Program Using Structs + -To understand when we might want to use structs, let’s write a program that -calculates the area of a rectangle. We’ll start with single variables, and then -refactor the program until we’re using structs instead. +## 構造体を使ったプログラム例 -Let’s make a new binary project with Cargo called *rectangles* that will take -the length and width of a rectangle specified in pixels and will calculate the -area of the rectangle. Listing 5-8 shows a short program with one way of doing -just that in our project’s *src/main.rs*: + + + -Filename: src/main.rs +構造体を使用したくなる可能性のあるケースを理解するために、四角形の面積を求めるプログラムを書きましょう。 +単一の変数から始め、代わりに構造体を使うようにプログラムをリファクタリングします。 + + + + + + +Cargoで*rectangles*という新規バイナリプロジェクトを作成しましょう。このプロジェクトは、 +四角形の長さと幅をピクセルで指定し、その面積を求めます。リスト5-8に、プロジェクトの*src/main.rs*で、 +そうする一例を短いプログラムとして示しました。 + + + +ファイル名: src/main.rs ```rust fn main() { let length1 = 50; let width1 = 30; + // 四角形の面積は、{}平方ピクセルです println!( "The area of the rectangle is {} square pixels.", area(length1, width1) @@ -27,37 +39,57 @@ fn area(length: u32, width: u32) -> u32 { } ``` -Listing 5-8: Calculating the area of a rectangle -specified by its length and width in separate variables + + + +リスト5-8: 個別の変数で長さと幅を指定して四角形の面積を求める -Now, run this program using `cargo run`: + + +では、`cargo run`でこのプログラムを走らせてください: ```text The area of the rectangle is 1500 square pixels. +(四角形の面積は、1500平方ピクセルです) ``` -### Refactoring with Tuples + + +### タプルでリファクタリングする + + + + + -Even though Listing 5-8 works and figures out the area of the rectangle by -calling the `area` function with each dimension, we can do better. The length -and the width are related to each other because together they describe one -rectangle. +リスト5-8のコードはうまく動き、各次元で`area`関数を呼び出すことで四角形の面積を割り出しますが、 +改善点があります。長さと幅は、組み合わせると一つの四角形を表すので、相互に関係があるわけです。 -The issue with this method is evident in the signature of `area`: + + +この方法の問題点は、`area`のシグニチャから明らかです: ```rust,ignore fn area(length: u32, width: u32) -> u32 { ``` -The `area` function is supposed to calculate the area of one rectangle, but the -function we wrote has two parameters. The parameters are related, but that’s -not expressed anywhere in our program. It would be more readable and more -manageable to group length and width together. We’ve already discussed one way -we might do that in the Grouping Values into Tuples section of Chapter 3 on -page XX: by using tuples. Listing 5-9 shows another version of our program that -uses tuples: + + + + + + + + +`area`関数は、1四角形の面積を求めるものと考えられますが、今書いた関数には、引数が2つあります。 +引数は関連性があるのに、このプログラム内のどこにもそのことは表現されていません。 +長さと幅を一緒にグループ化する方が、より読みやすく、扱いやすくなるでしょう。 +それをする一つの方法については、ページXXの第3章の「値をタプルにまとめ上げる」節ですでに議論しました: +タプルを使うのです。リスト5-9に、タプルを使う別バージョンのプログラムを示します: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust fn main() { @@ -74,29 +106,48 @@ fn area(dimensions: (u32, u32)) -> u32 { } ``` -Listing 5-8: Specifying the length and width of the -rectangle with a tuple + + + +リスト5-8: タプルで四角形の長さと幅を指定する + + + + + + +ある意味では、このプログラムはマシです。タプルのおかげで少し構造的になり、一引数を渡すだけになりました。 +しかし別の意味では、このバージョンは明確性を失っています: タプルは要素に名前を付けないので、 +計算が不明瞭になったのです。なぜなら、タプルの一部に添え字アクセスする必要があるからです。 + + + + + + + + -In one way, this program is better. Tuples let us add a bit of structure, and -we’re now passing just one argument. But in another way this version is less -clear: tuples don’t name their elements, so our calculation has become more -confusing because we have to index into the parts of the tuple. +面積計算で長さと幅を混在させるのなら問題はないのですが、四角形を画面に描画したいとなると、問題になるのです! +タプルの添え字`0`が`長さ`で、添え字`1`が`幅`であることを肝に命じておかなければなりません。 +他人がこのコードをいじることになったら、このことを割り出し、同様に肝に命じなければならないでしょう。 +容易く、このことを忘れ、これらの値を混ぜこぜにしてエラーを発生させてしまうでしょう。 +データの意味をコードに載せていないからです。 -It doesn’t matter if we mix up length and width for the area calculation, but -if we want to draw the rectangle on the screen, it would matter! We would have -to keep in mind that `length` is the tuple index `0` and `width` is the tuple -index `1`. If someone else worked on this code, they would have to figure this -out and keep it in mind as well. It would be easy to forget or mix up these -values and cause errors, because we haven’t conveyed the meaning of our data in -our code. + -### Refactoring with Structs: Adding More Meaning +### 構造体でリファクタリングする: より意味付けする -We use structs to add meaning by labeling the data. We can transform the tuple -we’re using into a data type with a name for the whole as well as names for the -parts, as shown in Listing 5-10: + + + -Filename: src/main.rs +データにラベル付けをして意味付けを行い、構造体を使います。現在使用しているタプルを全体と一部に名前のあるデータ型に、 +変形することができます。そう、リスト5-10に示したように: + + + +ファイル名: src/main.rs ```rust struct Rectangle { @@ -118,35 +169,57 @@ fn area(rectangle: &Rectangle) -> u32 { } ``` -Listing 5-10: Defining a `Rectangle` struct + + +リスト5-10: `Rectangle`構造体を定義する + + + + + -Here we’ve defined a struct and named it `Rectangle`. Inside the `{}` we -defined the fields as `length` and `width`, both of which have type `u32`. Then -in `main` we create a particular instance of a `Rectangle` that has a length of -50 and a width of 30. +ここでは、構造体を定義し、`Rectangle`という名前にしています。`{}`の中で`length`と`width`というフィールドを定義し、 +`u32`という型にしました。それから`main`内で`Rectangle`の特定のインスタンスを生成し、 +長さを50、幅を30にしました。 -Our `area` function is now defined with one parameter, which we’ve named -`rectangle`, whose type is an immutable borrow of a struct `Rectangle` -instance. As mentioned in Chapter 4, we want to borrow the struct rather than -take ownership of it. This way, `main` retains its ownership and can continue -using `rect1`, which is the reason we use the `&` in the function signature and -where we call the function. + + + + + + -The `area` function accesses the `length` and `width` fields of the `Rectangle` -instance. Our function signature for `area` now indicates exactly what we mean: -calculate the area of a `Rectangle` using its `length` and `width` fields. This -conveys that the length and width are related to each other, and gives -descriptive names to the values rather than using the tuple index values of `0` -and `1`—a win for clarity. +これで`area`関数は引数が一つになり、この引数は名前が`rectangle`、型は`Rectangle`構造体インスタンスへの不変参照になりました。 +第4章で触れたように、構造体の所有権を奪うよりも借用する必要があります。こうすることで`main`は所有権を保って、 +`rect1`を使用し続けることができ、そのために関数シグニチャと関数呼び出し時に`&`を使っているわけです。 -### Adding Useful Functionality with Derived Traits + + + + + + -It would be helpful to be able to print out an instance of the `Rectangle` -while we’re debugging our program in order to see the values for all its -fields. Listing 5-11 uses the `println!` macro as we have been in earlier -chapters: +`area`関数は、`Rectangle`インスタンスの`length`と`width`フィールドにアクセスしています。 +これで、`area`の関数シグニチャは、我々の意図をズバリ示すようになりました: `length`と`width`フィールドを使って、 +`Rectangle`の面積を計算します。これにより、長さと幅が相互に関係していることが伝わり、 +タプルの`0`や`1`という添え字を使うのではなく、値に説明的な名前を与えられるのです。簡潔性を勝ち取ったわけですね。 -Filename: src/main.rs + + +### トレイトの継承で有用な機能を追加する + + + + + + +プログラムのデバッグ中、フィールドの値を調べる目的で`Rectangle`のインスタンスを出力できると、 +助かるでしょう。リスト5-11では、以前の章でしたように、`println!`マクロを使用しています: + + + +ファイル名: src/main.rs ```rust,ignore struct Rectangle { @@ -157,61 +230,96 @@ struct Rectangle { fn main() { let rect1 = Rectangle { length: 50, width: 30 }; + // rect1は{}です println!("rect1 is {}", rect1); } ``` -Listing 5-11: Attempting to print a `Rectangle` -instance + + -When we run this code, we get an error with this core message: +リスト5-11: `Rectangle`のインスタンスを出力しようとする + + + +このコードを走らせると、こんな感じのエラーが出ます: ```text error[E0277]: the trait bound `Rectangle: std::fmt::Display` is not satisfied +(エラー: トレイト境界`Rectangle: std::fmt::Display`が満たされていません) ``` -The `println!` macro can do many kinds of formatting, and by default, `{}` -tells `println!` to use formatting known as `Display`: output intended for -direct end user consumption. The primitive types we’ve seen so far implement -`Display` by default, because there’s only one way you’d want to show a `1` or -any other primitive type to a user. But with structs, the way `println!` should -format the output is less clear because there are more display possibilities: -do you want commas or not? Do you want to print the curly braces? Should all -the fields be shown? Due to this ambiguity, Rust doesn’t try to guess what we -want and structs don’t have a provided implementation of `Display`. + + + + + + + + + + +`println!`マクロには、様々な整形があり、標準では、`{}`は`Display`として知られる整形をするよう、 +`println!`に指示するのです: 直接エンドユーザ向けの出力です。これまでに見てきた基本型は、 +標準で`Display`を実装しています。というのも、`1`や他の基本型をユーザに見せる方法は一つしかないからです。 +しかし構造体では、`println!`が出力を整形する方法は自明ではなくなります。出力方法がいくつもあるからです: +カンマは必要なの?波かっこを出力する必要はある?全フィールドが見えるべき?この曖昧性のため、 +Rustは必要なものを推測しようとせず、構造体には`Display`実装が提供されないのです。 + + -If we continue reading the errors, we’ll find this helpful note: +エラーを読み下すと、こんな有益な注意書きがあります: ```text note: `Rectangle` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string +(注釈: `Rectangle`は、デフォルト整形機では、整形できません; フォーマット文字列を使うのなら +代わりに`:?`を試してみてください) ``` -Let’s try it! The `println!` macro call will now look like `println!("rect1 is -{:?}", rect1);`. Putting the specifier `:?` inside the `{}` tells `println!` we -want to use an output format called `Debug`. `Debug` is a trait that enables us -to print out our struct in a way that is useful for developers so we can see -its value while we’re debugging our code. + + + + + -Run the code with this change. Drat! We still get an error: +試してみましょう!`pritnln!`マクロ呼び出しは、`println!("rect1 is {:?}", rect1);`という見た目になるでしょう。 +`{}`内に`:?`という指定子を書くと、`println!`に`Debug`と呼ばれる出力整形を使いたいと指示するのです。 +`Debug`とは、開発者にとって有用な方法で構造体を出力させてくれるトレイトなので、 +コードをデバッグしている最中に、値を確認することができます。 + + + +変更してコードを走らせてください。なに!まだエラーが出ます: ```text error: the trait bound `Rectangle: std::fmt::Debug` is not satisfied +(エラー: トレイト境界`Rectangle: std::fmt::Debug`は満たされていません) ``` -But again, the compiler gives us a helpful note: + + +しかし今回も、コンパイラは有益な注意書きを残してくれています: ```text note: `Rectangle` cannot be formatted using `:?`; if it is defined in your crate, add `#[derive(Debug)]` or manually implement it +(注釈: `Rectangle`は`:?`を使って整形できません; 自分のクレートで定義しているのなら +`#[derive(Debug)]`を追加するか、手動で実装してください) ``` -Rust *does* include functionality to print out debugging information, but we -have to explicitly opt-in to make that functionality available for our struct. -To do that, we add the annotation `#[derive(Debug)]` just before the struct -definition, as shown in Listing 5-12: + + + + + +*確かに*Rustにはデバッグ用の情報を出力する機能が備わっていますが、この機能を構造体で使えるようにするには、 +明示的な選択が必要なのです。そうするには、構造体定義の直前に`#[derive(Debug)]`という注釈を追加します。 +そう、リスト5-12で示されている通りです: + + -Filename: src/main.rs +ファイル名: src/main.rs ```rust #[derive(Debug)] @@ -227,21 +335,31 @@ fn main() { } ``` -Listing 5-12: Adding the annotation to derive the `Debug` -trait and printing the `Rectangle` instance using debug formatting + + -Now when we run the program, we won’t get any errors and we’ll see the -following output: +リスト5-12: `Debug`トレイトを継承する注釈を追加し、 + `Rectangle`インスタンスをデバッグ用整形機で出力する + + + + +これでプログラムを実行すれば、エラーは出ず、以下のような出力が得られるでしょう: ```text rect1 is Rectangle { length: 50, width: 30 } ``` -Nice! It’s not the prettiest output, but it shows the values of all the fields -for this instance, which would definitely help during debugging. When we have -larger structs, it’s useful to have output that’s a bit easier to read; in -those cases, we can use `{:#?}` instead of `{:?}` in the `println!` string. -When we use the `{:#?}` style in the example, the output will look like this: + + + + + + +素晴らしい!最善の出力ではないものの、このインスタンスの全フィールドの値を出力しているので、 +デバッグ中には間違いなく役に立つでしょう。より大きな構造体があるなら、もう少し読みやすい出力の方が有用です; +そのような場合には、`println!`文字列中の`{:?}`の代わりに`{:#?}`を使うことができます。 +この例で`{:#?}`というスタイルを使用したら、出力は以下のようになるでしょう: ```text rect1 is Rectangle { @@ -250,13 +368,22 @@ rect1 is Rectangle { } ``` -Rust has provided a number of traits for us to use with the `derive` annotation -that can add useful behavior to our custom types. Those traits and their -behaviors are listed in Appendix C. We’ll cover how to implement these traits -with custom behavior as well as how to create your own traits in Chapter 10. - -Our `area` function is very specific: it only computes the area of rectangles. -It would be helpful to tie this behavior more closely to our `Rectangle` -struct, because it won’t work with any other type. Let’s look at how we can -continue to refactor this code by turning the `area` function into an `area` -*method* defined on our `Rectangle` type. + + + + + +Rustには、`derive`注釈で使えるトレイトが多く提供されており、独自の型に有用な振る舞いを追加することができます。 +そのようなトレイトとその振る舞いは、おまけCで一覧になっています。これらのトレイトを独自の動作とともに実装する方法だけでなく、 +独自のトレイトを生成する方法については、第10章で解説します。 + + + + + + + +`area`関数は、非常に特殊です: 四角形の面積を算出するだけです。`Rectangle`構造体とこの動作をより緊密に結び付けられると、 +役に立つでしょう。なぜなら、他のどんな型でもうまく動作しなくなるからです。 +`area`関数を`Rectangle`型に定義された`area`*メソッド*に変形することで、 +このコードをリファクタリングし続けられる方法について見ていきましょう。 diff --git a/second-edition/src/ch05-03-method-syntax.md b/second-edition/src/ch05-03-method-syntax.md index c2fd6b2ea..0e87d2349 100644 --- a/second-edition/src/ch05-03-method-syntax.md +++ b/second-edition/src/ch05-03-method-syntax.md @@ -1,20 +1,34 @@ -## Method Syntax + -*Methods* are similar to functions: they’re declared with the `fn` keyword and -their name, they can have parameters and a return value, and they contain some -code that is run when they’re called from somewhere else. However, methods are -different from functions in that they’re defined within the context of a struct -(or an enum or a trait object, which we cover in Chapters 6 and 17, -respectively), and their first parameter is always `self`, which represents the -instance of the struct the method is being called on. +## メソッド記法 -### Defining Methods + + + + + + + -Let’s change the `area` function that has a `Rectangle` instance as a parameter -and instead make an `area` method defined on the `Rectangle` struct, as shown -in Listing 5-13: +*メソッド*は関数に似ています: `fn`キーワードと名前で宣言されるし、引数と返り値があるし、 +どこか別の場所で呼び出された時に実行されるコードを含みます。ところが、 +メソッドは構造体の文脈(あるいはenumかトレイトオブジェクトの。これらについては各々第6章と17章で解説します)で定義されるという点で、 +関数とは異なり、最初の引数は必ず`self`になり、これはメソッドが呼び出されている構造体インスタンスを表します。 -Filename: src/main.rs + + +### メソッドを定義する + + + + + +`Rectangle`インスタンスを引数に取る`area`関数を変え、代わりに`Rectangle`構造体上に`area`メソッドを作りましょう。 +リスト5-13に示した通りですね: + + + +ファイル名: src/main.rs ```rust #[derive(Debug)] @@ -39,56 +53,126 @@ fn main() { } ``` -Listing 5-13: Defining an `area` method on the -`Rectangle` struct - -To define the function within the context of `Rectangle`, we start an `impl` -(*implementation*) block. Then we move the `area` function within the `impl` -curly braces 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. - -In the signature for `area`, we use `&self` instead of `rectangle: &Rectangle` -because Rust knows the type of `self` is `Rectangle` due to this method being -inside the `impl Rectangle` context. Note that we still need to use the `&` -before `self`, just like we did in `&Rectangle`. Methods can take ownership of -`self`, borrow `self` immutably as we’ve done here, or borrow `self` mutably, -just like any other parameter. - -We’ve chosen `&self` here for the same reason we used `&Rectangle` in the -function version: we don’t want to take ownership, and we just want to read the -data in the struct, not write to it. If we wanted to change the instance that -we’ve called the method on as part of what the method does, we’d use `&mut -self` as the first parameter. Having a method that takes ownership of the -instance by using just `self` as the first parameter is rare; this technique is -usually used when the method transforms `self` into something else and we want -to prevent the caller from using the original instance after the transformation. - -The main benefit of using methods instead of functions, in addition to using -method syntax and not having to repeat the type of `self` in every method’s -signature, is for organization. We’ve put all the things we can do with an -instance of a type in one `impl` block rather than making future users of our -code search for capabilities of `Rectangle` in various places in the library we -provide. - -> ### Where’s the `->` Operator? + + + +リスト5-13: `Rectangle`構造体上に`area`メソッドを定義する + + + + + + + + + + +`Rectangle`の文脈内で関数を定義するには、`impl`(implementation; *実装*)ブロックを始めます。 +それから`area`関数を`impl`の波かっこ内に移動させ、最初の(今回は唯一の)引数をシグニチャ内と本体内全てで`self`に変えます。 +`area`関数を呼び出し、`rect1`を引数として渡す`main`では、代替としてメソッド記法を使用して、 +`Rectangle`インスタンスの`area`メソッドを呼び出せます。メソッド記法は、インスタンスの後に続きます: +ドット、メソッド名、かっこ、そして引数と続くわけです。 + + + + + + + + +`area`のシグニチャでは、`rectangle: &Rectangle`の代わりに`&self`を使用しています。 +というのも、コンパイラは、このメソッドが`impl Rectangle`という文脈内に存在するために、 +`self`の型が`Rectangle`であると把握しているからです。`&Rectangle`と同様に、 +`self`の直前に`&`を使用していることに注意してください。メソッドは、`self`の所有権を奪ったり、 +ここでしているように不変で`self`を借用したり、可変で`self`を借用したりできるのです。 +他の引数と全く同じですね。 + + + + + + + + + + +ここで`&self`を選んでいるのは、関数バージョンで`&Rectangle`を使用していたのと同様の理由です: +所有権はいらず、構造体のデータを読み込みたいだけで、書き込む必要はないわけです。 +メソッドの一部でメソッドを呼び出したインスタンスを変更したかったら、第1引数に`&mut self`を使用するでしょう。 +`self`だけを第1引数にしてインスタンスの所有権を奪うメソッドを定義することは稀です; このテクニックは、 +通常メソッドが`self`を何か別のものに変形し、変形後に呼び出し元が元のインスタンスを使用できないようにしたい場合に使用されます。 + + + + + + + + +関数の代替としてメソッドを使う主な利点は、メソッド記法を使用して全メソッドのシグニチャで`self`の型を繰り返す必要がなくなる以外だと、 +体系化です。コードの将来的な利用者に`Rectangle`の機能を提供しているライブラリ内の各所で探させるのではなく、 +この型のインスタンスでできることを一つの`impl`ブロックにまとめあげています。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +> ### `->`演算子はどこに行ったの? > -> In languages like C++, two different operators are used for calling methods: -> you use `.` if you’re calling a method on the object directly and `->` if -> you’re calling the method on a pointer to the object and need to dereference -> the pointer first. In other words, if `object` is a pointer, -> `object->something()` is similar to `(*object).something()`. +> C++のような言語では、メソッド呼び出しには2種類の異なる演算子が使用されます: +> オブジェクトに対して直接メソッドを呼び出すのなら、`.`を使用するし、オブジェクトのポインタに対してメソッドを呼び出し、 +> 先にポインタを参照外しする必要があるなら、`->`を使用するわけです。 +> 言い換えると、`object`がポインタなら、`object->something()`は、`(*object).something()`と類似するのです。 > -> Rust doesn’t have an equivalent to the `->` operator; instead, Rust has a -> feature called *automatic referencing and dereferencing*. Calling methods is -> one of the few places in Rust that has this behavior. +> Rustには`->`演算子の代わりとなるようなものはありません; その代わり、Rustには、 +> *自動参照および参照外し*という機能があります。Rustにおいてメソッド呼び出しは、 +> この動作が行われる数少ない箇所なのです。 > -> 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: +> 動作方法はこうです: `object.something()`とメソッドを呼び出すと、 +> コンパイラは`object`がメソッドのシグニチャと合致するように、自動で`&`か`&mut`、`*`を付与するのです。 +> 要するに、以下のコードは同じものです: > > ```rust > # #[derive(Debug,Copy,Clone)] @@ -111,23 +195,30 @@ provide. > (&p1).distance(&p2); > ``` > -> 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. +> 前者の方がずっと明確です。メソッドには自明な受け手(`self`の型)がいるので、この自動参照機能は動作するのです。 +> 受け手とメソッド名が与えられれば、コンパイラは確実にメソッドが読み込み専用か、書き込みもするのか、 +> 所有権を奪うのか判断できるわけです。Rustにおいて、メソッドの受け手に関して借用が明示されないという事実は、 +> 所有権を現実世界でプログラマフレンドリーにさせる大部分を占めているのです。 + + -### Methods with More Parameters +### より引数の多いメソッド -Let’s practice using methods by implementing a second method on the `Rectangle` -struct. This time, we want an instance of `Rectangle` to take another instance -of `Rectangle` and return `true` if the second `Rectangle` can fit completely -within `self`; otherwise it should return `false`. That is, we want to be able -to write the program shown in Listing 5-14, once we’ve defined the `can_hold` -method: + + + + + + -Filename: src/main.rs +`Rectangle`構造体に2番目のメソッドを実装して、メソッドを使う鍛錬をしましょう。今回は、`Rectangle`のインスタンスに、 +別の`Rectangle`のインスタンスを取らせ、2番目の`Rectangle`が`self`に完全にはめ込まれたら、`true`を返すようにしたいのです; +そうでなければ、`false`を返すべきです。つまり、一旦`can_hold`メソッドを定義したら、 +リスト5-14のようなプログラムを書けるようになりたいのです: + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -135,38 +226,56 @@ fn main() { let rect2 = Rectangle { length: 40, width: 10 }; let rect3 = Rectangle { length: 45, width: 60 }; + // rect1にrect2ははまり込む? println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); } ``` -Listing 5-14: Demonstration of using the as-yet-unwritten -`can_hold` method + + + +リスト5-14: 未完成の`can_hold`を使用するデモ -And the expected output would look like the following, because both dimensions -of `rect2` are smaller than the dimensions of `rect1`, but `rect3` is wider -than `rect1`: + + + + +そして、予期される出力は以下のようになります。なぜなら、`rect2`の各次元は`rect1`よりも小さいものの、 +`rect3`は`rect1`より幅が広いからです: ```text Can rect1 hold rect2? true Can rect1 hold rect3? false ``` -We know we want to define a method, so it will be within the `impl Rectangle` -block. The method name will be `can_hold`, and it will take an immutable borrow -of another `Rectangle` as a parameter. We can tell what the type of the -parameter will be by looking at the code that calls the method: -`rect1.can_hold(&rect2)` passes in `&rect2`, which is an immutable borrow to -`rect2`, an instance of `Rectangle`. This makes sense because we only need to -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 length and width of -`self` are both greater than the length and width 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: - -Filename: src/main.rs + + + + + + + + + + + + + + +メソッドを定義したいことはわかっているので、`impl Rectangle`ブロック内での話になります。 +メソッド名は、`can_hold`になり、引数として別の`Rectangle`を不変参照で取るでしょう。 +メソッドを呼び出すコードを見れば、引数の型が何になるかわかります: `rect1.can_hold(&rect2)`は、 +`&rect2`、`Rectangle`のインスタンスである`rect2`への不変参照を渡しています。 +これは道理が通っています。なぜなら、`rect2`を読み込む(書き込みではなく。この場合、可変参照が必要になります)だけでよく、 +`can_hold`メソッドを呼び出した後にも`rect2`が使えるよう、所有権を`main`に残したままにしたいからです。 +`can_hold`の返り値は、論理型になり、メソッドの中身は、`self`の長さと幅がもう一つの`Rectangle`の長さと幅よりも、 +それぞれ大きいことを確認します。リスト5-13の`impl`ブロックに新しい`can_hold`メソッドを追記しましょう。 +リスト5-15に示した通りです: + + + +ファイル名: src/main.rs ```rust # #[derive(Debug)] @@ -186,30 +295,49 @@ impl Rectangle { } ``` -Listing 5-15: Implementing the `can_hold` method on -`Rectangle` that takes another `Rectangle` instance as a parameter + + + +リスト5-15: 別の`Rectangle`のインスタンスを引数として取る`can_hold`メソッドを、 +`Rectangle`に実装する + + + + + -When we run this code with the `main` function in Listing 5-14, we’ll get our -desired output. Methods can take multiple parameters that we add to the -signature after the `self` parameter, and those parameters work just like -parameters in functions. +このコードをリスト5-14の`main`関数と合わせて実行すると、望み通りの出力が得られます。 +メソッドは、`self`引数の後にシグニチャに追加した引数を複数取ることができ、 +関数の引数と同様に動作するのです。 -### Associated Functions + -Another useful feature of `impl` blocks is that we’re allowed to define -functions within `impl` blocks that *don’t* take `self` as a parameter. These -are called *associated functions* because they’re associated with the struct. -They’re still functions, not methods, because they don’t have an instance of -the struct to work with. You’ve already used the `String::from` associated -function. +### 関連関数 -Associated functions are often used for constructors that will return a new -instance of the struct. For example, we could provide an associated function -that would have one dimension parameter and use that as both length and width, -thus making it easier to create a square `Rectangle` rather than having to -specify the same value twice: + + + + + + -Filename: src/main.rs +`impl`ブロックの別の有益な機能は、`impl`ブロック内に`self`を引数に取ら*ない*関数を定義できることです。 +これは、構造体に関連付けられているので、*関連関数*と呼ばれます。それでも、関連関数は関数であり、メソッドではありません。 +というのも、対象となる構造体のインスタンスが存在しないからです。もう`String::from`という関連関数を使用したことがありますね。 + + + + + + + +関連関数は、構造体の新規インスタンスを返すコンストラクタによく使用されます。例えば、一次元の引数を取り、 +長さと幅両方に使用する関連関数を提供することができ、その結果、同じ値を2回指定する必要なく、 +正方形の`Rectangle`を生成しやすくすることができます。 + + + +ファイル名: src/main.rs ```rust # #[derive(Debug)] @@ -225,16 +353,26 @@ impl Rectangle { } ``` -To call this associated function, we use the `::` syntax with the struct name, -like `let sq = Rectangle::square(3);`, for example. This function is -namespaced by the struct: the `::` syntax is used for both associated functions -and namespaces created by modules, which we’ll discuss in Chapter 7. + + + + + +この関連関数を呼び出すために、例えば、`let sq = Rectangle::square(3);`のように、 +構造体名と一緒に`::`記法を使用しています。この関数は、構造体によって名前空間分けされています: +`::`という記法は、関連関数とモジュールによって作り出される名前空間両方に使用され、 +モジュールについては第7章で議論します。 + + -### Multiple `impl` Blocks +### 複数の`impl`ブロック -Each struct is allowed to have multiple `impl` blocks. For example, Listing -5-15 is equivalent to the code shown in Listing 5-16, which has each method -in its own `impl` block: + + + + +各構造体には、複数の`impl`ブロックを存在させることができます。例えば、リスト5-15はリスト5-16に示したコードと等価で、 +リスト5-16では、各メソッドごとに`impl`ブロックを用意しています: ```rust # #[derive(Debug)] @@ -256,21 +394,36 @@ impl Rectangle { } ``` -Listing 5-16: Rewriting Listing 5-15 using multiple `impl` -blocks + + + +リスト5-16: 複数の`impl`ブロックを使用してリスト5-15を書き直す + + + + + +ここでこれらのメソッドを個々の`impl`ブロックに分ける理由はないのですが、有効な書き方です。 +複数の`impl`ブロックが有用になるケースは第10章で見ますが、そこではジェネリクスのある型とトレイトについて議論します。 + + + +## まとめ -There’s no reason to separate these methods into multiple `impl` blocks here, -but it’s valid syntax. We will see a case when multiple `impl` blocks are useful -in Chapter 10 when we discuss generic types and traits. + + + + + + -## Summary +構造体により、自分の領域で意味のある独自の型を作成することができます。構造体を使用することで、 +関連のあるデータ片を相互に結合させ続け、各部品に名前を付け、コードを明確にすることができます。 +メソッドにより、構造体のインスタンスが行う動作を指定することができ、関連関数により、 +構造体に特有の機能をインスタンスを利用することなく名前空間分けすることができます。 -Structs let us create custom types that are meaningful for our domain. By using -structs, we can keep associated pieces of data connected to each other and name -each piece to make our code clear. Methods let us specify the behavior that -instances of our structs have, and associated functions let us namespace -functionality that is particular to our struct without having an instance -available. + + -But structs aren’t the only way we can create custom types: let’s turn to -Rust’s enum feature to add another tool to our toolbox. +しかし、構造体だけが独自の型を作成する手段ではありません: Rustのenum機能に目を向けて、 +別の道具をツールボックスに追加しましょう。 From 5231f359a53866551ae4d5dd86193765a5914d00 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 7 Aug 2017 22:39:00 +0900 Subject: [PATCH 016/428] Delete the remaining merge messages --- .../src/ch02-00-guessing-game-tutorial.md | 26 +++++-------------- .../src/ch03-01-variables-and-mutability.md | 8 +----- .../src/ch03-03-how-functions-work.md | 7 ----- second-edition/src/ch03-05-control-flow.md | 14 +++------- .../src/ch06-01-defining-an-enum.md | 6 ----- second-edition/src/ch06-02-match.md | 15 ----------- 6 files changed, 12 insertions(+), 64 deletions(-) diff --git a/second-edition/src/ch02-00-guessing-game-tutorial.md b/second-edition/src/ch02-00-guessing-game-tutorial.md index d3e94b460..eceb55fda 100644 --- a/second-edition/src/ch02-00-guessing-game-tutorial.md +++ b/second-edition/src/ch02-00-guessing-game-tutorial.md @@ -146,8 +146,8 @@ fn main() { } ``` -<<<<<<< HEAD - + + リスト2-1: ユーザに予想を入力してもらい、それを出力するコード @@ -159,10 +159,6 @@ fn main() { -======= -Listing 2-1: Code to get a guess from the user and print -it out ->>>>>>> fork_master_master このコードには、たくさんの情報が詰め込まれてますね。なので、少しずつ噛み砕いていきましょう。 ユーザ入力を受け付け、結果を出力するためには、`io`(入/出力)ライブラリをスコープに導入する必要があります。 @@ -1287,29 +1283,21 @@ fn main() { -<<<<<<< HEAD 見てわかる通り、予想入力部分以降をループに入れ込みました。変更した行にインデントを追加するのを忘れないようにして、 またプログラムを走らせてみましょう。新たな問題が発生したことに気をつけてください。 プログラムが教えた通りに動作しているからですね: 永遠に予想入力を求めるわけです! これでは、ユーザが終了できないようです! - - - - - + + + + + ユーザは、`Ctrl-C`というキーボードショートカットを使って、いつでもプログラムを強制終了させられます。 しかし、「予想を秘密の数字と比較する」節の`parse`メソッドに関する議論で触れたこの貪欲なモンスターを 回避する別の方法があります: ユーザが数字以外の答えを入力すれば、プログラムはクラッシュするのです。 ユーザは、その利点を活かして、終了することができます。以下のようにね: -======= -The user could always halt the program by using the keyboard shortcut -ctrl-C. But there’s another way to escape this -insatiable monster that we mentioned in the `parse` discussion in “Comparing the -Guess to the Secret Number”: if the user enters a non-number answer, the program -will crash. The user can take advantage of that in order to quit, as shown here: ->>>>>>> fork_master_master ```text $ cargo run diff --git a/second-edition/src/ch03-01-variables-and-mutability.md b/second-edition/src/ch03-01-variables-and-mutability.md index a17540b64..6c1962085 100644 --- a/second-edition/src/ch03-01-variables-and-mutability.md +++ b/second-edition/src/ch03-01-variables-and-mutability.md @@ -188,7 +188,6 @@ The value of x is: 6 定数はどんなスコープでも定義できます。グローバルスコープも含めてね。なので、いろんなところで使用される可能性のある値を 定義するのに役に立ちます。 -<<<<<<< HEAD @@ -199,13 +198,8 @@ The value of x is: 6 -定数の名前が`MAX_POINTS`で値が100,000にセットされた定数定義の例をご覧ください。(Rustの定数の命名規則は、 +定数の名前が`MAX_POINTS`で、値が100,000にセットされた定数定義の例をご覧ください。(Rustの定数の命名規則は、 全て大文字でアンダースコアで単語区切りすることです): -======= -Here’s an example of a constant declaration where the constant’s name is -`MAX_POINTS` and its value is set to 100,000. (Rust constant naming convention -is to use all upper case with underscores between words): ->>>>>>> fork_master_master ```rust const MAX_POINTS: u32 = 100_000; diff --git a/second-edition/src/ch03-03-how-functions-work.md b/second-edition/src/ch03-03-how-functions-work.md index 151e02b97..88181e9e8 100644 --- a/second-edition/src/ch03-03-how-functions-work.md +++ b/second-edition/src/ch03-03-how-functions-work.md @@ -165,17 +165,10 @@ fn another_function(x: i32, y: i32) { } ``` -<<<<<<< HEAD -======= -This example creates a function with two parameters, both of which are `i32` -types. The function then prints out the values in both of its parameters. Note -that function parameters don’t all need to be the same type, they just happen -to be in this example. ->>>>>>> fork_master_master この例では、2引数の関数を生成しています。そして、引数はどちらも`i32`型です。この関数は、 仮引数の値を両方出力します。関数引数は、全てが同じ型である必要はありません。今回は、 diff --git a/second-edition/src/ch03-05-control-flow.md b/second-edition/src/ch03-05-control-flow.md index 75bd16333..490797e2d 100644 --- a/second-edition/src/ch03-05-control-flow.md +++ b/second-edition/src/ch03-05-control-flow.md @@ -414,12 +414,11 @@ again! ^Cagain! ``` -<<<<<<< HEAD - - - + + + -`^C`という記号が出た場所が、ctrl-Cを押した場所です。`^C`の後には`again!`と表示されたり、 +`^C`という記号が出た場所が、ctrl-Cを押した場所です。`^C`の後には`again!`と表示されたり、 されなかったりします。ストップシグナルをコードが受け取った時にループのどこにいたかによります。 @@ -432,11 +431,6 @@ again! キーワードを配置することでプログラムに実行を終了すべきタイミングを教えることができます。 第2章の「正しい予想をした後に終了する」節の数当てゲーム内でこれをして、ユーザが予想を的中させ、 ゲームに勝った時にプログラムを終了させたことを思い出してください。 -======= -The symbol `^C` represents where you pressed ctrl-C -. You may or may not see the word `again!` printed after the `^C`, -depending on where the code was in the loop when it received the halt signal. ->>>>>>> fork_master_master diff --git a/second-edition/src/ch06-01-defining-an-enum.md b/second-edition/src/ch06-01-defining-an-enum.md index 99bb708a5..31599a8ec 100644 --- a/second-edition/src/ch06-01-defining-an-enum.md +++ b/second-edition/src/ch06-01-defining-an-enum.md @@ -487,18 +487,12 @@ let some_string = Some("a string"); let absent_number: Option = None; ``` -<<<<<<< HEAD `Some`ではなく、`None`を使ったら、コンパイラに`Option`の型が何になるかを教えなければいけません。 というのも、`None`値を見ただけでは、`Some`バリアントが保持する型をコンパイラが推論できないからです。 -======= -If we use `None` rather than `Some`, we need to tell Rust what type of -`Option` we have, because the compiler can’t infer the type that the `Some` -variant will hold by looking only at a `None` value. ->>>>>>> fork_master_master diff --git a/second-edition/src/ch06-02-match.md b/second-edition/src/ch06-02-match.md index 079123748..aa9263db8 100644 --- a/second-edition/src/ch06-02-match.md +++ b/second-edition/src/ch06-02-match.md @@ -125,7 +125,6 @@ fn value_in_cents(coin: Coin) -> u32 { } ``` -<<<<<<< HEAD ### 値に束縛されるパターン @@ -165,20 +164,6 @@ enumのバリアントから値を取り出すことができます。 -======= -### Patterns that Bind to Values - -Another useful feature of match arms is that they can bind to parts of the -values that match the pattern. This is how we can extract values out of enum -variants. - -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 `State` value stored -inside it, which we’ve done here in Listing 6-4: ->>>>>>> fork_master_master ```rust #[derive(Debug)] // すぐに州を点検できるように From 527c5be29c97e761824f6be5738a6e3d1089fe59 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 7 Aug 2017 22:59:44 +0900 Subject: [PATCH 017/428] Translate part of SUMMARY.md into Japanese --- second-edition/src/SUMMARY.md | 78 ++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index 13b5ada15..841cc8531 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -1,34 +1,62 @@ -# The Rust Programming Language + -## Getting started +# Rustプログラミング言語 + + + +## 事始め - [Introduction](ch01-00-introduction.md) - [Installation](ch01-01-installation.md) - [Hello, World!](ch01-02-hello-world.md) -- [Guessing Game Tutorial](ch02-00-guessing-game-tutorial.md) - -- [Common Programming Concepts](ch03-00-common-programming-concepts.md) - - [Variables and Mutability](ch03-01-variables-and-mutability.md) - - [Data Types](ch03-02-data-types.md) - - [How Functions Work](ch03-03-how-functions-work.md) - - [Comments](ch03-04-comments.md) - - [Control Flow](ch03-05-control-flow.md) - -- [Understanding Ownership](ch04-00-understanding-ownership.md) - - [What is Ownership?](ch04-01-what-is-ownership.md) - - [References & Borrowing](ch04-02-references-and-borrowing.md) - - [Slices](ch04-03-slices.md) - -- [Using Structs to Structure Related Data](ch05-00-structs.md) - - [Defining and Instantiating Structs](ch05-01-defining-structs.md) - - [An Example Program Using Structs](ch05-02-example-structs.md) - - [Method Syntax](ch05-03-method-syntax.md) - -- [Enums and Pattern Matching](ch06-00-enums.md) - - [Defining an Enum](ch06-01-defining-an-enum.md) - - [The `match` Control Flow Operator](ch06-02-match.md) - - [Concise Control Flow with `if let`](ch06-03-if-let.md) + + +- [数当てゲームチュートリアル](ch02-00-guessing-game-tutorial.md) + + + + + + + + +- [普遍的なプログラミング概念](ch03-00-common-programming-concepts.md) + - [変数と可変性](ch03-01-variables-and-mutability.md) + - [データ型](ch03-02-data-types.md) + - [関数の動作法](ch03-03-how-functions-work.md) + - [コメント](ch03-04-comments.md) + - [制御フロー](ch03-05-control-flow.md) + + + + + + +- [所有権を理解する](ch04-00-understanding-ownership.md) + - [所有権とは?](ch04-01-what-is-ownership.md) + - [参照と借用](ch04-02-references-and-borrowing.md) + - [スライス](ch04-03-slices.md) + + + + + + +- [構造体を使用して関連のあるデータを構造化する](ch05-00-structs.md) + - [構造体を定義し、インスタンス化する](ch05-01-defining-structs.md) + - [構造体を使用したプログラム例](ch05-02-example-structs.md) + - [メソッド記法](ch05-03-method-syntax.md) + + + + + + +- [Enumとパターンマッチング](ch06-00-enums.md) + - [Enumを定義する](ch06-01-defining-an-enum.md) + - [`match`制御フロー演算子](ch06-02-match.md) + - [`if let`で簡潔な制御フロー](ch06-03-if-let.md) ## Basic Rust Literacy From befbe914b9326af8c434d0bd9520e254d843ce19 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 7 Aug 2017 23:15:08 +0900 Subject: [PATCH 018/428] First draft of the chapter 7-0 and translate another part of SUMMARY.md into Japanese --- second-edition/src/SUMMARY.md | 13 +++-- second-edition/src/ch07-00-modules.md | 68 +++++++++++++++++---------- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index 841cc8531..19db1345c 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -60,10 +60,15 @@ ## Basic Rust Literacy -- [Modules](ch07-00-modules.md) - - [`mod` and the Filesystem](ch07-01-mod-and-the-filesystem.md) - - [Controlling Visibility with `pub`](ch07-02-controlling-visibility-with-pub.md) - - [Importing Names with `use`](ch07-03-importing-names-with-use.md) + + + + + +- [モジュール](ch07-00-modules.md) + - [`mod`とファイルシステム](ch07-01-mod-and-the-filesystem.md) + - [`pub`で公開するか制御する](ch07-02-controlling-visibility-with-pub.md) + - [`use`で名前をインポートする](ch07-03-importing-names-with-use.md) - [Common Collections](ch08-00-common-collections.md) - [Vectors](ch08-01-vectors.md) diff --git a/second-edition/src/ch07-00-modules.md b/second-edition/src/ch07-00-modules.md index 110da77f8..b625cd0ed 100644 --- a/second-edition/src/ch07-00-modules.md +++ b/second-edition/src/ch07-00-modules.md @@ -1,24 +1,44 @@ -# Using Modules to Reuse and Organize Code - -When you start writing programs in Rust, your code might live solely in the -`main` function. As your code grows, you’ll eventually move functionality into -other functions for reuse and better organization. By splitting your code into -smaller chunks, each chunk is easier to understand on its own. But what happens -if you have too many functions? Rust has a module system that enables the reuse -of code in an organized fashion. - -In the same way that you extract lines of code into a function, you can extract -functions (and other code, like structs and enums) into different modules. A -*module* is a namespace that contains definitions of functions or types, and -you can choose whether those definitions are visible outside their module -(public) or not (private). Here’s an overview of how modules work: - -* The `mod` keyword declares a new module. Code within the module appears - either immediately following this declaration within curly braces or in - another file. -* By default, functions, types, constants, and modules are private. The `pub` - keyword makes an item public and therefore visible outside its namespace. -* The `use` keyword brings modules, or the definitions inside modules, into - scope so it’s easier to refer to them. - -We’ll look at each of these parts to see how they fit into the whole. + + +# モジュールを使用してコードを体系化し、再利用する + + + + + + + + +Rustでのプログラミングをし始めた頃は、コードは全て`main`関数内に収まったかもしれません。コードが肥大化するにつれ、 +最終的に機能を別の関数に移して再利用性とまとまりを高めるでしょう。コードを細切りにすることで、 +個々のコード片はそれだけで理解しやすくなります。しかし、あまりにも多くの関数があったらどうなるでしょうか? +Rustにはコードの再利用を体系化された形で行うことのできるモジュールシステムが組み込まれています。 + + + + + + + +コードを関数に抽出するのと同様に、関数(や他のコード、構造体やenumなど)を異なるモジュールに抽出することができます。 +*モジュール*とは、関数や型定義を含む名前空間のことで、それらの定義がモジュール外からも見えるようにするか(public)否か(private)は、 +選択することができます。以下が、モジュールの動作法の概要です: + + + + + + + + + +* `mod`キーワードで新規モジュールを宣言します。モジュール内のコードは、この宣言の直後の波かっこ内か、 +別のファイルに存在します。 +* 標準では、関数、型、定数、モジュールはプライベートです。`pub`キーワードで要素は公開され、 +名前空間の外からも見えるようになります。 +* `use`キーワードでモジュールやモジュール内の定義をスコープに入れることができるので、 +参照するのが楽になります。 + + + +この部品の各々を見て、それらが全体にどうはまり込むかを理解します。 From cb02213b8205f7370628879e9c9a2656e8f66fb4 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 8 Aug 2017 20:11:18 +0900 Subject: [PATCH 019/428] First draft of the chapter 7-1 --- .../src/ch07-01-mod-and-the-filesystem.md | 623 ++++++++++++------ 1 file changed, 422 insertions(+), 201 deletions(-) diff --git a/second-edition/src/ch07-01-mod-and-the-filesystem.md b/second-edition/src/ch07-01-mod-and-the-filesystem.md index 749db5983..27355f89b 100644 --- a/second-edition/src/ch07-01-mod-and-the-filesystem.md +++ b/second-edition/src/ch07-01-mod-and-the-filesystem.md @@ -1,28 +1,44 @@ -## `mod` and the Filesystem - -We’ll start our module example by making a new project with Cargo, but instead -of creating a binary crate, we’ll make a library crate: a project that other -people can pull into their projects as a dependency. For example, the `rand` -crate in Chapter 2 is a library crate that we used as a dependency in the -guessing game project. - -We’ll create a skeleton of a library that provides some general networking -functionality; we’ll concentrate on the organization of the modules and -functions but we won’t worry about what code goes in the function bodies. We’ll -call our library `communicator`. By default, Cargo will create a library unless -another type of project is specified: if we omit the `--bin` option that we’ve -been using in all of the chapters preceding this one, our project will be a -library: + + +## `mod`とファイルシステム + + + + + + + +モジュールの例をCargoで新規プロジェクトを生成することから始めるが、バイナリクレートの代わりに、 +ライブラリクレートを作成します: 他人が依存ファイルとして自分のプロジェクトに引き込めるプロジェクトです。 +例を挙げると、第2章の`rand`クレートは、数当てゲームプロジェクトで依存ファイルに使用したライブラリクレートです。 + + + + + + + + + +何らかの一般的なネットワーク機能を提供するライブラリの骨格を作成します; モジュールと関数の体系化に集中し、 +関数の本体にどんなコードが入るかについては気にかけません。このライブラリを`communicator`と呼びましょう。 +標準では、別のタイプのプロジェクトを指定しない限り、Cargoはライブラリを生成します: +ここまでの章全部で使ってきた`--bin`オプションを省略すれば、プロジェクトはライブラリになります: ```text $ cargo new communicator $ cd communicator ``` -Notice that Cargo generated *src/lib.rs* instead of *src/main.rs*. Inside -*src/lib.rs* we’ll find the following: + + + +Cargoが*src/main.rs*の代わりに*src/lib.rs*を生成したことに注目してください。*src/lib.rs*には、 +以下のような記述があります: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -33,27 +49,45 @@ mod tests { } ``` -Cargo creates an empty test to help us get our library started, rather than the -“Hello, world!” binary that we get when we use the `--bin` option. We’ll look -at the `#[]` and `mod tests` syntax in the “Using `super` to Access a Parent -Module” section later in this chapter, but for now, leave this code at the -bottom of *src/lib.rs*. + + + + + + +Cargoは、`--bin`オプションを使った時に得られる"Hello, world!"バイナリではなく、空のテストを生成して、 +ライブラリの事始めをしてくれました。`#[]`と`mod tests`という記法については、この章の後ほど、 +「`super`を使用して親モジュールにアクセスする」節で見ますが、今のところは、 +このコードを*src/lib.rs*の最後に残しておきましょう。 -Because we don’t have a *src/main.rs* file, there’s nothing for Cargo to -execute with the `cargo run` command. Therefore, we’ll use the `cargo build` -command to compile our library crate’s code. + + + -We’ll look at different options for organizing your library’s code that will be -suitable in a variety of situations, depending on the intent of the code. +*src/main.rs*ファイルがないので、`cargo run`コマンドでCargoが実行できるものは何もないわけです。 +従って、`cargo build`コマンドを使用してライブラリクレートのコードをコンパイルします。 -### Module Definitions + + -For our `communicator` networking library, we’ll first define a module named -`network` that contains the definition of a function called `connect`. Every -module definition in Rust starts with the `mod` keyword. Add this code to the -beginning of the *src/lib.rs* file, above the test code: +コードの意図によって、いろんなシチュエーションで最適になるライブラリコードを体系化する別のオプションをお目にかけます。 -Filename: src/lib.rs + + +### モジュール定義 + + + + + + +`communicator`ネットワークライブラリについて、まずは`connect`という関数定義を含む`network`という名前のモジュールを定義します。 +Rustにおいて、モジュール定義は、`mod`キーワードから開始します。このコードを*src/lib.rs*ファイルの頭、 +テストコードの上に追記してください。 + + + +ファイル名: src/lib.rs ```rust mod network { @@ -62,18 +96,29 @@ mod network { } ``` -After the `mod` keyword, we put the name of the module, `network`, and then a -block of code in curly braces. Everything inside this block is inside the -namespace `network`. In this case, we have a single function, `connect`. If we -wanted to call this function from a script outside the `network` module, we -would need to specify the module and use the namespace syntax `::`, like so: -`network::connect()` rather than just `connect()`. + + + + + + + +`mod`キーワードに続いて、モジュール名の`network`、さらに一連のコードを波かっこ内に記述します。 +このブロック内に存在するものは全て、`network`という名前空間に属します。今回の場合、 +`connect`という単独の関数があります。この関数を`network`モジュール外のスクリプトから呼び出したい場合、 +モジュールを指定し、名前空間記法の`::`を使用する必要があるでしょう。そう、以下のように: +`connect()`だけでなく、`network::connect()`と。 + + + + + +同じ*src/lib.rs*ファイル内に複数のモジュールを並べることもできます。`connect`という関数を含む`client`モジュールを用意するには、 +リスト7-1に示したように追記すればいいわけです: -We can also have multiple modules, side by side, in the same *src/lib.rs* file. -For example, to also have a `client` module that has a function named `connect` -as well, we can add it as shown in Listing 7-1: + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust mod network { @@ -87,26 +132,42 @@ mod client { } ``` -Listing 7-1: The `network` module and the `client` module -defined side by side in *src/lib.rs* + + -Now we have a `network::connect` function and a `client::connect` function. -These can have completely different functionality, and the function names do -not conflict with each other because they’re in different modules. +リスト7-1: *src/lib.rs*に並べて定義された`network`モジュールと`client`モジュール -In this case, because we’re building a library, the file that serves as the -entry point for building our library is *src/lib.rs*. However, in respect to -creating modules, there’s nothing special about *src/lib.rs*. We could also -create modules in *src/main.rs* for a binary crate in the same way as we’re -creating modules in *src/lib.rs* for the library crate. In fact, we can put -modules inside of modules, which can be useful as your modules grow to keep -related functionality organized together and separate functionality apart. The -choice of how you organize your code depends on how you think about the -relationship between the parts of your code. For instance, the `client` code -and its `connect` function might make more sense to users of our library if -they were inside the `network` namespace instead, as in Listing 7-2: + + + -Filename: src/lib.rs +これで、`network::connect`関数と`client::connect`関数が用意できました。これらは全く異なる機能を有する可能性があり、 +異なるモジュールに存在するので、関数名がお互いに衝突することはありません。 + + + + + + + + + + + + + +今回の場合、ライブラリを構成しているので、ライブラリビルド時にエントリーポイントとなるファイルは、 +*src/lib.rs*になります。しかし、モジュールを作成するという点に関しては、*src/lib.rs*には何も特別なことはありません。 +ライブラリクレートに対して*src/lib.rs*にモジュールを生成するのと全く同様に、 +バイナリクレートに対して*src/main.rs*にモジュールを生成することもできます。実は、モジュール内にモジュールを書くこともでき、 +モジュールが肥大化するにつれて、関連のある機能を一緒くたにし、機能を切り離すのに有用なのです。 +コードを体系化する方法は、コードの部分部分の関連性に対する考え方によって選択することになります。 +例ですが、`client`コードとその`connect`関数は、リスト7-2のように、代わりに`network`名前空間内に存在したら、 +ライブラリの使用者にとって意味のあるものになるかもしれません。 + + + +ファイル名: src/lib.rs ```rust mod network { @@ -120,19 +181,29 @@ mod network { } ``` -Listing 7-2: Moving the `client` module inside the -`network` module + + -In your *src/lib.rs* file, replace the existing `mod network` and `mod client` -definitions with the ones in Listing 7-2, which have the `client` module as an -inner module of `network`. Now we have the functions `network::connect` and -`network::client::connect`: again, the two functions named `connect` don’t -conflict with each other because they’re in different namespaces. +リスト7-2: `client`モジュールを`network`モジュール内に移動させる -In this way, modules form a hierarchy. The contents of *src/lib.rs* are at the -topmost level, and the submodules are at lower levels. Here’s what the -organization of our example in Listing 7-1 looks like when thought of as a -hierarchy: + + + + + + +*src/lib.rs*ファイル内で、すでにある`mod network`と`mod client`の定義をリスト7-2のものと置き換えると、 +`client`モジュールは`network`の内部モジュールになるわけです。すると、関数は、 +`network::connect`と`network::client::connect`になるわけです: またしても、異なる名前空間に存在するので、 +この二つの`connect`という名前の関数は、互いに干渉することはありません。 + + + + + + +このように、モジュールは階層構造を形成します。*src/lib.rs*の中身が頂点に立ち、サブモジュールが子供になるわけです。 +リスト7-1の例を階層構造という観点で見たときの構造は、以下のような感じになります: ```text communicator @@ -140,7 +211,9 @@ communicator └── client ``` -And here’s the hierarchy corresponding to the example in Listing 7-2: + + +さらに、リスト7-2の例に対応する階層構造は、以下の通りです: ```text communicator @@ -148,23 +221,38 @@ communicator └── client ``` -The hierarchy shows that in Listing 7-2, `client` is a child of the `network` -module rather than a sibling. More complicated projects can have many modules, -and they’ll need to be organized logically in order to keep track of them. What -“logically” means in your project is up to you and depends on how you and your -library’s users think about your project’s domain. Use the techniques shown -here to create side-by-side modules and nested modules in whatever structure -you would like. + + + + + + + -### Moving Modules to Other Files +この階層構造は、リスト7-2において、`client`モジュールは`network`モジュールの兄弟というよりも、子供になっていることを示しています。 +より複雑なプロジェクトなら、たくさんのモジュールが存在し、把握するのに論理的に体系化しておく必要があるでしょう。 +プロジェクト内で「論理的」とは、あなた次第であり、ライブラリ作成者と使用者がプロジェクトの領域についてどう考えるか次第でもあるわけです。 +こちらで示したテクニックを使用して、並列したモジュールや、ネストしたモジュールなど、どんな構造のモジュールでも、 +作成してください。 -Modules form a hierarchical structure, much like another structure in computing -that you’re used to: filesystems! We can use Rust’s module system along with -multiple files to split up Rust projects so not everything lives in -*src/lib.rs* or *src/main.rs*. For this example, let’s start with the code in -Listing 7-3: + -Filename: src/lib.rs +### モジュールを別ファイルに移す + + + + + + + +モジュールは階層構造をなす……コンピュータにおいて、もっと見慣れた構造に似ていませんか: そう、ファイルシステムです! +Rustのモジュールシステムを複数のファイルで使用して、プロジェクトを分割するので、 +全部が*src/lib.rs*や*src/main.rs*に存在することにはならなくなります。これの例として、 +リスト7-3のようなコードから始めましょう: + + + +ファイル名: src/lib.rs ```rust mod client { @@ -183,10 +271,15 @@ mod network { } ``` -Listing 7-3: Three modules, `client`, `network`, and -`network::server`, all defined in *src/lib.rs* + + -The file *src/lib.rs* has this module hierarchy: +リスト7-3: 全て*src/lib.rs*に定義された三つのモジュール、 +`client`、`network`、`network::server` + + + +*src/lib.rs*ファイルのモジュール階層は、こうなっています: ```text communicator @@ -195,17 +288,27 @@ communicator └── server ``` -If these modules had many functions, and those functions were becoming lengthy, -it would be difficult to scroll through this file to find the code we wanted to -work with. Because the functions are nested inside one or more mod blocks, the -lines of code inside the functions will start getting lengthy as well. These -would be good reasons to separate the `client`, `network`, and `server` modules -from *src/lib.rs* and place them into their own files. + + + + + + + +これらのモジュールが多数の関数を含み、その関数が長ったらしくなってきたら、このファイルをスクロールして、 +弄りたいコードを探すのが困難になるでしょう。関数が一つ以上のmodブロックにネストされているので、 +関数の中身となるコードも長ったらしくなってしまうのです。これだけで、`client`、`network`、`server`モジュールを*src/lib.rs*から分け、 +単独のファイルに配置するには十分でしょう。 -First, replace the `client` module code with only the declaration of the `client` -module, so that your *src/lib.rs* looks like the following: + + -Filename: src/lib.rs +最初に、`client`モジュールのコードを`client`モジュールの宣言だけに置き換えてください。 +すると、*src/lib.rs*は以下のようになります: + + + +ファイル名: src/lib.rs ```rust,ignore mod client; @@ -221,10 +324,14 @@ mod network { } ``` -We’re still *declaring* the `client` module here, but by replacing the block -with a semicolon, we’re telling Rust to look in another location for the code -defined within the scope of the `client` module. In other words, the line `mod -client;` means: + + + + + +一応、`client`モジュールをここで*宣言*していますが、ブロックをセミコロンで置換したことで、 +`client`モジュールのスコープのコードは別の場所を探すようにコンパイラに指示しているわけです。 +言い換えると、`mod client;`の行は、以下のような意味になります: ```rust,ignore mod client { @@ -232,37 +339,57 @@ mod client { } ``` -Now we need to create the external file with that module name. Create a -*client.rs* file in your *src/* directory and open it. Then enter the -following, which is the `connect` function in the `client` module that we -removed in the previous step: + + + + + + -Filename: src/client.rs +さて、このモジュール名の外部ファイルを作成する必要が出てきました。*src/*ディレクトリ内に*client.rs*ファイルを作成し、 +開いてください。それから以下のように入力してください。前段階で削除した`client`モジュールの`connect`関数です: + + + +ファイル名: src/client.rs ```rust fn connect() { } ``` -Note that we don’t need a `mod` declaration in this file because we already -declared the `client` module with `mod` in *src/lib.rs*. This file just -provides the *contents* of the `client` module. If we put a `mod client` here, -we’d be giving the `client` module its own submodule named `client`! + + + + + +このファイルには、`mod`宣言が必要ないことに着目してください。なぜなら、*src/lib.rs*に`mod`を使って、 +もう`client`モジュールを宣言しているからです。このファイルは、`client`モジュールの中身を提供するだけなのです。 +ここにも`mod client`を記述したら、`client`に`client`という名前のサブモジュールを与えることになってしまいます! + + + + + -Rust only knows to look in *src/lib.rs* by default. If we want to add more -files to our project, we need to tell Rust in *src/lib.rs* to look in other -files; this is why `mod client` needs to be defined in *src/lib.rs* and can’t -be defined in *src/client.rs*. +コンパイラは、標準で*src/lib.rs*だけを検索します。プロジェクトにもっとファイルを追加したかったら、 +*src/lib.rs*で他のファイルも検索するよう、コンパイラに指示する必要があるのです; このため、`mod client`を*src/lib.rs*に定義し、 +*src/client.rs*には定義できなかったのです。 -Now the project should compile successfully, although you’ll get a few -warnings. Remember to use `cargo build` instead of `cargo run` because we have -a library crate rather than a binary crate: + + + + +これでプロジェクトは問題なくコンパイルできるはずです。まあ、警告がいくつか出るんですが。 +`cargo run`ではなく、`cargo build`を使うことを忘れないでください。バイナリクレートではなく、 +ライブラリクレートだからですね: ```text $ cargo build Compiling communicator v0.1.0 (file:///projects/communicator) warning: function is never used: `connect`, #[warn(dead_code)] on by default +(警告: 関数は使用されていません: `connect`、#[warn(dead_code)]は標準で有効です) --> src/client.rs:1:1 | 1 | fn connect() { @@ -281,16 +408,24 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default | ^ ``` -These warnings tell us that we have functions that are never used. Don’t worry -about these warnings for now; we’ll address them in the “Controlling Visibility -with `pub`” section later in this chapter. The good news is that they’re just -warnings; our project built successfully! + + + + + +これらの警告は、全く使用されていない関数があると忠告してくれています。今は、警告を危惧する必要はありません; +この章の後ほど、「`pub`で公開するか制御する」節で特定します。嬉しいことにただの警告です; プロジェクトはビルドに成功しました! + + + + + +次に、同様のパターンを使用して`network`モジュールも単独のファイルに抽出しましょう。 +*src/lib.rs*で、`network`モジュールの本体を削除し、宣言にセミコロンを付加してください。こんな感じです: -Next, let’s extract the `network` module into its own file using the same -pattern. In *src/lib.rs*, delete the body of the `network` module and add a -semicolon to the declaration, like so: + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust,ignore mod client; @@ -298,9 +433,13 @@ mod client; mod network; ``` -Then create a new *src/network.rs* file and enter the following: + -Filename: src/network.rs +それから新しい*src/network.rs*ファイルを作成して、以下のように入力してください: + + + +ファイル名: src/network.rs ```rust fn connect() { @@ -312,16 +451,27 @@ mod server { } ``` -Notice that we still have a `mod` declaration within this module file; this is -because we still want `server` to be a submodule of `network`. + + + +このモジュールファイル内にもまだ`mod`宣言があることに気付いてください; +`server`は`network`のサブモジュールにしたいからです。 -Run `cargo build` again. Success! We have one more module to extract: `server`. -Because it’s a submodule—that is, a module within a module—our current tactic -of extracting a module into a file named after that module won’t work. We’ll -try anyway so you can see the error. First, change *src/network.rs* to have -`mod server;` instead of the `server` module’s contents: + + + + + -Filename: src/network.rs +再度`cargo build`してください。成功!抽出すべきモジュールがもう1個あります: `server`です。 +これはサブモジュール(つまり、モジュール内のモジュール)なので、 +モジュール名に倣ったファイルにモジュールを抽出するという今の手法は、通用しません。いずれにしても、 +エラーが確認できるように、試してみましょう。まず、*src/network.rs*ファイルを`server`モジュールの中身を含む代わりに、 +`mod server;`となるように変更してください。 + + + +ファイル名: src/network.rs ```rust,ignore fn connect() { @@ -330,63 +480,88 @@ fn connect() { mod server; ``` -Then create a *src/server.rs* file and enter the contents of the `server` -module that we extracted: + + + +そして、*src/server.rs*ファイルを作成し、抽出した`server`モジュールの中身を入力してください: + + -Filename: src/server.rs +ファイル名: src/server.rs ```rust fn connect() { } ``` -When we try to `cargo build`, we’ll get the error shown in Listing 7-4: + + +`cargo build`を試すと、リスト7-4に示したようなエラーが出ます: ```text $ cargo build Compiling communicator v0.1.0 (file:///projects/communicator) error: cannot declare a new module at this location +(エラー: この箇所では新規モジュールを宣言できません) --> src/network.rs:4:5 | 4 | mod server; | ^^^^^^ | note: maybe move this module `network` to its own directory via `network/mod.rs` +(注釈: もしかして、`network`というこのモジュールを`network/mod.rs`経由で独自のディレクトリに移すの) --> src/network.rs:4:5 | 4 | mod server; | ^^^^^^ note: ... or maybe `use` the module `server` instead of possibly redeclaring it +(注釈: それとも、再度宣言する可能性はなく、`server`というモジュールを`use`したの) --> src/network.rs:4:5 | 4 | mod server; | ^^^^^^ ``` -Listing 7-4: Error when trying to extract the `server` -submodule into *src/server.rs* + + + +リスト7-4: `server`サブモジュールを*src/server.rs*に抽出しようとしたときのエラー + + + + + +エラーは、`この箇所では新規モジュールを宣言できません`と忠告し、*src/network.rs*の`mod server;`行を指し示しています。 +故に、*src/network.rs*は、*src/lib.rs*と何かしら違うのです: 理由を知るために読み進めましょう。 -The error says we `cannot declare a new module at this location` and is -pointing to the `mod server;` line in *src/network.rs*. So *src/network.rs* is -different than *src/lib.rs* somehow: keep reading to understand why. + + -The note in the middle of Listing 7-4 is actually very helpful because it -points out something we haven’t yet talked about doing: +リスト7-4の真ん中の注釈は、非常に有用です。というのも、まだ話題にしていないことを指摘しているからです。 ```text note: maybe move this module `network` to its own directory via `network/mod.rs` ``` -Instead of continuing to follow the same file naming pattern we used -previously, we can do what the note suggests: + + -1. Make a new *directory* named *network*, the parent module’s name. -2. Move the *src/network.rs* file into the new *network* directory, and - rename *src/network/mod.rs*. -3. Move the submodule file *src/server.rs* into the *network* directory. +以前行ったファイル命名パターンに従い続けるのではなく、注釈が提言していることをすることができます: -Here are commands to carry out these steps: + + + + + +1. 親モジュール名である*network*という名前の新規*ディレクトリ*を作成する。 +2. *src/network.rs*ファイルを*network*ディレクトリに移し、 + *src/network/mod.rs*と名前を変える。 +3. サブモジュールファイルの*src/server.rs*を*network*ディレクトリに移す。 + + + +以下が、これを実行するコマンドです: ```text $ mkdir src/network @@ -394,9 +569,12 @@ $ mv src/network.rs src/network/mod.rs $ mv src/server.rs src/network ``` -Now when we try to run `cargo build`, compilation will work (we’ll still have -warnings though). Our module layout still looks like this, which is exactly the -same as it did when we had all the code in *src/lib.rs* in Listing 7-3: + + + + +`cargo build`を走らせたら、ようやくコンパイルは通ります(まだ警告はありますけどね)。 +モジュールの配置は以下のような感じになります。これは、リスト7-3で*src/lib.rs*に全てのコードを収めていたときと全く変わらないですね: ```text communicator @@ -405,7 +583,9 @@ communicator └── server ``` -The corresponding file layout now looks like this: + + +対応するファイルの配置は、以下のようになりました: ```text ├── src @@ -416,15 +596,24 @@ The corresponding file layout now looks like this: │ └── server.rs ``` -So when we wanted to extract the `network::server` module, why did we have to -also change the *src/network.rs* file to the *src/network/mod.rs* file and put -the code for `network::server` in the *network* directory in -*src/network/server.rs* instead of just being able to extract the -`network::server` module into *src/server.rs*? The reason is that Rust wouldn’t -be able to recognize that `server` was supposed to be a submodule of `network` -if the *server.rs* file was in the *src* directory. To clarify Rust’s behavior -here, let’s consider a different example with the following module hierarchy, -where all the definitions are in *src/lib.rs*: + + + + + + + + + + +では、`network::server`モジュールを抽出したかったときに、 +`network::server`モジュールを*src/server.rs*に直接抽出できずに、 +*src/network.rs*ファイルを*src/network/mod.rs*ファイルに変更し、 +`network::server`のコードを*network*ディレクトリ内の*src/network/server.rs*に置かなければならなかったのでしょうか? +理由は、*server.rs*ファイルが*src*ディレクトリにあると、コンパイラが、 +`server`は`network`のサブモジュールと考えられることを検知できないからです。 +ここでのコンパイラの動作をはっきりさせるために、以下のようなモジュール階層をもつ別の例を考えましょう。 +こちらでは、定義は全て*src/lib.rs*に存在します。 ```text communicator @@ -433,44 +622,76 @@ communicator └── client ``` -In this example, we have three modules again: `client`, `network`, and -`network::client`. Following the same steps we did earlier for extracting -modules into files, we would create *src/client.rs* for the `client` module. -For the `network` module, we would create *src/network.rs*. But we wouldn’t be -able to extract the `network::client` module into a *src/client.rs* file -because that already exists for the top-level `client` module! If we could put -the code for *both* the `client` and `network::client` modules in the -*src/client.rs* file, Rust wouldn’t have any way to know whether the code was -for `client` or for `network::client`. - -Therefore, in order to extract a file for the `network::client` submodule of -the `network` module, we needed to create a directory for the `network` module -instead of a *src/network.rs* file. The code that is in the `network` module -then goes into the *src/network/mod.rs* file, and the submodule -`network::client` can have its own *src/network/client.rs* file. Now the -top-level *src/client.rs* is unambiguously the code that belongs to the -`client` module. - -### Rules of Module Filesystems - -Let’s summarize the rules of modules with regard to files: - -* If a module named `foo` has no submodules, you should put the declarations - for `foo` in a file named *foo.rs*. -* If a module named `foo` does have submodules, you should put the declarations - for `foo` in a file named *foo/mod.rs*. - -These rules apply recursively, so if a module named `foo` has a submodule named -`bar` and `bar` does not have submodules, you should have the following files -in your *src* directory: + + + + + + + + + + +この例でも、モジュールは3つあります: `client`、`network`、`network::client`です。 +以前と同じ段階を経てモジュールをファイルに抽出すると、`client`モジュール用に*src/client.rs*を作成することになるでしょう。 +`network`モジュールに関しては、*src/network.rs*を作成します。しかし、 +`network::client`モジュールを*src/client.rs*ファイルに抽出することはできません。 +もうトップ階層の`client`モジュールとして存在するからです! +`client`と`network::client`*双方*のコードを*src/client.rs*ファイルに書くことができたら、 +コンパイラは、コードが`client`用なのか、`network::client`用なのか知る術を失ってしまいます。 + + + + + + + + + +従って、`network`モジュールの`network::client`サブモジュールをファイルに抽出するには、 +*src/network.rs*ファイルではなく、`network`モジュールのディレクトリを作成する必要があったわけです。 +そうすれば、`network`モジュールのコードは、*src/network/mod.rs*ファイルに移ることになり、 +`network::client`というサブモジュールは専用の`src/network/client.rs`ファイルを持てるわけです。 +これで、頂点にある*src/client.rs*は間違いなく、`client`モジュールに属するコードになるわけです。 + + + +### モジュールファイルシステムの規則 + + + +ファイルに関するモジュール規則をまとめましょう: + + + + + + +* `foo`という名前のモジュールにサブモジュールがなければ、`foo`の定義は、 + *foo.rs*というファイルに書くべきです。 +* `foo`というモジュールに本当にサブモジュールがあったら、`foo`の定義は、 + *foo/mod.rs*というファイルに書くべきです。 + + + + + +これらのルールは再帰的に適用されるので、`foo`というモジュールに`bar`というサブモジュールがあり、 +`bar`にはサブモジュールがなければ、*src*ディレクトリには以下のようなファイルが存在するはずです: ```text ├── foo │ ├── bar.rs (contains the declarations in `foo::bar`) +│ │ (`foo::bar`内の定義を含む) │ └── mod.rs (contains the declarations in `foo`, including `mod bar`) + (`mod bar`を含む、`foo`内の定義を含む) ``` -The modules should be declared in their parent module’s file using the `mod` -keyword. + + + +モジュールは、親モジュールのファイル内で`mod`キーワードを使って宣言されるべきなのです。 + + -Next, we’ll talk about the `pub` keyword and get rid of those warnings! +次は、`pub`キーワードについて話し、警告を取り除きます! From 5bce591710749fa909b37102be469e097826e2fc Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 8 Aug 2017 23:08:10 +0900 Subject: [PATCH 020/428] First draft of the chapter 7-2 --- ...ch07-02-controlling-visibility-with-pub.md | 415 ++++++++++++------ 1 file changed, 279 insertions(+), 136 deletions(-) diff --git a/second-edition/src/ch07-02-controlling-visibility-with-pub.md b/second-edition/src/ch07-02-controlling-visibility-with-pub.md index 73111648b..4973de011 100644 --- a/second-edition/src/ch07-02-controlling-visibility-with-pub.md +++ b/second-edition/src/ch07-02-controlling-visibility-with-pub.md @@ -1,11 +1,18 @@ -## Controlling Visibility with `pub` + -We resolved the error messages shown in Listing 7-4 by moving the `network` and -`network::server` code into the *src/network/mod.rs* and -*src/network/server.rs* files, respectively. At that point, `cargo build` was -able to build our project, but we still get warning messages about the -`client::connect`, `network::connect`, and `network::server::connect` functions -not being used: +## `pub`で公開するか制御する + + + + + + + + +リスト7-4に示したエラーメッセージを`network`と`network::server`のコードを、 +*src/network/mod.rs*と*src/network/server.rs*ファイルにそれぞれ移動することで解決しました。 +その時点で`cargo build`はプロジェクトをビルドできましたが、`client::connect`と`network::connect`と`network::server::connect`関数が、 +まだ使用されていないという警告メッセージが出ていました: ```text warning: function is never used: `connect`, #[warn(dead_code)] on by default @@ -27,18 +34,29 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default | ^ ``` -So why are we receiving these warnings? After all, we’re building a library -with functions that are intended to be used by our *users*, not necessarily by -us within our own project, so it shouldn’t matter that these `connect` -functions go unused. The point of creating them is that they will be used by -another project, not our own. + + + + + + +では、何故このような警告を受けているのでしょうか?結局のところ、必ずしも自分のプロジェクト内ではなく、 +*利用者*に利用されることを想定した関数を含むライブラリを構成しているので、 +これらの`connect`関数が使用されていかないということは、問題になるはずはありません。 +これらの関数を生成することの要点は、自分ではなく、他のプロジェクトで使用することにあるのです。 + + + + + -To understand why this program invokes these warnings, let’s try using the -`connect` library from another project, calling it externally. To do that, -we’ll create a binary crate in the same directory as our library crate by -making a *src/main.rs* file containing this code: +このプログラムがこのような警告を引き起こす理由を理解するために、外部から`connect`ライブラリを呼び出して、 +他のプロジェクトからこれを使用してみましょう。そうするには、以下のようなコードを含む*src/main.rs*を作成して、 +ライブラリクレートと同じディレクトリにバイナリクレートを作成します。 -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust,ignore extern crate communicator; @@ -48,62 +66,99 @@ fn main() { } ``` -We use the `extern crate` command to bring the `communicator` library crate -into scope. Our package now contains *two* crates. Cargo treats *src/main.rs* -as the root file of a binary crate, which is separate from the existing library -crate whose root file is *src/lib.rs*. This pattern is quite common for -executable projects: most functionality is in a library crate, and the binary -crate uses that library crate. As a result, other programs can also use the -library crate, and it’s a nice separation of concerns. - -From the point of view of a crate outside the `communicator` library looking -in, all the modules we’ve been creating are within a module that has the same -name as the crate, `communicator`. We call the top-level module of a crate the -*root module*. - -Also note that even if we’re using an external crate within a submodule of our -project, the `extern crate` should go in our root module (so in *src/main.rs* -or *src/lib.rs*). Then, in our submodules, we can refer to items from external -crates as if the items are top-level modules. - -Right now, our binary crate just calls our library’s `connect` function from -the `client` module. However, invoking `cargo build` will now give us an error -after the warnings: + + + + + + + + +`extern crate`コマンドを使用して、`communicator`ライブラリクレートをスコープに導入しています。 +パッケージには*2つ*のクレートが含まれるようになりました。Cargoは、*src/main.rs*をバイナリクレートのルートファイルとして扱い、 +これはルートファイルが*src/lib.rs*になる既存のライブラリクレートとは区別されます。このパターンは、 +実行形式プロジェクトで非常に一般的です: ほとんどの機能はライブラリクレートにあり、バイナリクレートはそれを使用するわけです。 +結果として、他のプログラムもまたこのライブラリクレートを使用でき、良い責任の分離になるわけです。 + + + + + + +`communicator`ライブラリの外部のクレートが検索するという観点から言えば、これまでに作ってきたモジュールは全て、 +`communicator`というクレートと同じ名前を持つモジュール内にあります。クレートのトップ階層のモジュールを、 +*ルートモジュール*と呼びます。 + + + + + + +プロジェクトのサブモジュール内で外部クレートを使用しているとしても、`extern crate`はルートモジュール(つまり、*src/main.rs*、 +または*src/lib.rs*)に書くべきということにも、注目してください。それから、 +サブモジュールで外部クレートの要素をトップ階層のモジュールかのように参照できるわけです。 + + + + + +現状、バイナリクレートは、`client`モジュールからライブラリの`connect`関数を呼び出しているだけです。 +ところが、`cargo build`を呼び出すと、警告の後にエラーが発生します: ```text error: module `client` is private +(エラー: `client`モジュールは非公開です) --> src/main.rs:4:5 | 4 | communicator::client::connect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` -Ah ha! This error tells us that the `client` module is private, which is the -crux of the warnings. It’s also the first time we’ve run into the concepts of -*public* and *private* in the context of Rust. The default state of all code in -Rust is private: no one else is allowed to use the code. If you don’t use a -private function within your program, because your program is the only code -allowed to use that function, Rust will warn you that the function has gone -unused. - -After we specify that a function like `client::connect` is public, not only -will our call to that function from our binary crate be allowed, but the -warning that the function is unused will go away. Marking a function as public -lets Rust know that the function will be used by code outside of our program. -Rust considers the theoretical external usage that’s now possible as the -function “being used.” Thus, when something is marked public, Rust will not -require that it be used in our program and will stop warning that the item is -unused. - -### Making a Function Public - -To tell Rust to make something public, we add the `pub` keyword to the start of -the declaration of the item we want to make public. We’ll focus on fixing the -warning that indicates `client::connect` has gone unused for now, as well as -the `` module `client` is private `` error from our binary crate. Modify -*src/lib.rs* to make the `client` module public, like so: - -Filename: src/lib.rs + + + + + + + + +ああ!このエラーは、`client`モジュールが非公開であることを教えてくれ、それが警告の肝だったわけです。 +Rustの文脈において、*公開*とか*非公開*という概念にぶち当たったのは、これが初めてでもあります。 +全コードの初期状態は、非公開です: 誰も他の人はコードを使用できないわけです。プログラム内で非公開の関数を使用していなければ、 +自分のプログラムだけがその関数を使用することを許可された唯一のコードなので、コンパイラは関数が未使用と警告してくるのです。 + + + + + + + + + + +`client::connect`のような関数を公開にすると指定した後は、バイナリクレートからその関数への呼び出しが許可されるだけでなく、 +関数が未使用であるという警告も消え去るわけです。関数を公開にすれば、コンパイラは、 +関数が自分のプログラム外のコードからも使用されることがあると知ります。コンパイラは、 +関数が「使用されている」という架空の外部使用の可能性を考慮してくれます。それ故に、何かが公開とマークされれば、 +コンパイラはそれが使用されるべきという要求をなくし、その要素が未使用という警告も止めるのです。 + + + +### 関数を公開にする + + + + + + + +コンパイラに何かを公開すると指示するには、公開にしたい要素の定義の先頭に`pub`キーワードを追記します。 +今は、`client::connect`が未使用であるとする警告とバイナリークレートの``モジュール`client`が非公開である``エラーの解消に努めます。 +*src/lib.rs*を弄って、`client`モジュールを公開にしてください。そう、こんな感じに: + + + +ファイル名: src/lib.rs ```rust,ignore pub mod client; @@ -111,7 +166,9 @@ pub mod client; mod network; ``` -The `pub` keyword is placed right before `mod`. Let’s try building again: + + +`pub`キーワードは、`mod`の直前に配置されています。再度ビルドしてみましょう: ```text error: function `connect` is private @@ -121,18 +178,26 @@ error: function `connect` is private | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` -Hooray! We have a different error! Yes, different error messages are a cause -for celebration. The new error shows `` function `connect` is private ``, so -let’s edit *src/client.rs* to make `client::connect` public too: + + + + +やった!違うエラーになりました!そうです、別のエラーメッセージは、祝杯を上げる理由になるのです。 +新エラーは、``関数`connect`は非公開です``と示しているので、*src/client.rs*を編集して、 +`client::connect`も公開にしましょう: -Filename: src/client.rs + + +ファイル名: src/client.rs ```rust pub fn connect() { } ``` -Now run `cargo build` again: + + +さて、再び、`cargo build`を走らせてください: ```text warning: function is never used: `connect`, #[warn(dead_code)] on by default @@ -148,21 +213,35 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default | ^ ``` -The code compiled, and the warning about `client::connect` not being used is -gone! + + + +コードのコンパイルが通り、`client:connect`が未使用という警告はなくなりました! + + + + + + + + + + +コード未使用警告が必ずしも、コード内の要素を公開にしなければならないことを示唆しているわけではありません: +これらの関数を公開APIの一部にしたく*なかった*ら、未使用コード警告がもう必要なく、安全に削除できるコードに注意を向けてくれる可能性もあります。 +また未使用コード警告は、ライブラリ内でこの関数を呼び出している箇所全てを誤って削除した場合に、 +バグに目を向けさせてくれる可能性もあります。 -Unused code warnings don’t always indicate that an item in your code needs to -be made public: if you *didn’t* want these functions to be part of your public -API, unused code warnings could be alerting you to code you no longer need that -you can safely delete. They could also be alerting you to a bug if you had just -accidentally removed all places within your library where this function is -called. + + + -But in this case, we *do* want the other two functions to be part of our -crate’s public API, so let’s mark them as `pub` as well to get rid of the -remaining warnings. Modify *src/network/mod.rs* to look like the following: +しかし今回は、本当に他の2つの関数もクレートの公開APIにしたいので、これも`pub`とマークして残りの警告を除去しましょう。 +*src/network/mod.rs*を変更して以下のようにしてください: -Filename: src/network/mod.rs + + +ファイル名: src/network/mod.rs ```rust,ignore pub fn connect() { @@ -171,7 +250,9 @@ pub fn connect() { mod server; ``` -Then compile the code: + + +そして、コードをコンパイルします: ```text warning: function is never used: `connect`, #[warn(dead_code)] on by default @@ -187,14 +268,21 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default | ^ ``` -Hmmm, we’re still getting an unused function warning, even though -`network::connect` is set to `pub`. The reason is that the function is public -within the module, but the `network` module that the function resides in is not -public. We’re working from the interior of the library out this time, whereas -with `client::connect` we worked from the outside in. We need to change -*src/lib.rs* to make `network` public too, like so: + + + + + + + +んんー、`nework::connect`は`pub`に設定されたにもかかわらず、まだ未使用関数警告が出ます。 +その理由は、関数はモジュール内で公開になったものの、関数が存在する`network`モジュールは公開ではないからです。 +今回は、ライブラリの内部から外に向けて作業をした一方、`client::connect`では、外から内へ作業をしていました。 +*src/lib.rs*を変えて`network`も公開にする必要があります。以下のように: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust,ignore pub mod client; @@ -202,7 +290,9 @@ pub mod client; pub mod network; ``` -Now when we compile, that warning is gone: + + +これでコンパイルすれば、あの警告はなくなります: ```text warning: function is never used: `connect`, #[warn(dead_code)] on by default @@ -212,23 +302,39 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default | ^ ``` -Only one warning is left! Try to fix this one on your own! + + +残る警告は1つ!自分で解消してみましょう! + + + +### プライバシー規則 + + + +まとめると、要素の公開性は以下のようなルールになります: + + + + + +1. 要素が公開なら、どの親モジュールを通してもアクセス可能です。 +2. 要素が非公開なら、直接の親モジュールとその親の子モジュールのみアクセスできます。 -### Privacy Rules + -Overall, these are the rules for item visibility: +### プライバシー例 -1. If an item is public, it can be accessed through any of its parent modules. -2. If an item is private, it can be accessed only by its immediate parent - module and any of the parent’s child modules. + + + -### Privacy Examples +もうちょっと鍛錬を得るために、もういくつかプライバシー例を見てみましょう。新しいライブラリプロジェクトを作成し、 +リスト7-5のコードを新規プロジェクトの*src/lib.rs*に入力してください: -Let’s look at a few more privacy examples to get some practice. Create a new -library project and enter the code in Listing 7-5 into your new project’s -*src/lib.rs*: + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust,ignore mod outermost { @@ -251,48 +357,85 @@ fn try_me() { } ``` -Listing 7-5: Examples of private and public functions, -some of which are incorrect + + + +リスト7-5: 公開と非公開関数の例。不正なものもあります + + + + + +このコードをコンパイルする前に、`try_me`関数のどの行がエラーになるか当ててみてください。 +それからコンパイルを試して、合ってたかどうか確かめ、エラーの議論を読み進めてください! + + + +#### エラーを確かめる + + + + + + +`try_me`関数は、プロジェクトのルートモジュールに存在しています。`outermost`という名前のモジュールは非公開ですが、 +プライバシー規則の2番目にある通り、`try_me`そのままに、`outermost`は現在(ルート)のモジュールなので、 +`try_me`関数は、`outermost`にアクセスすることを許可されるのです。 + + + + + + +`middle_function`は公開なので、`outermost::middle_function`という呼び出しも動作し、 +`try_me`は`middle_function`にその親モジュールの`outermost`を通してアクセスしています。 +前の段落でこのモジュールは、アクセス可能と決定しました。 + + + + + + +`outermost::middle_secret_function`の呼び出しは、コンパイルエラーになります。 +`middle_secret_function`は非公開なので、2番目の規則が適用されます。ルートモジュールは、 +`middle_secret_function`の現在のモジュール(`outermost`がそうです)でも、`middle_secret_function`のモジュールの子供でもないのです。 + + + + + -Before you try to compile this code, make a guess about which lines in the -`try_me` function will have errors. Then, try compiling the code to see whether -you were right, and read on for the discussion of the errors! +`inside`という名前のモジュールは非公開で子モジュールを持たないので、現在のモジュールである`outermost`からのみアクセスできます。 +つまり、`try_me`関数は、`outermost::inside::inner_function`も`outermost::inside::secret_function`も呼び出すことを許されないのです。 -#### Looking at the Errors + -The `try_me` function is in the root module of our project. The module named -`outermost` is private, but the second privacy rule states that the `try_me` -function is allowed to access the `outermost` module because `outermost` is in -the current (root) module, as is `try_me`. +#### エラーを修正する -The call to `outermost::middle_function` will work because `middle_function` is -public, and `try_me` is accessing `middle_function` through its parent module -`outermost`. We determined in the previous paragraph that this module is -accessible. + + + + -The call to `outermost::middle_secret_function` will cause a compilation error. -`middle_secret_function` is private, so the second rule applies. The root -module is neither the current module of `middle_secret_function` (`outermost` -is), nor is it a child module of the current module of `middle_secret_function`. +エラーを修正しようとする過程でできるコード変更案は、以下の通りです。各々試してみる前に、 +エラーを解消できるか当ててみてください。それからコンパイルして正しかったか間違っていたか確かめ、 +プライバシー規則を使用して理由を理解してください。 -The module named `inside` is private and has no child modules, so it can only -be accessed by its current module `outermost`. That means the `try_me` function -is not allowed to call `outermost::inside::inner_function` or -`outermost::inside::secret_function`. + + + + + -#### Fixing the Errors +* `inside`モジュールが公開だったらどうだろうか? +* `outermost`が公開で、`inside`が非公開ならどうだろうか? +* `inner_function`の本体で`::outermost::middle_secret_function()`を呼び出したらどうだろうか? + (頭の二つのコロンは、ルートモジュールから初めてモジュールを参照したいということを意味します) -Here are some suggestions for changing the code in an attempt to fix the -errors. Before you try each one, make a guess as to whether it will fix the -errors, and then compile the code to see whether or not you’re right, using the -privacy rules to understand why. + -* What if the `inside` module was public? -* What if `outermost` was public and `inside` was private? -* What if, in the body of `inner_function`, you called - `::outermost::middle_secret_function()`? (The two colons at the beginning mean - that we want to refer to the modules starting from the root module.) +自由にもっと実験を企てて、試してみてくださいね! -Feel free to design more experiments and try them out! + -Next, let’s talk about bringing items into scope with the `use` keyword. +今度は、`use`キーワードで要素をスコープに導入する話をしましょう。 From 6fab616eee3f66d7ffa092e76d4959a5057345c3 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 9 Aug 2017 19:13:51 +0900 Subject: [PATCH 021/428] First draft of the chapter 7-3 --- .../src/ch07-03-importing-names-with-use.md | 265 ++++++++++++------ 1 file changed, 181 insertions(+), 84 deletions(-) diff --git a/second-edition/src/ch07-03-importing-names-with-use.md b/second-edition/src/ch07-03-importing-names-with-use.md index dc31695fe..105ece5a5 100644 --- a/second-edition/src/ch07-03-importing-names-with-use.md +++ b/second-edition/src/ch07-03-importing-names-with-use.md @@ -1,10 +1,17 @@ -## Importing Names + -We’ve covered how to call functions defined within a module using the module -name as part of the call, as in the call to the `nested_modules` function shown -here in Listing 7-6: +## 名前をインポートする -Filename: src/main.rs + + + + +モジュール名を呼び出しの一部に使用してモジュール内に定義された関数の呼び出し方法を解説しました。 +リスト7-6に示した`nested_modules`関数の呼び出しのような感じですね: + + + +ファイル名: src/main.rs ```rust pub mod a { @@ -20,17 +27,28 @@ fn main() { } ``` -Listing 7-6: Calling a function by fully specifying its -enclosing module’s path + + + +リスト7-6: 囲まれたモジュールをフルパス指定して関数を呼び出す -As you can see, referring to the fully qualified name can get quite lengthy. -Fortunately, Rust has a keyword to make these calls more concise. + + -### Concise Imports with `use` +見てお分かりの通り、フルパス指定した名前を参照すると非常に長ったらしくなります。 +幸い、Rustには、これらの呼び出しをもっと簡潔にするキーワードが用意されています。 -Rust’s `use` keyword shortens lengthy function calls by bringing the modules of -the function you want to call into scope. Here’s an example of bringing the -`a::series::of` module into a binary crate’s root scope: + + +### `use`で簡潔なインポート + + + + + +Rustの`use`キーワードは、呼び出したい関数のモジュールをスコープに導入することで、 +長ったらしい関数呼び出しを短縮します。以下は、 +`a::series::of`モジュールをバイナリクレートのルートスコープに持ってくる例です: Filename: src/main.rs @@ -50,16 +68,24 @@ fn main() { } ``` -The line `use a::series::of;` means that rather than using the full -`a::series::of` path wherever we want to refer to the `of` module, we can use -`of`. + + + + +`use a::series::of`の行は、`of`モジュールを参照したい箇所全部でフルパスの`a::series::of`を使用するのではなく、 +`of`を利用できることを意味しています。 -The `use` keyword brings only what we’ve specified into scope: it does not -bring children of modules into scope. That’s why we still have to use -`of::nested_modules` when we want to call the `nested_modules` function. + + + -We could have chosen to bring the function into scope by instead specifying the -function in the `use` as follows: +この`use`キーワードは、指定したものだけをスコープに入れます: モジュールの子供はスコープに導入しないのです。 +そのため、`nested_modules`関数を呼び出したい際に、それでもまだ`of::nested_modules`を使わなければならないのです。 + + + + +以下のように、代わりに`use`で関数を指定して、関数をスコープに入れることもできます: ```rust pub mod a { @@ -77,13 +103,19 @@ fn main() { } ``` -Doing so allows us to exclude all the modules and reference the function -directly. + + + +そうすれば、モジュールをすべて取り除き、関数を直接参照することができます。 + + + + + -Because enums also form a sort of namespace like modules, we can import an -enum’s variants with `use` as well. For any kind of `use` statement, if you’re -importing multiple items from one namespace, you can list them using curly -braces and commas in the last position, like so: +enumもモジュールのようにある種の名前空間をなすので、enumのバリアントを`use`でインポートすることもできます。 +どんな`use`文に関しても、一つの名前空間から複数の要素をインポートする場合、波かっことお尻にカンマを使用することで列挙できます。 +こんな感じで: ```rust enum TrafficLight { @@ -101,13 +133,19 @@ fn main() { } ``` -We’re still specifying the `TrafficLight` namespace for the `Green` variant -because we didn’t include `Green` in the `use` statement. + + -### Glob Imports with `*` +`Green`を`use`文に含んでいないので、まだ`Green`バリアント用に`TrafficLight`名前空間を参照しています。 -To import all the items in a namespace at once, we can use the `*` syntax. For -example: + + +### `*`でまとめてインポート + + + + +ある名前空間の要素を全て一度にインポートするには、`*`表記が使用できます。例: ```rust enum TrafficLight { @@ -125,17 +163,28 @@ fn main() { } ``` -The `*` is called a *glob*, and it will import all items visible inside the -namespace. You should use globs sparingly: they are convenient, but this might -also pull in more items than you expected and cause naming conflicts. + + + + +`*`は*glob*(塊)と呼ばれ、名前空間内で公開されている要素全てをインポートします。 +あまりglobは使用するべきではありません: 便利ではありますが、予想以上の要素を引き込んで、 +名前衝突を引き起こすかもしれないのです。 -### Using `super` to Access a Parent Module + -As we saw at the beginning of this chapter, when you create a library crate, -Cargo makes a `tests` module for you. Let’s go into more detail about that now. -In your `communicator` project, open *src/lib.rs*: +### `super`を使用して親モジュールにアクセスする -Filename: src/lib.rs + + + + +この章の頭で見かけたように、ライブラリクレートを作成する際、Cargoは`tests`モジュールを用意してくれました。 +今からそれについて詳しく掘り下げていくことにしましょう。`communicator`プロジェクトで*src/lib.rs*を開いてください: + + + +ファイル名: src/lib.rs ```rust,ignore pub mod client; @@ -150,11 +199,15 @@ mod tests { } ``` -Chapter 11 explains more about testing, but parts of this example should make -sense now: we have a module named `tests` that lives next to our other modules -and contains one function named `it_works`. Even though there are special -annotations, the `tests` module is just another module! So our module hierarchy -looks like this: + + + + + + +第11章でテストについて詳しく説明しますが、これでこの例の一部が持つ意味がわかったのではないでしょうか: +他のモジュールに隣接する`tests`という名前のモジュールがあり、このモジュールは`it_works`という名前の関数を含んでいます。 +特別な注釈があるものの、`tests`モジュールもただのモジュールです!よって、モジュール階層は以下のような見た目になります: ```text communicator @@ -164,11 +217,16 @@ communicator └── tests ``` -Tests are for exercising the code within our library, so let’s try to call our -`client::connect` function from this `it_works` function, even though we won’t -be checking any functionality right now: + + + + +テストは、ライブラリ内でコードの準備運動を行うためのものなので、この`it_works`関数から`client::connect`関数を呼び出してみましょう。 +まあ、今のところは、機能の検査は何もしないんですけどね: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -180,58 +238,89 @@ mod tests { } ``` -Run the tests by invoking the `cargo test` command: + + +`cargo test`コマンドを呼び出してテストを実行してください: ```text $ cargo test Compiling communicator v0.1.0 (file:///projects/communicator) error[E0433]: failed to resolve. Use of undeclared type or module `client` +(エラー: 解決に失敗しました。未定義の型、またはモジュール`client`を使用しています) --> src/lib.rs:9:9 | 9 | client::connect(); | ^^^^^^^^^^^^^^^ Use of undeclared type or module `client` ``` -The compilation failed, but why? We don’t need to place `communicator::` in -front of the function like we did in *src/main.rs* because we are definitely -within the `communicator` library crate here. The reason is that paths are -always relative to the current module, which here is `tests`. The only -exception is in a `use` statement, where paths are relative to the crate root -by default. Our `tests` module needs the `client` module in its scope! + + + + + + + +コンパイルが失敗しましたが、なぜでしょうか?*src/main.rs*でしたように、関数の直前に`communicator::`を配置する必要はありません。 +なぜなら、間違いなくここでは、`communicator`ライブラリクレート内にいるからです。 +原因は、パスが常に現在のモジュールに対して相対的になり、ここでは`tests`になっているからです。 +唯一の例外は、`use`文内であり、パスは標準でクレートのルートに相対的になります。 +`tests`モジュールは、`client`モジュールがスコープに存在する必要があるのです! + + + + + -So how do we get back up one module in the module hierarchy to call the -`client::connect` function in the `tests` module? In the `tests` module, we can -either use leading colons to let Rust know that we want to start from the root -and list the whole path, like this: +では、どうやってモジュール階層を一つ上がり、`tests`モジュールの`client::connect`関数を呼び出すのでしょうか? +`tests`モジュールにおいて、先頭にコロンを使用して、コンパイラにルートから始めて、フルパスを列挙したいと知らせることもできます。 +こんな感じで: ```rust,ignore ::client::connect(); ``` -Or, we can use `super` to move up one module in the hierarchy from our current -module, like this: + + + +あるいは、`super`を使用して現在のモジュールからモジュール階層を一つ上がることもできます。 +以下のように: ```rust,ignore super::client::connect(); ``` -These two options don’t look that different in this example, but if you’re -deeper in a module hierarchy, starting from the root every time would make your -code lengthy. In those cases, using `super` to get from the current module to -sibling modules is a good shortcut. Plus, if you’ve specified the path from the -root in many places in your code and then you rearrange your modules by moving -a subtree to another place, you’d end up needing to update the path in several -places, which would be tedious. + + + + + + + + +この例では、これら二つの選択はそれほど異なるようには見えませんが、モジュール階層がもっと深ければ、 +常にルートから書き始めるのは、コードを冗長にする原因になります。そのような場合、 +`super`を使用して現在のモジュールから兄弟のモジュールに辿り着くのは、いいショートカットになります。 +さらに、コードのいろんなところでルートからパスを指定し、モジュール構造を変化させた場合、 +複数箇所でパスを更新する必要が出てきて、面倒なことになるでしょう。 + + + + + + +各テストで`super::`と入力しなければならないのも不快なことですが、それを解決してくれる道具をもう見かけています: +`use`です!`super::`の機能は、`use`に与えるパスを変更するので、ルートモジュールではなく、 +親モジュールに対して相対的になります。 -It would also be annoying to have to type `super::` in each test, but you’ve -already seen the tool for that solution: `use`! The `super::` functionality -changes the path you give to `use` so it is relative to the parent module -instead of to the root module. + + -For these reasons, in the `tests` module especially, `use super::something` is -usually the best solution. So now our test looks like this: +このような理由から、ことに`tests`モジュールにおいて`use super::somthing`は通常、 +最善策になるわけです。故に、今ではテストはこんな見た目になりました: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -245,8 +334,10 @@ mod tests { } ``` -When we run `cargo test` again, the test will pass and the first part of the -test result output will be the following: + + + +再度`cargo test`を実行すると、テストは通り、テスト結果出力の最初の部分は以下のようになるでしょう: ```text $ cargo test @@ -259,12 +350,18 @@ test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured ``` -## Summary + + +## まとめ + + + + -Now you know some new techniques for organizing your code! Use these techniques -to group related functionality together, keep files from becoming too long, and -present a tidy public API to your library users. +これでコードを体系化する新しいテクニックを知りましたね!これらのテクニックを使用して、 +関連のある機能をまとめ上げ、ファイルが長くなりすぎるのを防ぎ、ライブラリの使用者に整理整頓された公開APIを提供してください。 -Next, we’ll look at some collection data structures in the standard library -that you can use in your nice, neat code! + + +次は、自分の素晴らしく綺麗なコードで使用できる標準ライブラリのコレクションデータ構造について見ていきましょう! From 58c0a9e55944423d342d618c17fd4490a47cfa0a Mon Sep 17 00:00:00 2001 From: "Sunrin SHIMURA (keen)" <3han5chou7@gmail.com> Date: Wed, 16 Aug 2017 21:44:32 +0900 Subject: [PATCH 022/428] port the TranslationTable --- TranslationTable.md | 220 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 TranslationTable.md diff --git a/TranslationTable.md b/TranslationTable.md new file mode 100644 index 000000000..f39a4637a --- /dev/null +++ b/TranslationTable.md @@ -0,0 +1,220 @@ +# 原則 + +* カタカナ語のままで違和感のない用語はカタカナ語のまま使う + + 気持としては「無理矢理和訳」を避けたい。そのための基準。 + + カタカナ語の方が用語として認識しやすい +* 3音以上のカタカナ語の末尾の長音記号「ー」は省く([JIS Z 8301:2011](http://kikakurui.com/z8/Z8301-2011-01.html) G.6.2.2 b 表3を参照) +* 構文キーワードなどはそのままアルファベットを使う + +# 対訳表 + +| English | 日本語 +|:-------------------------------|:------------- +| abort | アボート +| (lockの) acquire | 獲得 +| aggregate type | 合成型 +| alignment | アラインメント +| allocate | アロケートする +| allocation | アロケーション +| allocator | アロケータ +| antipattern | アンチパターン +| application | アプリケーション +| arity | アリティ +| (マッチの)arm | 腕 +| array | 配列 +| assignment | 代入 +| associated - | 関連- +| atomic | アトミック +| attribute | アトリビュート +| binary | バイナリ +| binding | 束縛 +| block | ブロック +| borrowing | 借用 +| bounds | 境界 +| boxed | ボックス化された +| bug | バグ +| byte string | バイト列 +| capture | キャプチャ +| case analysis | 場合分け +| channel | チャネル +| closure | クロージャ +| coercion | 型強制 +| code bloat | コードの膨張 +| combinator | コンビネータ +| comma | カンマ +| command line | コマンドライン +| compile-time error | コンパイル時エラー +| compiler | コンパイラ +| compound data type | 複合データ型 +| composable | 合成可能 +| computer science | コンピュータサイエンス +| concurrency | 並行性 +| constant | 定数 +| constructor | コンストラクタ +| continuous integration | 継続的インテグレーション +| crate | クレート +| dangling | ダングリング +| data race | データ競合 +| deadlock | デッドロック +| deallocate | デアロケートする +| declaration statement | 宣言文 +| dereferencing | 参照外し +| destructor | デストラクタ +| destructuring | 分配 +| directive | ディレクティブ +| directory | ディレクトリ +| discriminant | 判別子 +| distribution | 配布物 +| diverge | 発散する +| diverging | 発散する〜(上の diverge を修飾語として使った場合) +| documentation comment | ドキュメンテーションコメント +| documentation test | ドキュメンテーションテスト +| early return | 早期リターン +| empty tuple | 空タプル +| encode | エンコード +| entry point | エントリポイント +| enum | 列挙型 +| equality | 等値性 +| ergonomic | エルゴノミック(人間にとって扱いやすいもの) +| error | エラー +| error handling | エラーハンドリング +| executable | 実行可能形式 +| existentially quantified type | 存在量型 +| expression statement | 式文 +| exterior | 外側の +| feature | フィーチャ +| foreign | 他言語 +| free | 解放する +| free-standing function | フリースタンディングな関数 +| garbage collector | ガベージコレクタ +| generic parameter | ジェネリックパラメータ +| generics | ジェネリクス +| glob | グロブ +| growable | 伸張可能 +| guard | ガード +| handle | ハンドル +| hash | ハッシュ +| identifier | 識別子 +| immutable | イミュータブル +| immutability | イミュータビリティ +| implement | 実装する +| initialize | 初期化する +| input lifetime | 入力ライフタイム +| interior | 内側の +| install | インストール +| installer | インストーラ +| interpolate | 補間する +| (string) interpolation | (文字列)補間 +| Intrinsics | Intrinsic +| key | キー +| keyword | キーワード +| Lang Items | Lang Item +| leak | リーク +| lending | 貸付け +| library | ライブラリ +| lifetime | ライフタイム +| lifetime elision | ライフタイムの省略 +| lifetime parameter | ライフタイムパラメータ +| link | リンク +| lint | リント +| lock | ロック +| mangling | マングリング +| match | マッチ +| match guards | マッチガード +| memory | メモリ +| method | メソッド +| monomorphization | 単相化 +| move | ムーブ +| mutability | ミュータビリティ +| mutable | ミュータブル +| mutable binding | ミュータブルな束縛 +| mutual-exclusion | 相互排他 +| null | ヌル +| object-safe | オブジェクト安全 +| offline | オフライン +| opaque | オペーク +| open source | オープンソース +| option | オプション +| output lifetime | 出力ライフタイム +| overflow | オーバーフロー +| owned | 所有権を持った +| owner | 所有者 +| ownership | 所有権 +| panic | パニック +| parameter | パラメータ +| parametric polymorphism | パラメトリック多相 +| parse | パース、パースする +| patch | パッチ +| pattern | パターン +| performance | パフォーマンス +| platform | プラットフォーム +| pointer | ポインタ +| process | プロセス +| range | 範囲 +| raw pointer | 生ポインタ +| raw string literal | 生文字列リテラル +| re-assignment | 再代入 +| rebind | 再束縛 +| reference | 参照 +| reference count | 参照カウント +| regression | リグレッション +| release | リリース +| (lockの) release | 解放 +| return | 返す +| return type | リターン型 +| return value | 戻り値 +| runtime | 実行時 +| safe | 安全 +| safety check | 安全性検査 +| scope | スコープ +| scoped | スコープ化された +| script | スクリプト +| semantics | セマンティクス +| shadow | 覆い隠す +| shadowing | シャドーイング +| signature | シグネチャ +| signed | 符号付き +| slice | スライス +| slicing | スライシング +| specialized | 特殊化された +| standard library | 標準ライブラリ +| string | 文字列 +| string interpolation | 文字列インターポーレーション +| string slice | 文字列スライス +| struct | 構造体 +| structure | ストラクチャ +| sum type | 直和型 +| symbol | シンボル +| syntactic sugar | 糖衣構文 +| syntax tree | 構文木 +| system | システム +| tagged union | タグ付き共用体 +| term | 項 +| thread-locality | スレッドローカル性 +| threadsafe | スレッドセーフ +| tick | クオート +| trait | トレイト +| tuple | タプル +| token trees | トークン木 +| type alias | 型エイリアス +| type erasure | 型消去 +| type family | 型族 +| type inference | 型推論 +| type parameter | 型パラメータ +| uninstall | アンインストール +| unit 注: `()` の読み | ユニット +| Universal Function Call Syntax | 共通の関数呼び出し構文 +| unsafe | アンセーフ +| unsigned | 符号無し +| unsized type | サイズ不定型 +| unwinding | 巻き戻し +| unwrap | アンラップ +| value constructor | 値コンストラクタ +| variable | 変数 +| variable binding | 変数束縛 +| variant | ヴァリアント +| vector | ベクタ +| version | バージョン +| warning | ウォーニング +| wildcard | ワイルドカード +| wrapper | ラッパ From a57048128021213a93e1fe48c2237abf4175d0a7 Mon Sep 17 00:00:00 2001 From: "Sunrin SHIMURA (keen)" <3han5chou7@gmail.com> Date: Wed, 16 Aug 2017 23:12:08 +0900 Subject: [PATCH 023/428] review ch2 --- .../src/ch02-00-guessing-game-tutorial.md | 154 +++++++++--------- 1 file changed, 76 insertions(+), 78 deletions(-) diff --git a/second-edition/src/ch02-00-guessing-game-tutorial.md b/second-edition/src/ch02-00-guessing-game-tutorial.md index eceb55fda..2fa425e1c 100644 --- a/second-edition/src/ch02-00-guessing-game-tutorial.md +++ b/second-edition/src/ch02-00-guessing-game-tutorial.md @@ -9,7 +9,7 @@ 実物のプロジェクトに一緒に取り組むことで、Rustの世界へ飛び込みましょう! -この章では、実際のプログラム内で使用する方法を通じて、いくつかの一般的なRustの概念に触れます。 +この章では、実際のプログラム内で使用しながらいくつかの一般的なRustの概念に触れます。 let文、match式、メソッド、関連関数、外部クレートの使用などについて学ぶでしょう! 後ほどの章でこれらの概念について深く知ることになります。この章では、基礎部分だけにしましょう。 @@ -21,7 +21,7 @@ let文、match式、メソッド、関連関数、外部クレートの使用な 古典的な初心者向けのプログラミング問題を実装してみましょう: 数当てゲームです。 これは以下のように動作します: プログラムは1から100までの乱数整数を生成します。 -さらにプレーヤーに予想を入力するよう促します。予想を入力し終わったら、プログラムは、 +そしてプレーヤーに予想を入力するよう促します。予想を入力したら、プログラムは、 その予想が少なすぎたか多すぎたかを出力します。予想が当たっていれば、ゲームが祝福してくれ、 そのまま終了します。 @@ -33,7 +33,7 @@ let文、match式、メソッド、関連関数、外部クレートの使用な 新規プロジェクトを立ち上げるには、第1章で作成した*projects*ディレクトリに行き、 -Cargoを使って新規プロジェクトを作成します。そう、以下のように: +Cargoを使って以下のように新規プロジェクトを作成します。 ```text $ cargo new guessing_game --bin @@ -69,7 +69,7 @@ authors = ["名前 "] -もし、Cargoがあなたの環境から取得した書き手情報が間違っていたら、 +もし、Cargoがあなたの環境から取得した作者情報が間違っていたら、 ファイルを編集して保存し直してください。 @@ -111,7 +111,7 @@ Hello, world! -*src/main.rs*ファイルを開き直しましょう。ここにすべてのコードを書いてきます。 +再度*src/main.rs*ファイルを開きましょう。ここにすべてのコードを書いてきます。 @@ -121,7 +121,7 @@ Hello, world! -プログラムの最初のパートは、ユーザに入力を求め、その入力を処理し、予期した形態になっていることを確認します。 +プログラムの最初のパートは、ユーザに入力を求め、その入力を処理し、予期した形式になっていることを確認します。 手始めにプレーヤーが予想を入力できるようにしましょう。 リスト2-1のコードを*src/main.rs*に入力してください。 @@ -174,17 +174,16 @@ use std::io; -標準では、コンパイラは、[*prelude*][prelude]に存在するいくつかの型しかプログラムで使用させてくれません。 +デフォルトでは、[*prelude*][prelude]に存在するいくつかの型のみ使えます。 もし、使用したい型がpreludeにない場合は、`use`文で明示的にその型をスコープに導入する必要があります。 -`std::io`ライブラリを使用することで、実用的な`入出力`関連の機能を使用することができます。 -ユーザ入力を受け付ける機能も含めてね。 +`std::io`ライブラリを使用することで、ユーザ入力を受け付けるなどの実用的な`入出力`関連の機能を使用することができます。 [prelude]: ../../std/prelude/index.html -第1章で目の当たりにした通り、`main`関数がプログラムへのエントリーポイント(スタート地点)になります: +第1章で見た通り、`main`関数がプログラムへのエントリーポイント(スタート地点)になります: ```rust,ignore fn main() { @@ -193,7 +192,7 @@ fn main() { -`fn`記法が関数を新しく宣言し、`()`は引数がないことを示し、`{`が関数本体のスタート地点になります。 +`fn`構文が関数を新しく宣言し、`()`は引数がないことを示し、`{`が関数本体のスタート地点になります。 @@ -276,7 +275,7 @@ let mut bar = 5; // mutable `::new`行にある`::`という記法は、`new`が`String`型の*関連付け関数*であることを表しています。 -関連付け関数とは、`String`型の特定のオブジェクトよりも型(この場合は`String`)に対して +関連関数とは、`String`型の特定のオブジェクトよりも型(この場合は`String`)に対して 実装された関数のことであり、*静的メソッド*と呼ばれる言語もあります。 @@ -289,7 +288,7 @@ let mut bar = 5; // mutable -まとめると、`let mut guess = String::new();`という行は、現在、新規で空の`String`オブジェクトに束縛されている +まとめると、`let mut guess = String::new();`という行は、現在、新たに空の`String`オブジェクトに束縛されている 可変変数を作っているわけです。ふう! @@ -297,7 +296,7 @@ let mut bar = 5; // mutable プログラムの1行目で、`use std::io`として、標準ライブラリから入/出力機能を取り込んだことを思い出してください。 -今度は、`io`型の`stdin`関連付け関数を呼び出しましょう: +今度は、`io`型の`stdin`関連関数を呼び出しましょう: ```rust,ignore io::stdin().read_line(&mut guess) @@ -321,8 +320,7 @@ io::stdin().read_line(&mut guess) その次のコード破片、`.read_line(&mut guess)`は、標準入力ハンドルの[`read_line`][read_line] -メソッドを呼び出して、ユーザから入力を受け付けます。また、`read_line`メソッドに対して、引数を一つ渡していますね: `&mut -guess`. +メソッドを呼び出して、ユーザから入力を受け付けます。また、`read_line`メソッドに対して、`&mut guess`という引数を一つ渡していますね. [read_line]: ../../std/io/struct.Stdin.html#method.read_line @@ -356,7 +354,7 @@ guess`. まだ、この行は終わりではありませんよ。テキストでは1行ですが、コードとしての論理行としては、 -まだ所詮最初の部分でしかないのです。2番目の部分はこのメソッドです。: +まだ所詮最初の部分でしかないのです。2番目の部分はこのメソッドです: ```rust,ignore .expect("Failed to read line"); @@ -366,7 +364,7 @@ guess`. -`.foo()`という記法で、メソッドを呼び出す時、改行と空白で長い行を分割するのは賢いことです。 +`.foo()`という記法で、メソッドを呼び出す時、改行と空白で長い行を分割するのが賢明です。 今回の場合、こう書くこともできますよね: ```rust,ignore @@ -391,8 +389,8 @@ io::stdin().read_line(&mut guess).expect("Failed to read line"); 以前にも述べたように、`read_line`メソッドは、渡された文字列にユーザが入力したものを入れ込むだけでなく、 値も返します(今回は[`io::Result`][ioresult]です)。 Rustには`Result`と名のついた型が -標準ライブラリにたくさんあります: ジェネリクスバージョンの[`Result`][result]の他、 -サブモジュール用の`io::Result`などの特別版まで。 +標準ライブラリにたくさんあります: 汎用の[`Result`][result]の他、 +`io::Result`などのサブモジュール用に特化したものまで。 [ioresult]: ../../std/io/type.Result.html [result]: ../../std/result/enum.Result.html @@ -413,9 +411,9 @@ enumについては、第6章で詳しく解説します。 -`Result`型に関しては、取りうる型の値(variant)は`Ok`か`Err`です。値`Ok`は、処理が成功したことを表し、 +`Result`型に関しては、取りうる型の値(バリアント)は`Ok`か`Err`です。`Ok`は、処理が成功したことを表し、 中に生成された値を保持します。`Err`は、処理が失敗したことを意味し、`Err`は、処理が失敗した過程や、 -理由などの情報を含有します。 +理由などの情報を保有します。 @@ -434,10 +432,10 @@ enumについては、第6章で詳しく解説します。 [`expect`メソッド][expect]があります。 この`io::Result`オブジェクトが`Err`値の場合、`expect`メソッドはプロラグムをクラッシュさせ、 引数として渡されたメッセージを表示します。`read_line`メソッドが`Err`を返したら、 -根底にあるOSによるエラーに起因する可能性が高くなります。 +恐らく根底にあるOSによるエラーに起因するのでしょう。 この`io::Result`オブジェクトが`Ok`値の場合、`expect`メソッドは、`Ok`バリアントが保持する -返り値を取り出して、ただその値を返すので、これを使用することができるかもしれません。 -今回の場合、その返り値とは、ユーザが標準入力に入力したバイト数になります。 +返り値を取り出して、ただその値を返すので、これを使用することができるでしょう。 +今回の場合、その返り値とは、ユーザが標準入力に入力したデータのバイト数になります。 [expect]: ../../std/result/enum.Result.html#method.expect @@ -537,7 +535,7 @@ You guessed(次のように予想したよ): 6 次に、ユーザが数当てに挑戦する秘密の数字を生成する必要があります。毎回この秘密の数字は、変わるべきです。 ゲームが何回も楽しめるようにですね。ゲームが難しくなりすぎないように、1から100までの乱数を使用しましょう。 -Rustの標準ライブラリには、乱数機能はまだ含まれていません。ですが、Rustチームが[`rand`クレート][randcrate]を +Rustの標準ライブラリには、乱数機能はまだ含まれていません。ですが、Rustの開発チームが[`rand`クレート][randcrate]を 用意してくれています。 [randcrate]: https://crates.io/crates/rand @@ -560,7 +558,7 @@ Rustの標準ライブラリには、乱数機能はまだ含まれていませ -Cargoを使って外部クレートを使用すると、Cargoがとても輝きます。`rand`を使ったコードを書くためには、 +外部クレートを使用する部分はCargoがとても輝くところです。`rand`を使ったコードを書くためには、 *Cargo.toml*ファイルを編集して、`rand`クレートを依存ファイルとして取り込む必要があります。 このファイルを開いて、以下の行をCargoが自動生成した`[dependencies]`セクションヘッダーの一番下に追記しましょう: @@ -586,17 +584,17 @@ rand = "0.3.14" *Cargo.toml*ファイルにおいて、ヘッダーに続くものは全て、他のセクションが始まるまで続くセクションの一部になります。 `[dependecies]`セクションは、プロジェクトが依存する外部クレートと必要とするバージョンを記述するところです。 -今は、`rand`クレートで、意味論的バージョンには`0.3.14`を指定します。Cargoは[意味論的バージョン付け][semver] -(時に*SemVer*と呼ばれる)を理解し、 意味論的バージョン付けは、バージョンナンバー記述の標準規格です。 +今は、`rand`クレートで、セマンティックバージョンには`0.3.14`を指定します。Cargoはバージョンナンバー記述の +標準規格であるところの[セマンティックバージョニング][semver] (時に*SemVer*と呼ばれる)を理解します。 `0.3.14`という数字は、実際には`^0.3.14`の省略記法で、これは、「バージョン0.3.14と互換性のある公開APIを持つ -バージョンならなんでも」を意味します。 +任意のバージョン」を意味します。 [semver]: http://semver.org -さて、コードは一切変えずに、プロジェクトをビルドしましょう。リスト2-2に示したようにね: +さて、コードは一切変えずに、リスト2-2のようにプロジェクトをビルドしましょう: ```text $ cargo build @@ -611,7 +609,7 @@ $ cargo build -リスト2-2: randクレートを依存ファイルとして追加した後の`cargo build`コマンドの出力 +リスト2-2: randクレートを依存として追加した後の`cargo build`コマンドの出力 @@ -624,7 +622,7 @@ $ cargo build -今や、外部依存ファイルを持つようになったので、Cargoは*registry*(登録所)から最新バージョンを拾ってきます。 +今や、外部依存を持つようになったので、Cargoは*レジストリ*(registry、登録所)から最新バージョンを拾ってきます。 *レジストリ*とは、[Crates.io][cratesio]のデータのコピーです. Crates.ioとは、Rustのエコシステムにいる人間が 他の人も使えるように自分のオープンソースのRustプロジェクトを投稿する場所です。 @@ -639,7 +637,7 @@ $ cargo build レジストリの更新後、Cargoは`[dependencies]`セクションをチェックし、まだ取得していないものを全部ダウンロードします。 今回の場合、`rand`しか依存ファイルには列挙していませんが、Cargoは`libc`のコピーも拾ってきます。 `rand`クレートが`libc`に依存しているからですね。ダウンロード完了後、コンパイラは依存ファイル、 -そして、依存ファイルが利用可能な状態でプロジェクトをコンパイルします。 +そして、依存が利用可能な状態でプロジェクトをコンパイルします。 @@ -650,9 +648,9 @@ $ cargo build 何も変更せず即座に`cargo build`コマンドを走らせたら、何も出力されないでしょう。 -Cargoは、すでに依存ファイルをダウンロードしてコンパイル済みであることを検知し、プログラマが -*Cargo.toml*ファイルを弄ってないからです。さらに、Cargoはプログラマがコードを変更していないことも -検知するので、再度コンパイルすることもありません。することがないので、ただ単に終了します。 +Cargoは、すでに全ての依存をダウンロードしてコンパイル済みであることも、あなたが +*Cargo.toml*ファイルを弄ってないことも知っているからです。さらに、Cargoはプログラマがコードを変更していない +ことも検知するので、再度コンパイルすることもありません。することがないので、ただ単に終了します。 *src/main.rs*ファイルを開き、些細な変更をし、保存して再度ビルドを行えば、1行だけ出力があるでしょう: ```text @@ -666,12 +664,12 @@ $ cargo build この行は、Cargoが*src/main.rs*ファイルへの取るに足らない変更に対してビルドを更新していることを示しています。 -依存ファイルは変更していないので、Cargoは、すでにダウンロードし、コンパイル済みの依存ファイルを使用できると +依存は変更していないので、Cargoは、すでにダウンロードしてコンパイルまで済ませてある依存を使用できると 検知します。自分で書いたコードのみ再ビルドをかけるわけです。 -#### *Cargo.lock*ファイルで再生成可能なビルドを保証する +#### *Cargo.lock*ファイルで再現可能なビルドを保証する @@ -681,7 +679,7 @@ $ cargo build Cargoには、プログラマが自分のコードを更新するたびに同じ生成物を再構成することを保証してくれるメカニズムを -備えています: Cargoは、プログラマが明示するまで、指定したバージョンの依存ファイルのみを使用してくれるでしょう。 +備えています: Cargoは、プログラマが明示するまで、指定したバージョンの依存のみを使用します。 例として、`rand`クレートの次週のバージョン`v0.3.15`が登場し、重要なバグ修正がなされているけれども、 自分のコードを破壊してしまう互換性破壊があった場合はどうなるでしょう? @@ -697,11 +695,11 @@ Cargoには、プログラマが自分のコードを更新するたびに同じ この問題に対する回答は、*Cargo.lock*ファイルであり、このファイルは、初めて`cargo build`コマンドを -走らせた時に生成され、*guessing_game*ディレクトリに存在しています。プロジェクトを始めてビルドする際に、 -Cargoは判断基準(criteria)に合致する依存ファイルのバージョンを割り出し、*Cargo.lock*ファイルに記述します。 +走らせた時に生成され、*guessing_game*ディレクトリに存在しています。プロジェクトを初めてビルドする際に、 +Cargoは判断基準(criteria)に合致するよう全ての依存のバージョンを計算し、*Cargo.lock*ファイルに記述します。 次にプロジェクトをビルドする際には、Cargoは*Cargo.lock*ファイルが存在することを確かめ、 -再度バージョン割り出しの作業を行うのではなく、そこに指定されているバージョンを使用するでしょう。 -このことにより、自動的に再生成可能なビルドを構成できるのです。つまり、明示的にアップグレードしない限り、 +再度バージョンの計算の作業を行うのではなく、そこに指定されているバージョンを使用します。 +このことにより、自動的に再現可能なビルドを構成できるのです。つまり、明示的にアップグレードしない限り、 プロジェクトが使用するバージョンは`0.3.14`に保たれるのです。*Cargo.lock*ファイルのおかげでね。 @@ -717,7 +715,7 @@ Cargoは判断基準(criteria)に合致する依存ファイルのバージョ -1. *Cargo.lock*ファイルを無視して*Cargo.toml*ファイルに指定された通りの最新バージョンを全て割り出します。 +1. *Cargo.lock*ファイルを無視して*Cargo.toml*ファイル内の全ての指定に合致する最新バージョンを計算します 1. それがうまくいったら、Cargoはそれらのバージョンを*Cargo.lock*ファイルに記述します。 @@ -725,7 +723,7 @@ Cargoは判断基準(criteria)に合致する依存ファイルのバージョ しかし標準でCargoは、`0.3.0`以上、`0.4.0`未満のバージョンのみを検索します。`rand`クレートの新バージョンが -2つリリースされていたら(`0.3.15`と`0.4.0`ですね)、`cargo update`コマンドを走らせた時に以下のような +2つリリースされていたら(`0.3.15`と`0.4.0`だとします)、`cargo update`コマンドを走らせた時に以下のような メッセージを目の当たりにするでしょう: ```text @@ -741,8 +739,8 @@ $ cargo update -ここで、プログラマはさらに*Cargo.lock*ファイルの中身の、現在使用している`rand`クレートのバージョンが、 -`0.3.15`になっていることに気付くでしょう。 +この時点で、*Cargo.lock*ファイルに書かれている現在使用している`rand`クレートのバージョンが、 +`0.3.15`になっていることにも気付くでしょう。 @@ -771,7 +769,7 @@ rand = "0.4.0" まだ第14章で議論する[Cargo][doccargo]と[そのエコシステム][doccratesio] については述べたいことが山ほどありますが、とりあえずは、これで知っておくべきことは全てです。 -Cargoのおかげでライブラリはとても簡単に再利用ができるので、Rust市民(Rustaceans)は数多くのパッケージから +Cargoのおかげでライブラリはとても簡単に再利用ができるので、Rustacean(Rustユーザのこと)は数多くのパッケージから 構成された小規模のプロジェクトを書くことができるのです。 [doccargo]: http://doc.crates.io @@ -784,7 +782,7 @@ Cargoのおかげでライブラリはとても簡単に再利用ができるの -`rand`クレートを*使用*開始しましょう。次のステップは、*src/main.rs*ファイルを更新することです。リスト2-3みたいにね: +`rand`クレートを*使用*開始しましょう。次のステップは、リスト2-3のように*src/main.rs*ファイルを更新することです: @@ -824,7 +822,7 @@ fn main() { -冒頭に`extern crate rand;`行を追加して、コンパイラにこの外部依存ファイルを使用することを知らせています。 +冒頭に`extern crate rand;`行を追加して、コンパイラにこの外部依存を使用することを知らせています。 これにより、`use rand`を呼ぶのと同じ効果が得られるので、`rand`クレートのものを`rand::` という接頭辞をつけて呼び出せるようになりました。 @@ -846,11 +844,11 @@ fn main() { -また、途中に2行追加もしています。`rand::thread_rng`関数は、私たちが使う特定の乱数生成器を -返してくれます: この乱数生成器は、実行スレッドに特有で、OSにより、シード値を与えられています。 +また、途中に2行追加もしています。`rand::thread_rng`関数は、これから使う特定の乱数生成器を +返してくれます: この乱数生成器は、実行スレッドに固有で、OSにより、シード値を与えられています。 次に、この乱数生成器の`gen_range`メソッドを呼び出しています。このメソッドは、`use rand::Rng`文で スコープに導入した`Rng`トレイトで定義されています。`gen_range`メソッドは二つの数字を引数に取り、 -それらの間の乱数を生成してくれます。最低値は含むものの、最高値は含まないため、`1`と`101`と指定しないと +それらの間の乱数を生成してくれます。範囲は下限値を含み、上限値を含まないため、`1`と`101`と指定しないと 1から100の範囲の数字は得られません。 @@ -862,8 +860,8 @@ fn main() { 使用すべきトレイトとクレートから呼び出すべき関数とメソッドを知ることが、単純に*知っている*ことではないでしょう。 -クレートの使用方法は、各クレートのドキュメントにある。Cargoの別の巧妙な機能は、`cargo doc --open`コマンドを -走らせてローカルに存在する依存ファィルすべてのドキュメントをビルドし、Webブラウザで閲覧できる機能です。例えば、 +クレートの使用方法は、各クレートのドキュメントにあります。Cargoの別の素晴しい機能は、`cargo doc --open`コマンドを +走らせてローカルに存在する依存すべてのドキュメントをビルドし、ブラウザで閲覧できる機能です。例えば、 `rand`クレートの他の機能に興味があるなら、`cargo doc --open`コマンドを走らせて、左側のサイドバーから `rand`をクリックすればいいわけです。 @@ -872,8 +870,8 @@ fn main() { -コードに追加した2行目は、秘密の数字を出力してくれます。これは、プログラムをテストする構築中には役立ちますが、 -最終版からは削除する予定です。プログラムがスタートと同時に答えを出力しちゃったら、ゲームにならないからですね! +コードに追加した2行目は、秘密の数字を出力してくれます。これは、プログラムを開発中にはテストするのに役立ちますが、 +最終版からは削除する予定です。プログラムがスタートと同時に答えを出力しちゃったら、ゲームになりませんからね! @@ -900,7 +898,7 @@ You guessed: 5 -毎回異なる乱数が出、その数字はすべて1から100の範囲になるはずです。よくやりました! +毎回異なる乱数が出て、その数字はすべて1から100の範囲になるはずです。よくやりました! @@ -959,7 +957,7 @@ fn main() { 最初の新しい点は、別の`use`文です。これで、`std::cmp::Ordering`という型を標準ライブラリから -スコープに導入しています。`Ordering`もenumです。`Result`のようにね。ただ、`Ordering`が取りうる値は、 +スコープに導入しています。`Result`と同じく`Ordering`もenumです。ただ、`Ordering`が取りうる値は、 `Less`、`Greater`そして、`Equal`です。これらは、2値比較した時に発生しうる3種類の結果です。 @@ -1000,9 +998,9 @@ match guess.cmp(&secret_number) { `match`式は、複数の*アーム*(腕)からできています。一つのアームは、パターンとそのパターンに `match`式の冒頭で与えた値がマッチした時に走るコードから構成されています。Rustは、`match`に与えられた -値を取り、各アームのパターンを順番に吟味していきます。`match`式とパターンは、コードを書く際に -目の当たりにする様々なシチュエーションを表現させてくれ、すべてのシチュエーションに対処する手助けをしてくれる -Rustの強力な機能です。これらの機能は、それぞれ、第6章と第18章で詳しく解説することにします。 +値を取り、各アームのパターンを順番に照合していきます。`match`式とパターンは、コードを書く際に +出会す様々なシチュエーションを表現させてくれ、すべてのシチュエーションに対処していることを保証するのを +手助けをしてくれるRustの強力な機能です。これらの機能は、それぞれ、第6章と第18章で詳しく解説することにします。 @@ -1019,11 +1017,11 @@ Rustの強力な機能です。これらの機能は、それぞれ、第6章と ここで使われている`match`式でどんなことが起こるかの例をじっくり観察してみましょう!例えば、 ユーザは50と予想し、ランダム生成された秘密の数字は今回、38だったとしましょう。コードが50と38を比較すると、 `cmp`メソッドは`Ordering::Greater`を返します。50は38よりも大きいからですね。`Ordering::Greater`が、 -`match`式に渡される値になります。まず、最初のアームのパターンを吟味します(`Ordering::Less`ですね)。しかし、 +`match`式に渡される値になります。まず、最初のアームのパターンと照合します(`Ordering::Less`ですね)。しかし、 値の`Ordering::Greater`と`Ordering::Less`はマッチしないため、このアームのコードは無視され、 次のアームに移ります。次のアームのパターン、`Ordering::Greater`は*見事に*`Ordering::Greater`とマッチします! このアームに紐づけられたコードが実行され、画面に`Too big!`が表示されます。 -これで`match`式の実行は終わりになります。この筋書きでは、最後のアームを吟味する必要はもうないからですね。 +これで`match`式の実行は終わりになります。この筋書きでは、最後のアームと照合する必要はもうないからですね。 @@ -1057,10 +1055,10 @@ Could not compile `guessing_game`. (`guessing_game`をコンパイルでき -このエラーの核は、*型の不一致*があると言っています。Rustは、強力な静的型付けシステムを持っています。 +このエラーの核は、*型の不一致*があると言っています。Rustは、強い静的型システムを持っています。 しかし、型推論にも対応しています。`let guess = String::new()`と書いた時、コンパイラは、 -`guess`が`String`型であるべきと推論してくれ、その型を明示させられることはありませんでした。 -一方で、`secret_number`変数は、数値型です。少数の数値型しか1から100を表すことはできません: +`guess`が`String`型であるはずと推論してくれ、その型を明示させられることはありませんでした。 +一方で、`secret_number`変数は、数値型です。1から100を表すことができる数値型はいくつかあります: `i32`は32ビットの数字; `u32`は32ビットの非負数字; `i64`は64ビットの数字;などです。 Rustでの標準は、`i32`型であり、型情報をどこかに追加して、コンパイラに異なる数値型だと推論させない限り、 `secret_number`の型はこれになります。エラーの原因は、Rustでは、文字列と数値型を比較できないことです。 @@ -1128,10 +1126,10 @@ let guess: u32 = guess.trim().parse() `guess`という名前の変数を生成しています。あれ、でも待って。もうプログラムには`guess`という名前の変数が -ありませんでしたっけ?確かにありますが、Rustでは、新しい値で`guess`の値を*多重定義*(shadow)することが +ありませんでしたっけ?確かにありますが、Rustでは、新しい値で`guess`の値を*覆い隠す*(shadow)ことが 許されているのです。この機能は、今回のような、値を別の型に変換したいシチュエーションでよく使われます。 -多重定義のおかげで別々の変数を2つ作らされることなく、`guess`という変数名を再利用することができるのです。 -`guess_str`と`guess`みたいなね(多重定義については、第3章でもっと掘り下げます)。 +シャドーイング(shadowing)のおかげで別々の変数を2つ作らされることなく、`guess`という変数名を再利用することができるのです。 +`guess_str`と`guess`みたいなね(シャドーイングについては、第3章でもっと掘り下げます)。 @@ -1166,11 +1164,11 @@ let guess: u32 = guess.trim().parse() -[文字列の`parse`メソッド][parse]は、文字列を解析して何らかの数値にします。 -このメソッドは、いろんな数値型を解析できるので、`let guess: u32`としてコンパイラに私たちが求めている型をズバリ示唆する必要があるのです。 +[文字列の`parse`メソッド][parse]は、文字列をパースして何らかの数値にします。 +このメソッドは、いろんな数値型をパースできるので、`let guess: u32`としてコンパイラに私たちが求めている型をズバリ示唆する必要があるのです。 `guess`の後のコロン(`:`)がコンパイラに変数の型を注釈する合図になります。 -Rustには、組み込みの数値型がいくつかあります; ここで見られる`u32`型は、32ビットの非負整数です。 -小さな非負整数は、良い基準になります。他の数値型については、第3章で学ぶでしょう。 +Rustには、組み込みの数値型がいくつかあります; ここの`u32`型は、32ビットの非負整数です。 +`u32`型は小さな非負整数のデフォルトの選択肢として丁度良いです。他の数値型については、第3章で学ぶでしょう。 付け加えると、このサンプルプログラムの`u32`という注釈と`secret_number`変数との比較は、 `secret_number`変数も`u32`型であるとコンパイラが推論することを意味します。 さて、従って、比較が同じ型の2つの値で行われることになります。 @@ -1294,7 +1292,7 @@ fn main() { -ユーザは、`Ctrl-C`というキーボードショートカットを使って、いつでもプログラムを強制終了させられます。 +ユーザは、Ctrl-Cというキーボードショートカットを使って、いつでもプログラムを強制終了させられます。 しかし、「予想を秘密の数字と比較する」節の`parse`メソッドに関する議論で触れたこの貪欲なモンスターを 回避する別の方法があります: ユーザが数字以外の答えを入力すれば、プログラムはクラッシュするのです。 ユーザは、その利点を活かして、終了することができます。以下のようにね: @@ -1450,7 +1448,7 @@ let guess: u32 = match guess.trim().parse() { 2番目のアームの`Err(_)`というパターンにはマッチするわけです。この`_`は、包括値です; この例では、 保持している情報がどんなものでもいいから全ての`Err`値にマッチさせたいと宣言しています。 従って、プログラムは2番目のアームのコードを実行し(`continue`ですね)、これは、`loop`の -次の段階に移り、再度予想入力を求めることを意味します。故に実効的には、プログラムは`parse`メソッドが +次の段階に移り、再度予想入力を求めることを意味します。故に実質的には、プログラムは`parse`メソッドが 遭遇しうる全てのエラーを無視するようになります! @@ -1555,7 +1553,7 @@ fn main() { このプロジェクトは、たくさんの新しいRustの概念に触れる実践的な方法でした: -`let`文、`match`式、メソッド、関連付け関数、外部クレートの使用などなど。 +`let`文、`match`式、メソッド、関連関数、外部クレートの使用などなど。 以降の数章で、これらの概念についてより深く学ぶことになるでしょう。 第3章では、ほとんどのプログラミング言語が持っている、変数、データ型、関数などの概念について解説し、 それらのRustでの使用方法について示します。 From a78c61a094cc42ddc09a5fe484c4366168e1dc58 Mon Sep 17 00:00:00 2001 From: "Sunrin SHIMURA (keen)" <3han5chou7@gmail.com> Date: Wed, 16 Aug 2017 23:12:33 +0900 Subject: [PATCH 024/428] update TranslationTable --- TranslationTable.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/TranslationTable.md b/TranslationTable.md index f39a4637a..96f3d4676 100644 --- a/TranslationTable.md +++ b/TranslationTable.md @@ -58,6 +58,7 @@ | deadlock | デッドロック | deallocate | デアロケートする | declaration statement | 宣言文 +| (crateの)dependency | 依存 | dereferencing | 参照外し | destructor | デストラクタ | destructuring | 分配 @@ -90,13 +91,13 @@ | generic parameter | ジェネリックパラメータ | generics | ジェネリクス | glob | グロブ -| growable | 伸張可能 +| growable | サイズ可変 | guard | ガード | handle | ハンドル | hash | ハッシュ | identifier | 識別子 -| immutable | イミュータブル -| immutability | イミュータビリティ +| immutable | 不変 +| immutability | 不変性 | implement | 実装する | initialize | 初期化する | input lifetime | 入力ライフタイム @@ -125,9 +126,9 @@ | method | メソッド | monomorphization | 単相化 | move | ムーブ -| mutability | ミュータビリティ -| mutable | ミュータブル -| mutable binding | ミュータブルな束縛 +| mutability | 可変性 +| mutable | 可変 +| mutable binding | 可変束縛 | mutual-exclusion | 相互排他 | null | ヌル | object-safe | オブジェクト安全 @@ -169,6 +170,7 @@ | scope | スコープ | scoped | スコープ化された | script | スクリプト +| semantic versioning | セマンティックバージョニング | semantics | セマンティクス | shadow | 覆い隠す | shadowing | シャドーイング @@ -212,7 +214,7 @@ | value constructor | 値コンストラクタ | variable | 変数 | variable binding | 変数束縛 -| variant | ヴァリアント +| variant | バリアント | vector | ベクタ | version | バージョン | warning | ウォーニング From baaf71b499ff533d4db415075f9ccac86e753b92 Mon Sep 17 00:00:00 2001 From: "Sunrin SHIMURA (keen)" <3han5chou7@gmail.com> Date: Fri, 18 Aug 2017 10:10:48 +0900 Subject: [PATCH 025/428] review ch03-00 --- second-edition/src/ch03-00-common-programming-concepts.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/second-edition/src/ch03-00-common-programming-concepts.md b/second-edition/src/ch03-00-common-programming-concepts.md index 4c4c07770..9c7fb600b 100644 --- a/second-edition/src/ch03-00-common-programming-concepts.md +++ b/second-edition/src/ch03-00-common-programming-concepts.md @@ -8,8 +8,8 @@ この章では、ほとんど全てのプログラミング言語で見られる概念を解説し、それらがRustにおいて、 -どう動作するかを見ていこう。多くのプログラミング言語は、その核心において、いろいろなものを共有しています。 -この章で提示する概念は、全てRustに固有のものではありませんが、Rustの文脈で議論し、その規格を +どう動作するかを見ていきます。多くのプログラミング言語は、その核心において、いろいろなものを共有しています。 +この章で提示する概念は、全てRustに固有のものではありませんが、Rustの文脈で議論し、その仕様を 解説していきます。 @@ -33,8 +33,8 @@ > ### キーワード > > Rust言語にも他の言語同様、キーワードが存在し、これらは言語だけが使用できるようになっています。 -> これらの単語は、変数や関数名には使えないことを弁えておいてください。多数のキーワードは、特別な意味を持っており、 +> これらの単語は、変数や関数名には使えないことを弁えておいてください。ほとんどのキーワードは、特別な意味を持っており、 > 自らのRustプログラムにおいて、様々な作業をこなすために使用することができます; -> いくつかは、紐付けられた機能がないものの、将来Rustに追加されるかもしれない機能用に担保されています。 +> いくつかは、紐付けられた機能がないものの、将来Rustに追加されるかもしれない機能用に予約されています。 > キーワードの一覧は、付録Aで確認できます。 From aa56db7b7c087435b928e20448ef1156cb9ba3d8 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 26 Aug 2017 21:43:49 +0900 Subject: [PATCH 026/428] Fix some errors in the Chapter 4-3 --- second-edition/src/ch04-03-slices.md | 28 ++++++++++--------- .../src/ch07-03-importing-names-with-use.md | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/second-edition/src/ch04-03-slices.md b/second-edition/src/ch04-03-slices.md index 3a6327c9b..5a6341cf0 100644 --- a/second-edition/src/ch04-03-slices.md +++ b/second-edition/src/ch04-03-slices.md @@ -62,7 +62,7 @@ fn first_word(s: &String) -> usize { このコードを少し噛み砕いていきましょう。`String`の値を要素ごとに見て、空白かどうかを確かめる必要があるので、 -`as_bytes`メソッドを使って、`String`オブジェクトをバイト配列に変換しました。 +`as_bytes`メソッドを使って、`String`オブジェクトをバイト配列に変換しています。 ```rust,ignore let bytes = s.as_bytes(); @@ -83,7 +83,7 @@ for (i, &item) in bytes.iter().enumerate() { -イテレータについて詳しくは、第13章で議論します。今は、`iter`は、コレクション内の各要素を返す関数であること、 +イテレータについて詳しくは、第13章で議論します。今は、`iter`は、コレクション内の各要素を返すメソッドであること、 `enumerate`が`iter`の結果を包んで、代わりにタプルの一部として各要素を返すことを知っておいてください。 戻り値のタプルの第1要素は、番号であり、2番目の要素は、(コレクションの)要素への参照になります。 これは、手動で番号を計算するよりも少しだけ便利です。 @@ -241,7 +241,7 @@ let world = &s[6..11]; これは、`String`全体への参照を取ることに似ていますが、余計な`[0..5]`という部分が付いています。 `String`全体への参照というよりも、`String`の一部への参照です。`開始..終点`という記法は、`開始`から始まり、 -`終端`未満までずっと続く範囲です。 +`終点`未満までずっと続く範囲です。 @@ -251,9 +251,9 @@ let world = &s[6..11]; -`[starting_index..ending_index`と指定することで、角かっこに範囲を使い、スライスを生成できます。 +`[starting_index..ending_index]`と指定することで、角かっこに範囲を使い、スライスを生成できます。 ここで、`starting_index`はスライスに含まれる最初の位置、`ending_index`はスライスに含まれる終端位置よりも、 -1大きくなります。内部的には、スライスデータは、開始地点とスライスの長さを保持しており、 +1大きくなります。内部的には、スライスデータ構造は、開始地点とスライスの長さを保持しており、 スライスの長さは`ending_index`から`starting_index`を引いたものに対応します。以上より、 `let world = &s[6..11];`の場合には、`world`は`s`の6バイト目へのポインタと5という長さを保持するスライスになるでしょう。 @@ -261,12 +261,14 @@ let world = &s[6..11]; 図4-12は、これを図解しています。 -world containing a pointer to the 6th byte of String s and a length 5 + + +文字列sの6バイト目へのポインタと長さ5を保持するworld -`String`オブジェクトの一部を参照する文字列スライス +図4-12: `String`オブジェクトの一部を参照する文字列スライス @@ -452,7 +454,7 @@ let s = "Hello, world!"; リテラルや`String`のスライスを得ることができると知ると、`first_word`に対して、もう一つ改善点を見出すことができます。 -それはシグニチャです: +シグニチャです: ```rust,ignore fn first_word(s: &String) -> &str { @@ -474,7 +476,7 @@ fn first_word(s: &str) -> &str { もし、文字列スライスがあるなら、それを直接渡せます。`String`オブジェクトがあるなら、 -その`String`全体のスライスを渡せます。Stringへの参照の代わりに文字列リテラルを取るよう関数を定義すると、 +その`String`全体のスライスを渡せます。Stringへの参照の代わりに文字列スライスを取るよう関数を定義すると、 何も機能を失うことなくAPIをより一般的で有益なものにできるのです。 Filename: src/main.rs @@ -531,8 +533,8 @@ fn main() { // first_wordは文字列リテラルのスライスに対して機能する let word = first_word(&my_string_literal[..]); - // 文字列リテラルは、すでに文字列リテラル*なの*で、 - // こちらも、スライス記法なしで機能するのだ! + // 文字列リテラルは、すでに文字列スライス*な*ので、 + // スライス記法なしでも機能するのだ! let word = first_word(my_string_literal); } ``` @@ -568,7 +570,7 @@ let slice = &a[1..3]; -このスライスは、`&[i32]`という型になります。これも文字列リテラルと全く同じ方法で動作しています。 +このスライスは、`&[i32]`という型になります。これも文字列スライスと全く同じように動作します。 つまり、最初の要素への参照と長さを保持することです。他のすべての種類のコレクションに対して、 この種のスライスは使用することができるでしょう。これらのコレクションについて詳しくは、 第8章でベクタ型について話すときに議論します。 @@ -585,7 +587,7 @@ let slice = &a[1..3]; 所有権、借用、スライスの概念は、コンパイル時にRustプログラムにおいて、メモリ安全性を確保するものです。 Rust言語も他のシステムプログラミング言語同様、メモリの使用法について制御させてくれるわけですが、 -データの所有者に所有者がスコープを抜けたときに自動的にデータを片付けさせることは、この制御を得るために、 +所有者がスコープを抜けたときにデータの所有者に自動的にデータを片付けさせることは、この制御を得るために、 余計なコードを書いてデバッグする必要がないことを意味します。 diff --git a/second-edition/src/ch07-03-importing-names-with-use.md b/second-edition/src/ch07-03-importing-names-with-use.md index 105ece5a5..a22f0a510 100644 --- a/second-edition/src/ch07-03-importing-names-with-use.md +++ b/second-edition/src/ch07-03-importing-names-with-use.md @@ -6,7 +6,7 @@ -モジュール名を呼び出しの一部に使用してモジュール内に定義された関数の呼び出し方法を解説しました。 +モジュール名を呼び出しの一部に使用して、モジュール内に定義された関数の呼び出し方法を解説しました。 リスト7-6に示した`nested_modules`関数の呼び出しのような感じですね: From b90d369b6cc009e92c5d18d6d01af5715c918ea4 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 26 Aug 2017 22:06:44 +0900 Subject: [PATCH 027/428] Fix some errors in the Chapter 4-2 --- second-edition/src/ch04-02-references-and-borrowing.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/second-edition/src/ch04-02-references-and-borrowing.md b/second-edition/src/ch04-02-references-and-borrowing.md index 43ccba322..0e7114694 100644 --- a/second-edition/src/ch04-02-references-and-borrowing.md +++ b/second-edition/src/ch04-02-references-and-borrowing.md @@ -50,7 +50,9 @@ fn calculate_length(s: &String) -> usize { これらのアンド記号が参照であり、これのおかげで所有権をもらうことなく値を参照することができるのです。 図4-8はその図解です。 -&String s pointing at String s1 + + +文字列s1を指す&String型のs @@ -355,7 +357,7 @@ immutable ポインタのある言語では、誤ってダングリングポインタを生成してしまいやすいです。ダングリングポインタとは、 他人に渡されてしまった可能性のあるメモリを指すポインタのことであり、その箇所へのポインタを保持している間に、 メモリを解放してしまうことで発生します。対照的にRustでは、コンパイラが、 -参照がダングリング参照に絶対ならないよう保証しくれます:つまり、何らかのデータへの参照があったら、 +参照がダングリング参照に絶対ならないよう保証してくれます:つまり、何らかのデータへの参照があったら、 コンパイラは参照がスコープを抜けるまで、データがスコープを抜けることがないよう確認してくれるわけです。 From 0d80cf0b2e9b92037f340fbdd806ca8070e9a60a Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 26 Aug 2017 23:09:52 +0900 Subject: [PATCH 028/428] Fix some errors in the Chapter 4-1 --- .../src/ch04-01-what-is-ownership.md | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/second-edition/src/ch04-01-what-is-ownership.md b/second-edition/src/ch04-01-what-is-ownership.md index ce9a7b0ca..56cc028f5 100644 --- a/second-edition/src/ch04-01-what-is-ownership.md +++ b/second-edition/src/ch04-01-what-is-ownership.md @@ -129,7 +129,7 @@ Rustの中心的な機能は、*所有権*です。機能は説明するのに > 保管することができますが、実データが必要になったら、ポインタを追いかける必要があります。 > > レストランで席を確保することを考えましょう。入店したら、グループの人数を告げ、店員が全員座れる -> 空いている席を探し、そこまで誘導します。もしグループの誰かが遅れて来るのなら、着いた席の場所を訪ねて +> 空いている席を探し、そこまで誘導します。もしグループの誰かが遅れて来るのなら、着いた席の場所を尋ねて > あなたを発見することができます。 > > ヒープへのデータアクセスは、スタックのデータへのアクセスよりも低速です。ポインタを追って目的の場所に @@ -338,7 +338,7 @@ println!("{}", s); // これは`hello, world!`と出力する 文字列リテラルの場合、中身はコンパイル時に判明しているので、テキストは最終的なバイナリファイルに直接ハードコードされます。 -その結果、文字列リテラルは、高速で効率的になるのです。しかし、これらの要素は、その不変性にのみ +その結果、文字列リテラルは、高速で効率的になるのです。しかし、これらの特性は、その不変性にのみ 端を発するものです。残念なことに、コンパイル時にサイズが不明だったり、プログラム実行に合わせてサイズが 可変なテキスト片用に一塊のメモリをバイナリに確保しておくことは不可能です。 @@ -354,13 +354,13 @@ println!("{}", s); // これは`hello, world!`と出力する 1. メモリは、実行時にOSに要求される。 -2. `String`型を使用し終わったら、OSにこのメモリを変換する方法が必要である。 +2. `String`型を使用し終わったら、OSにこのメモリを返還する方法が必要である。 -この最初の部分は、すでにしています: `String::from`関数を読んだら、その実装が必要なメモリを要求するのです。 +この最初の部分は、すでにしています: `String::from`関数を呼んだら、その実装が必要なメモリを要求するのです。 これは、プログラミング言語において、極めて普遍的です。 @@ -435,7 +435,7 @@ Rustは、異なる道を歩んでいます: ひとたび、メモリを所有 このパターンは、Rustコードの書かれ方に甚大な衝撃をもたらします。現状は簡単そうに見えるかもしれませんが、 ヒープ上に確保されたデータを複数の変数に使用させるようなもっと複雑な場面では、コードの振る舞いは、 -予期しないものになる可能性もあります。 +予期しないものになる可能性もあります。これから、そのような場面を掘り下げてみましょう。 @@ -463,7 +463,7 @@ to `y` --> -もしかしたら、他の言語の経験に基づいて、これが何をしているのか予想することができるでしょう: +もしかしたら、他の言語の経験に基づいて、何をしているのか予想することができるでしょう: 「値`5`を`x`に束縛する; それから`x`の値をコピーして`y`に束縛する。」これで、二つの変数(`x`と `y`)が存在し、両方、値は`5`になりました。これは確かに起こっている現象を説明しています。 なぜなら、整数は既知の固定サイズの単純な値で、これら二つの`5`という値は、スタックに積まれるからです。 @@ -496,7 +496,9 @@ let s2 = s1; メモリへのポインタと長さ、そして、許容量です。この種のデータは、スタックに保持されます。 右側には、ヒープ上の中身を保持したメモリがあります。 -String in memory + + +メモリ上の文字列 @@ -523,7 +525,9 @@ OSから受け取った全メモリ量をバイトで表したものです。長 コピーするということです。ポインタが指すヒープ上のデータはコピーしません。言い換えると、メモリ上のデータ表現は 図4-4のようになるということです。 -s1 and s2 pointing to the same value + + +同じ値を指すs1とs2 @@ -540,7 +544,9 @@ that has a copy of the pointer, length, and capacity of `s1` --> という選択をしていた場合のメモリ表現ですね。Rustがこれをしていたら、ヒープ上のデータが大きい時に `s2 = s1`という処理の実行時性能がとても悪くなっていた可能性があるでしょう。 -s1 and s2 to two places + + +2箇所へのs1とs2 @@ -568,7 +574,7 @@ do if Rust copied the heap data as well --> - + メモリ安全性を保証するために、Rustにおいてこの場面で知っておきたい起こる事の詳細がもう一つあります。 確保されたメモリをコピーしようとする代わりに、コンパイラは、`s1`が最早有効ではないと考え、故に @@ -613,11 +619,13 @@ which does not implement the `Copy` trait 他の言語を触っている間に"shallow copy"と"deep copy"という用語を耳にしたことがあるなら、 データのコピーなしにポインタと長さ、許容量をコピーするという概念は、shallow copyのように思えるかもしれません。 -ですが、コンパイラは最初の変数を無効化するので、これをshallow copyと呼ぶ代わりに、 +ですが、コンパイラは最初の変数をも無効化するので、これをshallow copyと呼ぶ代わりに、 ムーブとして知られているわけです。ここでは、`s1`は`s2`に*ムーブ*されたと解読します。 以上より、実際に起きることを図4-6に示してみました。 -s1 moved to s2 + + +s2にムーブされたs1 @@ -736,7 +744,7 @@ Rustには`Copy`トレイトと呼ばれる特別な注釈があり、整数の では、どの型が`Copy`なのでしょうか?ある型について、ドキュメントをチェックすればいいのですが、 一般規則として、単純なスカラー値の集合は何でも`Copy`であり、メモリ確保が必要だったり、 -何らかの携帯のリソースだったりするものは`Copy`ではありません。ここに`Copy`の型を並べておきます。 +何らかの形態のリソースだったりするものは`Copy`ではありません。ここに`Copy`の型を並べておきます。 @@ -744,9 +752,9 @@ Rustには`Copy`トレイトと呼ばれる特別な注釈があり、整数の -* 全部の整数型。`u32`など。 +* あらゆる整数型。`u32`など。 * 論理値型、`bool`、`true`と`false`という値がある。 -* 全部の浮動小数点型、`f64`など。 +* あらゆる浮動小数点型、`f64`など。 * タプル。ただ、`Copy`の型だけを含む場合。`(i32, i32)`は`Copy`だが `(i32, String)`は違う。 @@ -969,5 +977,5 @@ fn calculate_length(s: String) -> (String, usize) { -でも、これでは、大袈裟すぎますし、ありふれているはずの概念に対して、作業量が多すぎます。私たちにとって -幸運なことにRustにはこの概念に対する機能があり、それは*参照*と呼ばれます。 +でも、これでは、大袈裟すぎますし、ありふれているはずの概念に対して、作業量が多すぎます。 +私たちにとって幸運なことに、Rustにはこの概念に対する機能があり、それは*参照*と呼ばれます。 From bc29d954a2a66a2e28502047e43f6186c929c1bf Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 26 Aug 2017 23:11:55 +0900 Subject: [PATCH 029/428] Fix an error in the Chapter 4-0 --- second-edition/src/ch04-00-understanding-ownership.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch04-00-understanding-ownership.md b/second-edition/src/ch04-00-understanding-ownership.md index e0fb8efd8..397735217 100644 --- a/second-edition/src/ch04-00-understanding-ownership.md +++ b/second-edition/src/ch04-00-understanding-ownership.md @@ -2,7 +2,7 @@ # 所有権を理解する - + From 15b711306c09a570f222ace3c1a6f6bd3b0a451b Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 27 Aug 2017 18:46:03 +0900 Subject: [PATCH 030/428] Fix some errors and revise the content in the Chapter 3-1 --- .../src/ch03-01-variables-and-mutability.md | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/second-edition/src/ch03-01-variables-and-mutability.md b/second-edition/src/ch03-01-variables-and-mutability.md index 6c1962085..e6b777453 100644 --- a/second-edition/src/ch03-01-variables-and-mutability.md +++ b/second-edition/src/ch03-01-variables-and-mutability.md @@ -8,17 +8,17 @@ -第2章で触れた通り、変数は標準で*不変*になります。これは、Rustが提供する安全性や簡潔な並列プログラミングの -利点を享受する形でコードを書くことを推奨してくれる一押しです。ところが、まだ変数を可変にするという -選択肢も残されています。不変性を好むようコンパイラが推奨する手段と理由および、それと違う道を選びたくなる理由を -見ていきましょう。 +第2章で触れた通り、変数は標準で*不変*になります。これは、 +Rustが提供する安全性や簡潔な並列プログラミングの利点を享受する形でコードを書くことを推奨してくれる一押しです。 +ところが、まだ変数を可変にするという選択肢も残されています。不変性を好むようコンパイラが推奨する手段と理由および、 +それと違う道を選びたくなる理由を見ていきましょう。 変数が不変であるとは、値が一旦名前に束縛されたら、その値を変えることができないことを意味します。 -具体化するために、*projects*ディレクトリに`cargo new --bin variables`コマンドを使って +具体化するために、*projects*ディレクトリに`cargo new --bin variables`コマンドを使って、 *variables*という名前のプロジェクトを生成しましょう。 @@ -66,8 +66,8 @@ error[E0384]: re-assignment of immutable variable `x` この例では、コンパイラがプログラムに潜むエラーを見つけ出す手助けをしてくれることが示されています。 -コンパイルエラーは、イライラするものですが、まだプログラムにしてほしいことを安全に行えていないだけ -なのです; エラーが出るからといって、あなたがいいプログラマではないという意味では*ありません*! +コンパイルエラーは、イライラすることもあるものですが、まだプログラムにしてほしいことを安全に行えていないだけということなのです; +エラーが出るからといって、あなたがいいプログラマではないという意味では*ありません*! 経験豊富なRust市民でも、コンパイラエラーを出すことはあります。このエラーは、エラーの原因が `不変変数への再代入`であると示しています。不変な`x`という変数に第2段階の値を代入しようとしたからです。 @@ -80,10 +80,11 @@ error[E0384]: re-assignment of immutable variable `x` 以前に不変と指定された値を変えようとした時に、コンパイルエラーが出るのは重要なことです。 -なぜなら、この状況はまさしく、バグに繋がるからです。コードのある部分は、値が変わることはないという -前提のもとに処理を行い、別の部分がその値を変更していたら、最初の部分が目論見通りに -動いていない可能性があるのです。このようなバグの発生は、事実(`脚注`:実際にプログラムを走らせた結果のことと思われる) -の後には追いかけづらいものです。特に第2のコード破片が、値を*時々*しか変えない場合尚更です。 +なぜなら、この状況はまさしく、バグに繋がるからです。コードのある部分は、 +値が変わることはないという前提のもとに処理を行い、別の部分がその値を変更していたら、 +最初の部分が目論見通りに動いていない可能性があるのです。このようなバグの発生は、 +事実(`脚注`:実際にプログラムを走らせた結果のことと思われる)の後には追いかけづらいものです。 +特に第2のコード破片が、値を*時々*しか変えない場合尚更です。 @@ -100,9 +101,9 @@ Rustでは、値が不変であると宣言したら、本当に変わらない -しかし、可変性は時として非常に有益なこともあります。変数は、標準でのみ、不変です。つまり、変数名の前に -`mut`キーワードを付ければ、可変にできるわけです。この値が変化できるようにするとともに、未来の読者に対して -コードの別の部分がこの変数の値を変えることを示すことで、その意図を汲ませることができるのです。 +しかし、可変性は時として非常に有益なこともあります。変数は、標準でのみ、不変です。つまり、 +変数名の前に`mut`キーワードを付ければ、可変にできるわけです。この値が変化できるようにするとともに、 +未来の読者に対してコードの別の部分がこの変数の値を変える可能性を示すことで、その意図を汲ませることができるのです。 @@ -139,7 +140,7 @@ The value of x is: 6 `mut`キーワードを使うことで、`x`が束縛している値を`5`から`6`に変更できるようになりました。 -変数を可変にする方が、不変変数だけを使う実装よりも書きやすくなるケースもあるでしょう。 +変数を可変にする方が、不変変数だけを使う実装よりも書きやすくなるケースもあるので、変数を可変にしたくなることもあるでしょう。 @@ -149,10 +150,9 @@ The value of x is: 6 考えるべきトレードオフはバグの阻止以外にも、いくつかあります。例えば、大きなデータ構造を使う場合などです。 -オブジェクトを可変にして変更できるようにする方が、いちいちオブジェクトをコピーして新しくメモリ割り当てされた -オブジェクトを返すよりも速くなります。小規模なデータ構造なら、新規オブジェクトを生成して、 -もっと関数型っぽいコードを書く方が中身を把握しやすくなるため、低パフォーマンスは、その簡潔性を得るのに -足りうるペナルティになるかもしれません。 +インスタンスを可変にして変更できるようにする方が、いちいちインスタンスをコピーして新しくメモリ割り当てされたインスタンスを返すよりも速くなります。 +小規模なデータ構造なら、新規インスタンスを生成して、もっと関数型っぽいコードを書く方が中身を把握しやすくなるため、 +低パフォーマンスは、その簡潔性を得るのに足りうるペナルティになるかもしれません。 @@ -164,7 +164,7 @@ The value of x is: 6 -変数の値を変更できないようにするといえば、他の多くの言語も持っている別のプログラミング概念を思い浮かべるでしょう: +変数の値を変更できないようにするといえば、他の多くの言語も持っている別のプログラミング概念を思い浮かべるかもしれません: *定数*です. 不変変数のように、定数も名前に紐付き、変更することが叶わない値のことですが、 定数と変数の間にはいくつかの違いがあります。 @@ -180,19 +180,19 @@ The value of x is: 6 定数は`let`キーワードの代わりに、`const`キーワードで宣言し、値の型は*必ず*注釈しなければなりません。 型と型注釈については次のセクション、「データ型」で解説する予定なので、その詳細については気にする必要はありません。 -ただ単に型を注釈しなければならないのだと思っていてください。 +ただ単に型は常に注釈しなければならないのだと思っていてください。 -定数はどんなスコープでも定義できます。グローバルスコープも含めてね。なので、いろんなところで使用される可能性のある値を -定義するのに役に立ちます。 +定数はどんなスコープでも定義できます。グローバルスコープも含めてね。なので、 +いろんなところで使用される可能性のある値を定義するのに役に立ちます。 -最後の違いは、定数は定数式にしかセットできないことです。関数呼び出し結果や、実行時に評価される値ではありません。 +最後の違いは、定数は定数式にしかセットすることが叶わないことです。関数呼び出し結果や、実行時に評価される値にはセットできません。 @@ -211,22 +211,22 @@ const MAX_POINTS: u32 = 100_000; -定数は、プログラムが走る期間、定義されたスコープ内でずっと有効です。従って、プログラムのいろんなところで -使用される可能性のあるアプリケーション空間の値を定義するのに有益な選択肢になります。例えば、 -ゲームでプレイヤーが取得可能なポイントの最高値や、光速度などですね。 +定数は、プログラムが走る期間、定義されたスコープ内でずっと有効です。従って、 +プログラムのいろんなところで使用される可能性のあるアプリケーション空間の値を定義するのに有益な選択肢になります。 +例えば、ゲームでプレイヤーが取得可能なポイントの最高値や、光速度などですね。 -プログラム中で使用されるハードコードされた値に対して、定数として名前付けすることは、コードの将来的な -管理者にとって値の意味を汲むのに役に立ちます。将来、ハードコードされた値を変える必要が出た時に、 +プログラム中で使用されるハードコードされた値に対して、定数として名前付けすることは、 +コードの将来的な管理者にとって値の意味を汲むのに役に立ちます。将来、ハードコードされた値を変える必要が出た時に、 たった1箇所を変更するだけで済むようにもしてくれます。 -### (変数の)多重定義 +### (変数の)多重定義(shadowing) @@ -235,9 +235,9 @@ const MAX_POINTS: u32 = 100_000; -第2章の数当てゲームのチュートリアルで見たように、前に定義した変数と同じ名前の変数を新しく定義でき、 -新しい変数は、前の変数を*上書き*(shadow)する。Rust市民はこれを最初の変数は、2番目の変数に*上書き* -されたと言い、この変数を使用した際に、2番目の変数の値が得られるということです。 +第2章の数当てゲームのチュートリアルで見たように、前に定義した変数と同じ名前の変数を新しく宣言でき、 +新しい変数は、前の変数を*上書き*(shadow)します。Rust市民はこれを最初の変数は、 +2番目の変数に*上書き*されたと言い、この変数を使用した際に、2番目の変数の値が得られるということです。 以下のようにして、同じ変数名を用いて変数を上書きし、`let`キーワードの使用を繰り返します: @@ -262,8 +262,8 @@ fn main() { -このプログラムはまず、`x`を`5`という値に束縛します。それから`let x =`という文法要素を繰り返すことで -`x`を上書きし、元の値に`1`を加えることになるので、`x`の値は、`6`になります。 +このプログラムはまず、`x`を`5`という値に束縛します。それから`let x =`を繰り返すことで`x`を上書きし、 +元の値に`1`を加えることになるので、`x`の値は、`6`になります。 3番目の`let`文も`x`を上書きし、以前の値に`2`をかけることになるので、`x`の最終的な値は`12`になります。 このプログラムを走らせたら、以下のように出力するでしょう: @@ -279,8 +279,8 @@ The value of x is: 12 -これは、変数を`mut`にするのとは違います。なぜなら、`let`キーワードを使っている限り、誤ってこの変数に -再代入を試みようものなら、コンパイルエラーが出るからです。値にちょっとした加工は加えられますが、 +これは、変数を`mut`にするのとは違います。なぜなら、`let`キーワードを再度使わない限り、 +誤ってこの変数に再代入を試みようものなら、コンパイルエラーが出るからです。値にちょっとした加工は加えられますが、 その加工が終わったら、変数は不変になるわけです。 @@ -290,9 +290,9 @@ The value of x is: 12 `mut`と上書きのもう一つの違いは、再度`let`キーワードを使用したら、実効的には新しい変数を生成していることになるので、 -値の型を変えつつ、同じ変数名を使いまわせることです。例えば、プログラムがユーザに何らかのテキストに対して -空白文字を入力することで何個分のスペースを表示したいかを尋ねるとします。ただ、この入力を数値として -保持したいとしましょう: +値の型を変えつつ、同じ変数名を使いまわせることです。例えば、 +プログラムがユーザに何らかのテキストに対して空白文字を入力することで何個分のスペースを表示したいかを尋ねるとします。 +ただ、実際にはこの入力を数値として保持したいとしましょう: ```rust let spaces = " "; @@ -307,7 +307,7 @@ let spaces = spaces.len(); この文法要素は、容認されます。というのも、最初の`spaces`変数は文字列型であり、2番目の`spaces`変数は、 -たまたま最初の変数と同じ名前になったまっさらな変数のわけですが、数値型になるからです。故に、多重定義のおかげで、 +たまたま最初の変数と同じ名前になったまっさらな変数のわけですが、数値型になるからです。故に、上書きのおかげで、 異なる名前を思いつく必要がなくなるわけです。`spaces_str`と`spaces_num`などですね; 代わりに、 よりシンプルな`spaces`という名前を再利用できるわけです。一方で、この場合に`mut`を使おうとすると、 以下に示した通りですが: From 6f96ea541a17d154eb3c09c388a135c1f66c0b26 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 27 Aug 2017 19:43:58 +0900 Subject: [PATCH 031/428] Fix some errors and enhance the quality of the content in the Chapter 3-2 --- second-edition/src/ch03-02-data-types.md | 96 ++++++++++++------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/second-edition/src/ch03-02-data-types.md b/second-edition/src/ch03-02-data-types.md index a129c4140..1cdbd73a9 100644 --- a/second-edition/src/ch03-02-data-types.md +++ b/second-edition/src/ch03-02-data-types.md @@ -8,7 +8,7 @@ Rustにおける値は全て、何らかの*型*になり、コンパイラがどんなデータが指定されているか知れるので、 -そのデータの取り扱い方も把握できるというわけです。この節では、言語に組み込まれている種々の型について +そのデータの取り扱い方も把握できるというわけです。この節では、言語に組み込まれている種々の型について、 見ていきましょう。型を二分割しましょう: スカラー型と複合型です。 @@ -18,10 +18,11 @@ Rustにおける値は全て、何らかの*型*になり、コンパイラが -この節を通して、Rustは*静的型付け*言語であることを弁えておいてください。つまり、コンパイル時に -全ての変数の型が判明している必要があるということです。コンパイラは通常、値と使用方法に基づいて、 -使用したい型を推論してくれます。複数の型が推論される可能性がある場合、そう例えば、第2章で`parse`メソッドを -使って`String`型を数値型に変換した時のような場合には、型注釈をつけなければいけません。以下のようにね: +この節を通して、Rustは*静的型付け*言語であることを弁えておいてください。つまり、 +コンパイル時に全ての変数の型が判明している必要があるということです。コンパイラは通常、値と使用方法に基づいて、 +使用したい型を推論してくれます。複数の型が推論される可能性がある場合、そう例えば、 +第2章で`parse`メソッドを使って`String`型を数値型に変換した時のような場合には、型注釈をつけなければいけません。 +以下のようにね: ```rust let guess: u32 = "42".parse().expect("Not a number!"); // 数字ではありません! @@ -32,8 +33,7 @@ let guess: u32 = "42".parse().expect("Not a number!"); // 数字ではあり ここで型注釈を付けなければ、コンパイラは以下のエラーを表示し、これは可能性のある型のうち、 -どの型を使用したいのかを知るのに、コンパイラがプログラマからもっと情報を得る必要があることを -意味します: +どの型を使用したいのかを知るのに、コンパイラがプログラマからもっと情報を得る必要があることを意味します: ```text error[E0282]: unable to infer enough type information about `_` @@ -78,9 +78,9 @@ Rustでの動作方法について見ていきましょう。 整数とは、小数部分のない数値のことです。この章の前半で一つの整数型を使用しました。`i32`型です。 -この型定義は、紐付けられる値が、符号付き整数(そのため、`i`になります。非負整数に対する`u`と逆ですね) -になり、これは、32ビット分のサイズを取ります。表3-1は、Rustの組み込み整数型を表示しています。 -符号付きと符号なし欄の各バリアント(例: *i32*)を使用して、整数値の型を定義することができます。 +この型定義は、紐付けられる値が、符号付き整数(そのため、`i`になります。非負整数に対する`u`と逆ですね)になり、 +これは、32ビット分のサイズを取ります。表3-1は、Rustの組み込み整数型を表示しています。 +符号付きと符号なし欄の各バリアント(例: *i32*)を使用して、整数値の型を宣言することができます。 @@ -128,10 +128,9 @@ Rustでの動作方法について見ていきましょう。 各符号付きバリアントは、-(2n - 1)から2n - 1 - 1までの数値を保持でき、 -ここで`n`はこのバリアントが使用するビット数です。以上から、`i8`型は-(27)から -27 - 1まで、つまり、-128から127までを保持できます。符号なしバリアントは、0から -2n - 1までを保持できるので、`u8`型は、0から28 - 1までの値、つまり、 -0から255までを保持できることになります。 +ここで`n`はこのバリアントが使用するビット数です。以上から、`i8`型は-(27)から27 - 1まで、 +つまり、-128から127までを保持できます。符号なしバリアントは、0から2n - 1までを保持できるので、 +`u8`型は、0から28 - 1までの値、つまり、0から255までを保持できることになります。 @@ -144,7 +143,8 @@ Rustでの動作方法について見ていきましょう。 -整数リテラル(`脚注`: リテラルとは、見たまんまの値ということ)は表3-2に示すどの形態でも記述することができます。バイトリテラルを除く数値リテラルは全て、 +整数リテラル(`脚注`: リテラルとは、見たまんまの値ということ)は、表3-2に示すどの形態でも記述することができます。 +バイトリテラルを除く数値リテラルは全て、 型接尾辞を付加すること(例えば、`57u8`)と`_`を見た目の区切り記号(例えば、`1_000`)にできます。 @@ -172,8 +172,8 @@ Rustでの動作方法について見ていきましょう。 -では、どの整数型を使うべきかはどう把握すればいいのでしょうか?もし確信が持てないのならば、Rustの -デフォルトは一般的にいい選択になります。整数型の基準は`i32`型です: 64ビットシステム上でも、 +では、どの整数型を使うべきかはどう把握すればいいのでしょうか?もし確信が持てないのならば、 +Rustの基準型は一般的にいい選択になります。整数型の基準は`i32`型です: 64ビットシステム上でも、 普通最速になります。`isize`と`usize`を使う主な状況は、何らかのコレクションにアクセスすることです。 @@ -193,9 +193,9 @@ Rustでの動作方法について見ていきましょう。 Rustにはさらに、*浮動小数点数*に対しても、2種類の基本型があり、浮動小数点数とは10進小数のことです。 Rustの浮動小数点型は、`f32`と`f64`で、それぞれ32ビットと64ビットサイズです。基準型は`f64`です。 なぜなら、`f32`とほぼ同スピードにもかかわらず、より精度が高くなるからです。32ビットシステム上でも、 -`f64`型を使用することはできますが、`f32`型を使うよりも遅くなります。ほとんどの場合、パフォーマンスが悪くなる -可能性と引き換えに高精度を得ることは、一考の価値のある第1選択肢になる上、自らのコードで浮動小数点数のサイズが -問題になる可能性があると疑うのなら、ベンチマークをしてみるべきです。 +`f64`型を使用することはできますが、`f32`型を使うよりも遅くなります。ほとんどの場合、 +パフォーマンスが悪くなる可能性と引き換えに高精度を得ることは、一考の価値のある第1選択肢になる上、 +自らのコードで浮動小数点数のサイズが問題になる可能性があると疑うのなら、ベンチマークをしてみるべきです。 @@ -276,8 +276,8 @@ fn main() { -これらの文の各式は、数学演算子を使用しており、一つの値に評価され、変数に束縛されます。付録BにRustで使える -演算子の一覧が載っています。 +これらの文の各式は、数学演算子を使用しており、一つの値に評価され、変数に束縛されます。 +付録BにRustで使える演算子の一覧が載っています。 @@ -315,7 +315,7 @@ fn main() { -論理値を消費する主な手段は、条件式です。例えば、`if`式などですね。`if`式の動作方法については、 +論理値を消費する主な手段は、条件式です。例えば、`if`式などですね。`if`式のRustでの動作方法については、 「フロー制御」節で解説します。 @@ -326,8 +326,8 @@ fn main() { -ここまで、数値型のみ扱ってきましたが、Rustには文字も用意されています。Rustの`char`型は、言語の最も -基本的なアルファベット型であり、以下のコードでその使用方法の一例を見ることができます: +ここまで、数値型のみ扱ってきましたが、Rustには文字も用意されています。Rustの`char`型は、 +言語の最も基本的なアルファベット型であり、以下のコードでその使用方法の一例を見ることができます: @@ -350,12 +350,12 @@ fn main() { -Rustの`char`型は、ユニコードのスカラー値を表します。これはつまり、アスキーよりもずっとたくさんの -ものを表せるということです。アクセント文字、中国語/日本語/韓国語表意文字(`脚注`: 漢字のことだと思われる)、 +Rustの`char`型は、ユニコードのスカラー値を表します。これはつまり、アスキーよりもずっとたくさんのものを表せるということです。 +アクセント文字、中国語/日本語/韓国語表意文字(`脚注`: 漢字のことだと思われる)、 絵文字、ゼロ幅スペースは、全てRustでは、有効な`char`型になります。ユニコードスカラー値は、 -`U+0000`から`U+D7FF`までと`U+E0000`から`U+10FFFF`までの範囲になります。ところが、「文字」は -実はユニコードの概念ではないので、文字とは何かという人間としての直観は、Rustにおける`char`型が何か -とは合致しない可能性があります。この話題については第8章の「文字列」節で詳しく議論しましょう。 +`U+0000`から`U+D7FF`までと`U+E0000`から`U+10FFFF`までの範囲になります。 +ところが、「文字」は実はユニコードの概念ではないので、文字とは何かという人間としての直観は、 +Rustにおける`char`型が何かとは合致しない可能性があります。この話題については第8章の「文字列」節で詳しく議論しましょう。 @@ -399,7 +399,7 @@ fn main() { 変数`tup`は、タプル全体に束縛されています。なぜなら、タプルは、一つの複合要素と考えられるからです。 -タプルからここの値を取り出すには、パターンマッチングにより分解を使用することができます。以下のように: +タプルから個々の値を取り出すには、パターンマッチングにより分解を使用することができます。以下のように: @@ -421,16 +421,16 @@ fn main() { -このプログラムは、まずタプルを生成し、それを変数`tup`に束縛しています。それから`let`文と -パターンを使って`tup`変数の中身を3つの個別の変数(`x`、`y`、`z`ですね)に変換しています。 +このプログラムは、まずタプルを生成し、それを変数`tup`に束縛しています。 +それから`let`文とパターンを使って`tup`変数の中身を3つの個別の変数(`x`、`y`、`z`ですね)に変換しています。 この過程は、*分解*と呼ばれます。単独のタプルを破壊して三分割しているからです。最後に、 -プログラムは`y`変数の値を出力し、それは`6.4`になります。 +プログラムは`y`変数の値を出力し、`6.4`と表示されます。 -パターンマッチングを通しての分解の他にも、アクセスしたい値の番号をピリオドに続けて書くことで、 +パターンマッチングを通しての分解の他にも、アクセスしたい値の番号をピリオド(`.`)に続けて書くことで、 タプルの要素に直接アクセスすることもできます。例です: @@ -453,7 +453,7 @@ fn main() { -このプログラムは、新しいタプル`x`を作成し、添え字アクセスで書く要素に対して新しい変数も作成しています。 +このプログラムは、新しいタプル`x`を作成し、添え字アクセスで各要素に対して新しい変数も作成しています。 多くのプログラミング言語同様、タプルの最初の添え字は0です。 @@ -467,7 +467,7 @@ fn main() { *配列*によっても、複数の値のコレクションを得ることができます。タプルと異なり、配列の全要素は、 同じ型でなければなりません。Rustの配列は、他の言語と異なっている場合があります。Rustの配列は、 -固定長なのです: 一度定義されたら、サイズを伸ばすことも縮めることもできません。 +固定長なのです: 一度宣言されたら、サイズを伸ばすことも縮めることもできません。 @@ -492,8 +492,8 @@ fn main() { -配列は、ヒープよりもスタック(スタックとヒープについては第4章で詳らかに議論します)にデータのメモリを確保したい時、 -または、常に固定長の要素があることを確認したい時に役に立ちます。ただ、配列は、ベクタ型ほどは柔軟ではありません。 +配列は、ヒープよりもスタック(スタックとヒープについては第4章で(つまび)らかに議論します)にデータのメモリを確保したい時、 +または、常に固定長の要素があることを確認したい時に有効です。ただ、配列は、ベクタ型ほど柔軟ではありません。 ベクタ型も、標準ライブラリによって提供されている似たようなコレクション型で、こちらは、 サイズを伸縮させることが*できます*。配列とベクタ型、どちらを使うべきか確信が持てない時は、 おそらくベクタ型を使うべきです: 第8章でベクタ型について詳細に議論します。 @@ -503,7 +503,7 @@ fn main() { -ベクタ型よりも配列を使いたくなる例は、1年の月の名前を扱うプログラムです。そのようなプログラムで、 +ベクタ型よりも配列を使いたくなるかもしれない例は、1年の月の名前を扱うプログラムです。そのようなプログラムで、 月を追加したり削除したりすることはほぼ稀なので、配列を使用できます。常に12個要素があることもわかってますしね: ```rust @@ -518,8 +518,8 @@ let months = ["January", "February", "March", "April", "May", "June", "July", -配列は、スタック上に確保される一塊のメモリです。添え字によって配列の -要素にアクセスすることができます。こんな感じ: +配列は、スタック上に確保される一塊のメモリです。添え字によって、 +配列の要素にアクセスすることができます。こんな感じ: @@ -538,7 +538,7 @@ fn main() { -この例では、`first`という名前の変数には`1`という値が格納されます。配列の`[0]`番目にある値が +この例では、`first`という名前の変数には`1`という値が格納されます。配列の`[0]`番目にある値が、 それだからですね。`second`という名前の変数には、配列の`[1]`番目の値`2`が格納されます。 @@ -548,8 +548,8 @@ fn main() { -配列の終端を越えて要素にアクセスしようとしたら、どうなるでしょうか?先ほどの例を以下のように -変えたとしよう: +配列の終端を越えて要素にアクセスしようとしたら、どうなるでしょうか? +先ほどの例を以下のように変えたとしましょう: @@ -588,8 +588,8 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. コンパイルでは何もエラーが出なかったものの、プログラムは*実行時*エラーに陥り、 -正常終了しませんでした。要素に添え字アクセスを試みると、言語は、指定されたその添え字が -配列長よりも小さいかをチェックしてくれます。添え字が配列長よりも大きければ、言語は*パニック*します。 +正常終了しませんでした。要素に添え字アクセスを試みると、言語は、 +指定されたその添え字が配列長よりも小さいかを確認してくれます。添え字が配列長よりも大きければ、言語は*パニック*します。 パニックとは、プログラムがエラーで終了したことを表すRust用語です。 @@ -600,5 +600,5 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. これは、実際に稼働しているRustの安全機構の最初の例になります。低レベル言語の多くでは、 この種のチェックは行われないため、間違った添え字を与えると、無効なメモリにアクセスできてしまいます。 -Rustでは、メモリアクセスを許可し、処理を継続する代わりに即座にプログラムを終了することで +Rustでは、メモリアクセスを許可し、処理を継続する代わりに即座にプログラムを終了することで、 この種のエラーからプログラマを保護しています。Rustのエラー処理については、第9章で詳しく議論します。 From b8ff1dac48a1f5d30dda186d8584908292fd4672 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 27 Aug 2017 20:12:21 +0900 Subject: [PATCH 032/428] Fix some errors in the Chapter 3-3 --- .../src/ch03-03-how-functions-work.md | 67 +++++++++---------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/second-edition/src/ch03-03-how-functions-work.md b/second-edition/src/ch03-03-how-functions-work.md index 88181e9e8..029a95d36 100644 --- a/second-edition/src/ch03-03-how-functions-work.md +++ b/second-edition/src/ch03-03-how-functions-work.md @@ -7,9 +7,9 @@ -関数は、Rustのコードにおいてよく見かける存在です。すでに、言語において最も重要な関数のうちの -一つを目撃していますね: そう、`main`関数で、これは、多くのプログラムのエントリーポイントになります。 -`fn`キーワードもすでに見かけましたね。これによって新しい関数を定義することができます。 +関数は、Rustのコードにおいてよく見かける存在です。すでに、言語において最も重要な関数のうちの一つを目撃していますね: +そう、`main`関数です。これは、多くのプログラムのエントリーポイント(`脚注`: プログラム実行時に最初に走る関数のこと)になります。 +`fn`キーワードもすでに見かけましたね。これによって新しい関数を宣言することができます。 @@ -49,17 +49,17 @@ Rustにおいて関数定義は、`fn`キーワードで始まり、関数名の -定義した関数は、名前に丸かっこの組を続けることで呼び出すことができます。`another_function`関数が -プログラム内で定義されているので、`main`関数内から呼び出すことができるわけです。ソースコード中で -`another_function`を`main`関数の*後*に定義していることに注目してください; 勿論、main関数の前に -定義することもできます。コンパイラは、関数がどこで定義されているかは気にしません。 +定義した関数は、名前に丸かっこの組を続けることで呼び出すことができます。 +`another_function`関数がプログラム内で定義されているので、`main`関数内から呼び出すことができるわけです。 +ソースコード中で`another_function`を`main`関数の*後*に定義していることに注目してください; +勿論、main関数の前に定義することもできます。コンパイラは、関数がどこで定義されているかは気にしません。 どこかで定義されていることのみ気にします。 -*functions*という名前の新しいバイナリ生成プロジェクトを始めて、関数についてさらに深く探知していきましょう。 +*functions*という名前の新しいバイナリ生成プロジェクトを始めて、関数についてさらに深く探求していきましょう。 `another_function`の例を*src/main.rs*ファイルに配置して、走らせてください。 以下のような出力が得られるはずです: @@ -92,14 +92,13 @@ Another function. 関数は、引数を持つようにも定義できます。引数とは、関数シグニチャの一部になる特別な変数のことです。 関数に引数があると、引数の位置に実際の値を与えることができます。技術的にはこの実際の値は -*実引数*と呼ばれますが、普段の会話では、仮引数("parameter")と実引数("argument")を -関数定義の変数と関数呼び出し時に渡す実際の値、両方の意味に区別なく使います(`脚注`: 日本語では、 -どちらも単に引数と呼ぶことが多いでしょう)。 +*実引数*と呼ばれますが、普段の会話では、仮引数("parameter")と実引数("argument")を関数定義の変数と関数呼び出し時に渡す実際の値、 +両方の意味に区別なく使います(`脚注`: 日本語では、どちらも単に引数と呼ぶことが多いでしょう)。 -以下の書き直した`another_function`では、Rustのパラメータがどんな見た目なのかを示しています: +以下の書き直した`another_function`では、Rustの仮引数がどんな見た目なのかを示しています: @@ -131,8 +130,8 @@ The value of x is: 5 -`another_function`の宣言には、`x`という名前の仮引数があります。`x`の型は、`i32`と -指定されています。値`5`が`another_function`に渡されると、`println!`マクロにより、 +`another_function`の宣言には、`x`という名前の仮引数があります。`x`の型は、 +`i32`と指定されています。値`5`が`another_function`に渡されると、`println!`マクロにより、 フォーマット文字列中の1組の波かっこがある位置に値`5`が出力されます。 @@ -140,9 +139,9 @@ The value of x is: 5 -関数シグニチャにおいて、各仮引数の型を宣言しなければなりません。これは、Rustの設計において、 -意図的な判断です: 関数定義で型注釈が必要不可欠ということは、コンパイラがその意図するところを -推し量るのに、コードの他の箇所で使用する必要がないということを意味します。 +関数シグニチャにおいて、各仮引数の型を宣言しなければ*なりません*。これは、Rustの設計において、 +意図的な判断です: 関数定義で型注釈が必要不可欠ということは、コンパイラがその意図するところを推し量るのに、 +コードの他の箇所で使用する必要がないということを意味します。 @@ -170,7 +169,7 @@ fn another_function(x: i32, y: i32) { -この例では、2引数の関数を生成しています。そして、引数はどちらも`i32`型です。この関数は、 +この例では、2引数の関数を生成しています。そして、引数はどちらも`i32`型です。それからこの関数は、 仮引数の値を両方出力します。関数引数は、全てが同じ型である必要はありません。今回は、 偶然同じになっただけです。 @@ -178,8 +177,8 @@ fn another_function(x: i32, y: i32) { -このコードを走らせてみましょう。今、*function*プロジェクトの*src/main.rs*ファイルに記載されている -プログラムを先ほどの例と置き換えて、`cargo run`で走らせてください: +このコードを走らせてみましょう。今、*function*プロジェクトの*src/main.rs*ファイルに記載されているプログラムを先ほどの例と置き換えて、 +`cargo run`で走らせてください: ```text $ cargo run @@ -207,8 +206,8 @@ The value of y is: 6 -関数本体は、文が並び、最後に式を置くか文を置くという形で形成されます。現在までには、式で終わらない -関数だけを見てきたわけですが、式が文の一部になっているものなら見かけましたね。Rustは、式志向言語なので、 +関数本体は、文が並び、最後に式を置くか文を置くという形で形成されます。現在までには、 +式で終わらない関数だけを見てきたわけですが、式が文の一部になっているものなら見かけましたね。Rustは、式指向言語なので、 これは理解しておくべき重要な差異になります。他の言語にこの差異はありませんので、文と式がなんなのかと、 その違いが関数本体にどんな影響を与えるかを見ていきましょう。 @@ -301,9 +300,9 @@ CやRubyなどの言語とは異なる動作です。CやRubyでは、代入は -式は何かに評価され、これからあなたが書くRustコードの多くを構成します。簡単な数学演算(`5 + 6`など)を -思い浮かべましょう。この例は、値`11`に評価される式です。式は文の一部になりえます: `let y = 6`という -文を含むリスト3-3では、`6`は値`6`に評価される式です。関数呼び出しも式です。マクロ呼び出しも式です。 +式は何かに評価され、これからあなたが書くRustコードの多くを構成します。 +簡単な数学演算(`5 + 6`など)を思い浮かべましょう。この例は、値`11`に評価される式です。式は文の一部になりえます: +`let y = 6`という文を含むリスト3-3では、`6`は値`6`に評価される式です。関数呼び出しも式です。マクロ呼び出しも式です。 新しいスコープを作る際に使用するブロック(`{}`)も式です: @@ -325,7 +324,7 @@ fn main() { -この式は: +以下の式は: ```rust,ignore { @@ -342,8 +341,8 @@ fn main() { 今回の場合、`4`に評価されるブロックです。その値が、`let`文の一部として`y`に束縛されます。 -今まで見かけてきた行と異なり、セミコロンがついていない行に気をつけてください。式に終端のセミコロンは、 -含みません。式の終端にセミコロンを付けたら、文に変えてしまいます。そして、文は値を返しません。 +今まで見かけてきた行と異なり、文末にセミコロンがついていない行に気をつけてください。 +式は終端にセミコロンを、含みません。式の終端にセミコロンを付けたら、文に変えてしまいます。そして、文は値を返しません。 次に関数の戻り値や式を見ていく際にこのことを肝に命じておいてください。 @@ -357,8 +356,8 @@ fn main() { 関数は、それを呼び出したコードに値を返すことができます。戻り値に名前付けはできませんが、 -矢印(`->`)の後に型を書いて宣言します。Rustでは、関数の戻り値は、関数本体ブロックの最後の式の値と -同義です。こちらが、値を返す関数の例です: +矢印(`->`)の後に型を書いて宣言します。Rustでは、関数の戻り値は、関数本体ブロックの最後の式の値と同義です。 +こちらが、値を返す関数の例です: @@ -399,8 +398,8 @@ The value of x is: 5 `five`内の`5`が関数の戻り値です。だから、戻り値型が`i32`なのです。これについてもっと深く考察しましょう。 -重要な箇所は2つあります: まず、`let x = five()`という行は、関数の戻り値を使って変数を初期化している -ことを示しています。関数`five`は`5`を返すので、この行は以下のように書くのと同義です: +重要な箇所は2つあります: まず、`let x = five()`という行は、関数の戻り値を使って変数を初期化していることを示しています。 +関数`five`は`5`を返すので、この行は以下のように書くのと同義です: ```rust let x = 5; @@ -434,8 +433,8 @@ fn plus_one(x: i32) -> i32 { -このコードを走らせると、`The value of x is: 6`と出力されるでしょう。では、`x + 1`を含む行の -終端にセミコロンを付けて、式から文に変えてみたら、どうなるでしょうか? +このコードを走らせると、`The value of x is: 6`と出力されるでしょう。では、 +`x + 1`を含む行の終端にセミコロンを付けて、式から文に変えてみたら、どうなるでしょうか? From 1d9dd0118c5da017d934c76f792b35211a04b198 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 27 Aug 2017 20:44:32 +0900 Subject: [PATCH 033/428] Fix some errors and revise the content in the Chapter 3-5 so that the resulting html wouldn't contain unnecesary spaces between words --- second-edition/src/ch03-05-control-flow.md | 101 +++++++++++---------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/second-edition/src/ch03-05-control-flow.md b/second-edition/src/ch03-05-control-flow.md index 490797e2d..4a206b42e 100644 --- a/second-edition/src/ch03-05-control-flow.md +++ b/second-edition/src/ch03-05-control-flow.md @@ -8,9 +8,9 @@ -条件が真かどうかによってコードを走らせるかどうかを決定したり、条件が真の間繰り返しコードを走らせるか -決定したりすることは、多くのプログラミング言語において、基本的な構成ブロックです。Rustコードの -実行フローを制御する最も一般的な文法要素は、`if`式とループです。 +条件が真かどうかによってコードを走らせるかどうかを決定したり、 +条件が真の間繰り返しコードを走らせるか決定したりすることは、多くのプログラミング言語において、基本的な構成ブロックです。 +Rustコードの実行フローを制御する最も一般的な文法要素は、`if`式とループです。 @@ -60,13 +60,14 @@ fn main() { -`if`式は全て、キーワードの`if`から始め、条件式を続けます。今回の場合、条件式は変数`number`が -5未満の値になっているかどうかをチェックします。条件が真の時に実行したい一連のコードを条件式の直後に -波かっこで包んで配置します。`if`式の条件式と紐付けられる一連のコードは、時として*アーム*と呼ばれることがあります。 +`if`式は全て、キーワードの`if`から始め、条件式を続けます。今回の場合、 +条件式は変数`number`が5未満の値になっているかどうかをチェックします。 +条件が真の時に実行したい一連のコードを条件式の直後に波かっこで包んで配置します。`if`式の条件式と紐付けられる一連のコードは、 +時として*アーム*と呼ばれることがあります。 第2章の「予想と秘密の数字を比較する」の節で議論した`match`式のアームのようですね。オプションとして、 -`else`式を含むこともでき(ここではそうしています)、これによりプログラムは、条件式が偽になった時に -実行するコードを与えられることになります。仮に、`else`式を与えずに条件式が偽になったら、プログラムは単に -`if`ブロックを無視して次のコードを実行しにいきます。 +`else`式を含むこともでき(ここではそうしています)、これによりプログラムは、 +条件式が偽になった時に実行するコードを与えられることになります。仮に、`else`式を与えずに条件式が偽になったら、 +プログラムは単に`if`ブロックを無視して次のコードを実行しにいきます。 @@ -103,8 +104,8 @@ condition was false -このコード内の条件式は、`bool`型で*なければならない*ことにも触れる価値があります。条件式が、 -`bool`型でない時に何が起こるかを確かめるために、以下のコードを走らせてみましょう: +このコード内の条件式は、`bool`型で*なければならない*ことにも触れる価値があります。 +条件式が、`bool`型でない時に何が起こるかを確かめるために、以下のコードを走らせてみましょう: @@ -146,9 +147,9 @@ error[E0308]: mismatched types このエラーは、コンパイラは`bool`型を予期していたのに、整数だったことを示唆しています。Rustでは、 -論理値以外の値が、自動的に論理値に変換されることはありません。RubyやJavaScriptなどの言語とは -異なりますね。明示的に必ず`if`には条件式として、`論理値`を与えなければなりません。例えば、 -数値が`0`以外の時だけ`if`のコードを走らせたいなら、以下のように`if`式を変更することができます: +論理値以外の値が、自動的に論理値に変換されることはありません。 +RubyやJavaScriptなどの言語とは異なります。明示的に必ず`if`には条件式として、`論理値`を与えなければなりません。 +例えば、数値が`0`以外の時だけ`if`のコードを走らせたいなら、以下のように`if`式を変更することができます: @@ -201,7 +202,7 @@ fn main() { } ``` - + このプログラムには、通り道が4つあります。実行後、以下のような出力を目の当たりにするはずです: @@ -221,16 +222,17 @@ number is divisible by 3 このプログラムを実行すると、`if`式が順番に吟味され、最初に条件が真になった本体が実行されます。 -6は2で割り切れるものの、`number is devisible by 2`や`else`ブロックの`number is not divisible by 4, 3, or 2` -という出力はされないことに注目してください。その原因は、言語が最初の真条件のブロックのみを実行し、 -条件に合ったものが見つかったら、残りはチェックすらしないということだからです。 +6は2で割り切れるものの、`number is devisible by 2`や、 +`else`ブロックの`number is not divisible by 4, 3, or 2`という出力はされないことに注目してください。 +その原因は、言語が最初の真条件のブロックのみを実行し、 +条件に合ったものが見つかったら、残りはチェックすらしないからです。 `else if`式を使いすぎると、コードがめちゃくちゃになってしまうので、1つ以上あるなら、 -コードをリファクタリングしたくなるかもしれません。これらのケースに有用な`match`と呼ばれる +コードをリファクタリングしたくなるかもしれません。これらのケースに有用な`match`と呼ばれる、 強力なRustの枝分かれ文法要素については第6章で解説します。 @@ -344,12 +346,11 @@ error[E0308]: if and else have incompatible types `if`ブロックの式は整数に評価され、`else`ブロックの式は文字列に評価されます。これでは動作しません。 -変数は単独の型でなければならないのです。コンパイラは、コンパイル時に`number`変数の型を確実に -把握する必要があるため、コンパイル時に`number`が使われている箇所全部で型が有効かどうか -検査することができるのです。`number`の型が実行時にしか決まらないのであれば、コンパイラは -それを実行することができなくなってしまいます; コンパイラはより複雑であり、どの変数に対しても、 -架空の複数の型があることを追いかけなければならないのであれば、コードに対して行える保証が -少なくなってしまうでしょう。 +変数は単独の型でなければならないからです。コンパイラは、コンパイル時に`number`変数の型を確実に把握する必要があるため、 +コンパイル時に`number`が使われている箇所全部で型が有効かどうか検査することができるのです。 +`number`の型が実行時にしか決まらないのであれば、コンパイラはそれを実行することができなくなってしまいます; +どの変数に対しても、架空の複数の型があることを追いかけなければならないのであれば、コンパイラはより複雑になり、 +コードに対して行える保証が少なくなってしまうでしょう。 @@ -360,8 +361,9 @@ error[E0308]: if and else have incompatible types -一連のコードを1回以上実行できることは、しばしば役に立ちます。この作業用に、Rustにはいくつかの -*ループ*が用意されています。ループは、本体内のコードを最後まで実行し、直後にまた最初から開始します。 +一連のコードを1回以上実行できると、しばしば役に立ちます。この作業用に、 +Rustにはいくつかの*ループ*が用意されています。ループは、本体内のコードを最後まで実行し、 +直後にまた最初から処理を開始します。 ループを試してみるのに、*loops*という名の新プロジェクトを作りましょう。 @@ -400,8 +402,8 @@ fn main() { このプログラムを実行すると、プログラムを手動で止めるまで、何度も何度も続けて`again!`と出力するでしょう。 -ほとんどのターミナルでctrl-Cというショートカットが使え、永久ループに囚われてしまったプログラムを終了させられます。 -試しにやってみましょう: +ほとんどのターミナルでctrl-Cというショートカットが使え、 +永久ループに囚われてしまったプログラムを終了させられます。試しにやってみましょう: ```text $ cargo run @@ -427,8 +429,8 @@ again! -幸いなことに、Rustにはループを抜け出す別のより信頼できる手段があります。ループ内に`break` -キーワードを配置することでプログラムに実行を終了すべきタイミングを教えることができます。 +幸いなことに、Rustにはループを抜け出す別のより信頼できる手段があります。 +ループ内に`break`キーワードを配置することでプログラムに実行を終了すべきタイミングを教えることができます。 第2章の「正しい予想をした後に終了する」節の数当てゲーム内でこれをして、ユーザが予想を的中させ、 ゲームに勝った時にプログラムを終了させたことを思い出してください。 @@ -444,8 +446,8 @@ again! プログラムにとってループ内で条件式を評価できると、有益なことがしばしばあります。条件が真の間、 ループが走るわけです。条件が真でなくなった時に`break`を呼び出し、ループを終了します。 -このタイプのループは、`loop`、`if`、`else`、`break`を組み合わせることで実装できます; -なんならプログラムで試してみるのもいいでしょう。 +このタイプのループは、`loop`、`if`、`else`、`break`を組み合わせることでも実装できます; +お望みなら、プログラムで試してみるのもいいでしょう。 @@ -538,7 +540,7 @@ the value is: 50 -予想通り、配列の5つの要素が全てターミナルに出力されました。`index`変数の値はどこかで`5`という値になるものの、 +予想通り、配列の5つの要素が全てターミナルに出力されています。`index`変数の値はどこかで`5`という値になるものの、 配列から6番目の値を拾おうとする前にループは実行を終了します。 @@ -546,14 +548,14 @@ the value is: 50 -しかし、このアプローチは間違いが発生しやすいです; 添え字の長さが間違っていれば、プログラムは -パニックしてしまいます。また遅いです。コンパイラが実行時にループの各回ごとに境界値チェックを行う -ようなコードを追加するからです。 +しかし、このアプローチは間違いが発生しやすいです; 添え字の長さが間違っていれば、 +プログラムはパニックしてしまいます。また遅いです。 +コンパイラが実行時にループの各回ごとに境界値チェックを行うようなコードを追加するからです。 -より効率的な対立案として、`for`ループを使ってコレクションの各アイテムにコードを実行することができます。 +より効率的な対立案として、`for`ループを使ってコレクションの各アイテムに対してコードを実行することができます。 `for`ループはこんな見た目です: @@ -581,17 +583,17 @@ fn main() { -このコードを走らせたら、リスト3-5と同じ出力が得られるでしょう。より重要なのは、コードの安全性を -向上させ、配列の終端を超えてアクセスしたり、終端に届く前にループを終えてアイテムを見逃してしまったりする -バグの可能性を完全に排除したことです。 +このコードを走らせたら、リスト3-5と同じ出力が得られるでしょう。より重要なのは、 +コードの安全性を向上させ、配列の終端を超えてアクセスしたり、 +終端に届く前にループを終えてアイテムを見逃してしまったりするバグの可能性を完全に排除したことです。 -例えば、リスト3-5のコードで、`a`配列からアイテムを1つ削除したのに、条件式を`while index < 4`に -するのを忘れていたら、コードはパニックします。`for`ループを使っていれば、配列の要素数を変えても、 +例えば、リスト3-5のコードで、`a`配列からアイテムを1つ削除したのに、条件式を`while index < 4`にするのを忘れていたら、 +コードはパニックします。`for`ループを使っていれば、配列の要素数を変えても、 他のコードをいじることを覚えておく必要はなくなるわけです。 @@ -603,16 +605,15 @@ fn main() { `for`ループのこの安全性と簡潔性により、Rustで使用頻度の最も高いループになっています。 -リスト3-5で`while`ループを使ったカウントダウンサンプルのように、一定の回数、同じコードを実行したい -ような状況であっても、多くのRust市民は、`for`ループを使うでしょう。どうやってやるかといえば、 -`Range`型を使うのです。Range型は、標準ライブラリで提供される片方の数字から始まって、もう片方の数字未満の -数値を順番に生成する型です。 +リスト3-5で`while`ループを使ったカウントダウンサンプルのように、一定の回数、同じコードを実行したいような状況であっても、 +多くのRust市民は、`for`ループを使うでしょう。どうやってやるかといえば、 +`Range`型を使うのです。Range型は、標準ライブラリで提供される片方の数字から始まって、 +もう片方の数字未満の数値を順番に生成する型です。 -`for`ループを使い、まだ話していない別のメソッド`rev`を使って範囲を逆順にした -カウントダウンはこうなります: +`for`ループを使い、まだ話していない別のメソッド`rev`を使って範囲を逆順にしたカウントダウンはこうなります: @@ -649,7 +650,7 @@ fn main() { * 温度を華氏と摂氏で変換する。 * フィボナッチ数列のn番目を生成する。 -* クリスマスキャロルの定番、"The Twelve Days of Christmas"の歌詞を +* クリスマスキャロルの定番、"The Twelve Days of Christmas"の歌詞を、 曲の反復性を利用して出力する。 From 93fe3d5765bab9353c9b4e4041befedc4ebddc5e Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 27 Aug 2017 22:34:28 +0900 Subject: [PATCH 034/428] Fix some errors in the Chapter 5-1 --- second-edition/src/ch05-01-defining-structs.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/second-edition/src/ch05-01-defining-structs.md b/second-edition/src/ch05-01-defining-structs.md index 7bec3fda0..a8ca39669 100644 --- a/second-edition/src/ch05-01-defining-structs.md +++ b/second-edition/src/ch05-01-defining-structs.md @@ -50,7 +50,7 @@ struct User { 構造体を定義した後に使用するには、各フィールドに対して具体的な値を指定して構造体の*インスタンス*を生成します。 インスタンスは、構造体名を記述し、`key: value`ペアを含む波かっこを付け加えることで生成します。 ここで、キーはフィールド名、値はそのフィールドに格納したいデータになります。フィールドは、 -構造体で定義した時通りの順番に指定する必要はありません。換言すると、構造体定義とは、 +構造体で宣言した通りの順番に指定する必要はありません。換言すると、構造体定義とは、 型に対する一般的な雛形のようなものであり、インスタンスは、その雛形を特定のデータで埋め、その型の値を生成するわけです。 例えば、リスト5-2で示されたように特定のユーザを宣言することができます。 @@ -236,7 +236,7 @@ let user2 = User { *構造体更新記法*は、リスト5-6のコードと同じ効果を達成しつつ、コード量を減らせます。構造体更新記法は、 -`..`を使い、明示的にセットされていない残りのフィールドが与えられたインスタンスの値と同じになるように指定します。 +`..`を使い、明示的にセットされていない残りのフィールドが、与えられたインスタンスの値と同じになるように指定します。 リスト5-7のコードも、`email`と`username`の値は異なり、`active`と`sign_in_count`の値は、 `user1`と同じになる`user2`というインスタンスを生成します。 @@ -303,7 +303,7 @@ let origin = Point(0, 0, 0); -### フィールドのないユニット様構造体 +### フィールドのないユニット(よう)構造体 @@ -312,7 +312,7 @@ let origin = Point(0, 0, 0); また、一切フィールドのない構造体を定義することもできます!これらは、`()`、ユニット型と似たような振る舞いをすることから、 -*ユニット様(よう)構造体*と呼ばれます。ユニット様構造体は、ある型にトレイトを実装するけれども、 +*ユニット様構造体*と呼ばれます。ユニット様構造体は、ある型にトレイトを実装するけれども、 型自体に保持させるデータは一切ないような場合に有効になります。トレイトについては第10章で議論します。 @@ -408,6 +408,7 @@ let origin = Point(0, 0, 0); > | > 2 | username: &str, > | ^ expected lifetime parameter +> (ライフタイム引数を予期しました) > > error[E0106]: missing lifetime specifier > --> From 017f8f13bcc0b62c423e46c7f8fb13e0addac4b3 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 27 Aug 2017 23:02:09 +0900 Subject: [PATCH 035/428] Fix an error in the Chapter 5-2 --- second-edition/src/ch05-02-example-structs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch05-02-example-structs.md b/second-edition/src/ch05-02-example-structs.md index edb659619..50ee6de8b 100644 --- a/second-edition/src/ch05-02-example-structs.md +++ b/second-edition/src/ch05-02-example-structs.md @@ -189,7 +189,7 @@ fn area(rectangle: &Rectangle) -> u32 { -これで`area`関数は引数が一つになり、この引数は名前が`rectangle`、型は`Rectangle`構造体インスタンスへの不変参照になりました。 +これで`area`関数は引数が一つになり、この引数は名前が`rectangle`、型は`Rectangle`構造体インスタンスへの不変借用になりました。 第4章で触れたように、構造体の所有権を奪うよりも借用する必要があります。こうすることで`main`は所有権を保って、 `rect1`を使用し続けることができ、そのために関数シグニチャと関数呼び出し時に`&`を使っているわけです。 From dbf2e0ab98a9e58f7720c3af4e9dd00fbb09cfda Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 28 Aug 2017 19:10:43 +0900 Subject: [PATCH 036/428] Fix some errors in the Chapter 5-3 --- second-edition/src/ch05-03-method-syntax.md | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/second-edition/src/ch05-03-method-syntax.md b/second-edition/src/ch05-03-method-syntax.md index 0e87d2349..03552be3b 100644 --- a/second-edition/src/ch05-03-method-syntax.md +++ b/second-edition/src/ch05-03-method-syntax.md @@ -110,7 +110,7 @@ fn main() { 関数の代替としてメソッドを使う主な利点は、メソッド記法を使用して全メソッドのシグニチャで`self`の型を繰り返す必要がなくなる以外だと、 -体系化です。コードの将来的な利用者に`Rectangle`の機能を提供しているライブラリ内の各所で探させるのではなく、 +体系化です。コードの将来的な利用者に`Rectangle`の機能を提供しているライブラリ内の各所でその機能を探させるのではなく、 この型のインスタンスでできることを一つの`impl`ブロックにまとめあげています。 @@ -164,7 +164,7 @@ fn main() { > C++のような言語では、メソッド呼び出しには2種類の異なる演算子が使用されます: > オブジェクトに対して直接メソッドを呼び出すのなら、`.`を使用するし、オブジェクトのポインタに対してメソッドを呼び出し、 > 先にポインタを参照外しする必要があるなら、`->`を使用するわけです。 -> 言い換えると、`object`がポインタなら、`object->something()`は、`(*object).something()`と類似するのです。 +> 言い換えると、`object`がポインタなら、`object->something()`は、`(*object).something()`と同等なのです。 > > Rustには`->`演算子の代わりとなるようなものはありません; その代わり、Rustには、 > *自動参照および参照外し*という機能があります。Rustにおいてメソッド呼び出しは、 @@ -196,8 +196,8 @@ fn main() { > ``` > > 前者の方がずっと明確です。メソッドには自明な受け手(`self`の型)がいるので、この自動参照機能は動作するのです。 -> 受け手とメソッド名が与えられれば、コンパイラは確実にメソッドが読み込み専用か、書き込みもするのか、 -> 所有権を奪うのか判断できるわけです。Rustにおいて、メソッドの受け手に関して借用が明示されないという事実は、 +> 受け手とメソッド名が与えられれば、コンパイラは確実にメソッドが読み込み専用(`&self`)か、書き込みもする(`&mut self`)のか、 +> 所有権を奪う(`self`)のか判断できるわけです。Rustにおいて、メソッドの受け手に関して借用が明示されないという事実は、 > 所有権を現実世界でプログラマフレンドリーにさせる大部分を占めているのです。 @@ -264,10 +264,10 @@ Can rect1 hold rect3? false メソッドを定義したいことはわかっているので、`impl Rectangle`ブロック内での話になります。 -メソッド名は、`can_hold`になり、引数として別の`Rectangle`を不変参照で取るでしょう。 +メソッド名は、`can_hold`になり、引数として別の`Rectangle`を不変借用で取るでしょう。 メソッドを呼び出すコードを見れば、引数の型が何になるかわかります: `rect1.can_hold(&rect2)`は、 -`&rect2`、`Rectangle`のインスタンスである`rect2`への不変参照を渡しています。 -これは道理が通っています。なぜなら、`rect2`を読み込む(書き込みではなく。この場合、可変参照が必要になります)だけでよく、 +`&rect2`、`Rectangle`のインスタンスである`rect2`への不変借用を渡しています。 +これは道理が通っています。なぜなら、`rect2`を読み込む(書き込みではなく。この場合、可変借用が必要になります)だけでよく、 `can_hold`メソッドを呼び出した後にも`rect2`が使えるよう、所有権を`main`に残したままにしたいからです。 `can_hold`の返り値は、論理型になり、メソッドの中身は、`self`の長さと幅がもう一つの`Rectangle`の長さと幅よりも、 それぞれ大きいことを確認します。リスト5-13の`impl`ブロックに新しい`can_hold`メソッドを追記しましょう。 @@ -308,7 +308,7 @@ impl Rectangle { このコードをリスト5-14の`main`関数と合わせて実行すると、望み通りの出力が得られます。 メソッドは、`self`引数の後にシグニチャに追加した引数を複数取ることができ、 -関数の引数と同様に動作するのです。 +その引数は、関数の引数と同様に動作するのです。 @@ -359,8 +359,8 @@ impl Rectangle { この関連関数を呼び出すために、例えば、`let sq = Rectangle::square(3);`のように、 -構造体名と一緒に`::`記法を使用しています。この関数は、構造体によって名前空間分けされています: -`::`という記法は、関連関数とモジュールによって作り出される名前空間両方に使用され、 +構造体名と一緒に`::`記法を使用します。この関数は、構造体によって名前空間分けされています: +`::`という記法は、関連関数とモジュールによって作り出される名前空間両方に使用されます。 モジュールについては第7章で議論します。 @@ -404,7 +404,7 @@ impl Rectangle { ここでこれらのメソッドを個々の`impl`ブロックに分ける理由はないのですが、有効な書き方です。 -複数の`impl`ブロックが有用になるケースは第10章で見ますが、そこではジェネリクスのある型とトレイトについて議論します。 +複数の`impl`ブロックが有用になるケースは第10章で見ますが、そこではジェネリクスのある型と、トレイトについて議論します。 @@ -418,7 +418,7 @@ impl Rectangle { 構造体により、自分の領域で意味のある独自の型を作成することができます。構造体を使用することで、 -関連のあるデータ片を相互に結合させ続け、各部品に名前を付け、コードを明確にすることができます。 +関連のあるデータ片を相互に結合させたままにし、各部品に名前を付け、コードを明確にすることができます。 メソッドにより、構造体のインスタンスが行う動作を指定することができ、関連関数により、 構造体に特有の機能をインスタンスを利用することなく名前空間分けすることができます。 From 80a35b58609850b35c97aa5d023da558be6603e4 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 28 Aug 2017 19:20:30 +0900 Subject: [PATCH 037/428] Use other words on some texts --- second-edition/src/ch06-00-enums.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/second-edition/src/ch06-00-enums.md b/second-edition/src/ch06-00-enums.md index 3a3e6676a..356207e52 100644 --- a/second-edition/src/ch06-00-enums.md +++ b/second-edition/src/ch06-00-enums.md @@ -16,14 +16,14 @@ この章では、*列挙型*について見ていきます。列挙型は、*enum*とも称されます。enumは、取りうる値を列挙することで、 型を定義させてくれます。最初に、enumを定義し、使用して、enumがデータとともに意味をエンコードする方法を示します。 -次に、特別に有効なenumである`Option`について掘り下げていきましょう。この型は、 +次に、特別に有用なenumである`Option`について掘り下げていきましょう。この型は、 値が何かかなんでもないかを表現します。それから、`match`式のパターンマッチングにより、 どうenumの異なる値に対して異なるコードを走らせやすくなるかを見ます。最後に、`if let`文法要素も、 -どうenumをコードで扱う際に使用可能な便利で簡潔な慣用句であることを解説します。 +如何(いか)にenumをコードで扱う際に使用可能な便利で簡潔な慣用句であるかを解説します。 enumは多くの言語に存在する機能ですが、その能力は言語ごとに異なります。Rustのenumは、F#、OCaml、Haskellなどの、 -関数型言語にある*数学的データ型*に非常に酷似しています。 +関数型言語に存在する*数学的データ型*に非常に酷似しています。 From 600560f18d9eee6523a94819dd3cca70ca1bc184 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 28 Aug 2017 20:02:15 +0900 Subject: [PATCH 038/428] Use other words on some texts and enhance the quality of the texts in the Chapter 6-1 --- .../src/ch06-01-defining-an-enum.md | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/second-edition/src/ch06-01-defining-an-enum.md b/second-edition/src/ch06-01-defining-an-enum.md index 31599a8ec..3409efcce 100644 --- a/second-edition/src/ch06-01-defining-an-enum.md +++ b/second-edition/src/ch06-01-defining-an-enum.md @@ -9,7 +9,7 @@ -コードで表現したくなるかもしれない場面を見て、enumが有効でこの場合、構造体よりも適切である理由を確認しましょう。 +コードで表現したくなるかもしれない場面に目を向けて、enumが有効でこの場合、構造体よりも適切である理由を確認しましょう。 IPアドレスを扱う必要が出たとしましょう。現在、IPアドレスの規格は二つあります: バージョン4とバージョン6です。 これらは、プログラムが遭遇するIPアドレスのすべての可能性です: 列挙型は、取りうる値をすべて*列挙*でき、 これが列挙型の名前の由来です。 @@ -22,7 +22,7 @@ IPアドレスを扱う必要が出たとしましょう。現在、IPアドレ どんなIPアドレスも、バージョン4かバージョン6のどちらかになりますが、同時に両方にはなり得ません。 -今回の場合、IPアドレスのその要素によりenumデータ構造が適切なものになります。というのも、 +今回の場合、IPアドレスのその特性によりenumデータ構造が適切なものになります。というのも、 enumの値は、そのバリアントのいずれか一つにしかなり得ないからです。バージョン4とバージョン6のアドレスは、 どちらも根源的にはIPアドレスですから、コードがいかなる種類のIPアドレスにも適用される場面を扱う際には、 同じ型として扱われるべきです。 @@ -43,7 +43,7 @@ enum IpAddrKind { -これで、`IpAddrKind`はコードの他の場所で使用できるカスタマイズされたデータ型になります。 +これで、`IpAddrKind`はコードの他の場所で使用できる独自のデータ型になります。 @@ -85,7 +85,7 @@ fn route(ip_type: IpAddrKind) { } -そして、この関数をどちらのバリアント対しても呼び出せます: +そして、この関数をどちらのバリアントに対しても呼び出せます: ```rust # enum IpAddrKind { @@ -156,7 +156,7 @@ let loopback = IpAddr { -各enumのバリアントに直接データを格納して、enumを構造体の一部というよりもenumだけを使って、 +各enumのバリアントに直接データを格納して、enumを構造体の一部にするというよりもenumだけを使って、 同じ概念をもっと簡潔な方法で表現することができます。この新しい`IpAddr`の定義は、 `V4`と`V6`バリアント両方に`String`値が紐付けられていることを述べています。 @@ -174,7 +174,7 @@ let loopback = IpAddr::V6(String::from("::1")); -enumの各バリアントにデータを直接添加できるので、余計な構造体を作る必要は全くありません。 +enumの各バリアントにデータを直接添付できるので、余計な構造体を作る必要は全くありません。 @@ -305,6 +305,7 @@ enum Message { リスト6-2のようなバリアントを含むenumを定義することは、enumの場合、`struct`キーワードを使わず、 全部のバリアントが`Message`型の元に分類される点を除いて、異なる種類の構造体定義を定義するのと類似しています。 +以下の構造体も、先ほどのenumのバリアントが保持しているのと同じデータを格納することができます: @@ -374,7 +375,7 @@ m.call(); -非常に一般的で有効な別の標準ライブラリのenumを見てみましょう: `Option`です。 +非常に一般的で有用な別の標準ライブラリのenumを見てみましょう: `Option`です。 @@ -389,7 +390,7 @@ m.call(); -前節で、`IpAddr`enumがRustの型システムを使用して、プログラムにデータ以上の情報をエンコードできる方法を見ました。 +前節で、`IpAddr`enumがRustの型システムを使用して、プログラムにデータ以上の情報をエンコードできる方法を目撃しました。 この節では、`Option`のケーススタディを掘り下げていきます。この型も標準ライブラリにより定義されているenumです。 この`Option`型はいろんな箇所で使用されます。なぜなら、値が何かかそうでないかという非常に一般的な筋書きをコード化するからです。 この概念を型システムの観点で表現することは、コンパイラが、プログラマが処理すべき場面全てを処理していることをチェックできることを意味し、 @@ -421,7 +422,7 @@ nullの開発者であるTony Hoareの著書"Null References: The Billion Dollar > 私はそれを10億ドルの失敗と呼んでいます。その頃、私は、オブジェクト指向言語の参照に対する、 -> 最初のわかりやすい型システムをデザインしていました。私の目標は、 +> 最初のわかりやすい型システムを設計していました。私の目標は、 > どんな参照の使用も全て完全に安全であるべきことを、コンパイラにそのチェックを自動で行ってもらって保証することだったのです。 > しかし、null参照を入れるという誘惑に打ち勝つことができませんでした。それは、単純に実装が非常に容易だったからです。 > これが無数のエラーや脆弱性、システムクラッシュにつながり、過去40年で10億ドルの苦痛や損害を引き起こしたであろうということなのです。 @@ -438,7 +439,7 @@ null値の問題は、nullの値をnullでない値のように実際に使用 しかしながら、nullが表現しようとしている概念は、それでも役に立つものです: nullは、 -何らかの理由で現在無効または存在しない値のことなのです。 +何らかの理由で現在無効、または存在しない値のことなのです。 @@ -466,7 +467,7 @@ enum Option { `Option`は有益すぎて、初期化処理(prelude)にさえ含まれています。つまり、明示的にインポートする必要がないのです。 -さらに、バリアントもそうなっています: `Some`と`None`を`Option::`と接頭辞をつけることなく直接使えるわけです。 +さらに、バリアントもそうなっています: `Some`と`None`を`Option::`と接頭辞を付けることなく直接使えるわけです。 ただ、`Option`は普通のenumであり、`Some(T)`と`None`は`Option`型のバリアントです。 @@ -501,7 +502,7 @@ let absent_number: Option = None; `Some`値がある時、値が存在するとわかり、その値は、`Some`に保持されています。`None`値がある場合、 ある意味、nullと同じことを意図します: 有効な値がないのです。では、なぜ`Option`の方が、 -nullよりも好ましいのでしょうか? +nullよりも少しでも好ましいのでしょうか? @@ -572,7 +573,7 @@ nullでない値があるという想定を見逃す心配をしなくてもよ nullになる可能性のある値を保持するには、その値の型を`Option`にすることで明示的に同意しなければなりません。 それからその値を使用する際には、値がnullである場合を明示的に処理する必要があります。 値が`Option`以外の型であるとこ全てにおいて、値がnullでないと安全に想定することが*できます*。 -これは、Rustにとって、意図的なデザイン決定であり、nullの普遍性を制限し、Rustコードの安全性を向上させます。 +これは、Rustにとって、意図的な設計上の決定であり、nullの普遍性を制限し、Rustコードの安全性を向上させます。 @@ -599,5 +600,5 @@ Rustの旅が極めて有益になるでしょう。 一般的に、`Option`値を使うには、各バリアントを処理するコードが欲しくなります。 `Some(T)`値がある時だけ走る何らかのコードが欲しくなり、このコードが内部の`T`を使用できます。 `None`値があった場合に走る別のコードが欲しくなり、そちらのコードは`T`値は使用できない状態になります。 -`match`式が、enumとともに使用した時にこれだけをするフロー制御文法要素になります: enumのバリアントによって、 -違うコードが走り、そのコードがマッチした値の中のデータを使用できるのです。 +`match`式が、enumとともに使用した時にこれだけの動作をするフロー制御文法要素になります: +enumのバリアントによって、違うコードが走り、そのコードがマッチした値の中のデータを使用できるのです。 From 530aae23ec718130db7bc767b2cb10a17bf33621 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 28 Aug 2017 20:29:29 +0900 Subject: [PATCH 039/428] Use other words on some texts and enhance the quality of the content in the Chapter 6-2 --- second-edition/src/ch06-02-match.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/second-edition/src/ch06-02-match.md b/second-edition/src/ch06-02-match.md index aa9263db8..c3c6a89e0 100644 --- a/second-edition/src/ch06-02-match.md +++ b/second-edition/src/ch06-02-match.md @@ -11,7 +11,7 @@ Rustには、一連のパターンに対して値を比較し、マッチしたパターンに応じてコードを実行させてくれる`match`と呼ばれる、 -非常に強力なフロー制御演算子があります。パターンは、リテラル値、変数名、ワイルドカードや他の多くのもので構成することができます; +非常に強力なフロー制御演算子があります。パターンは、リテラル値、変数名、ワイルドカードやその他多数のもので構成することができます; 第18章で、全ての種類のパターンと、その目的については解説します。`match`のパワーは、 パターンの表現力に由来し、コンパイラが全てのありうるパターンを処理しているかを確認してくれます。 @@ -22,7 +22,7 @@ Rustには、一連のパターンに対して値を比較し、マッチした `match`式をコイン並べ替え装置のようなものと考えてください: コインは、様々なサイズの穴が空いた通路を流れ落ち、 -各コインは、サイズのあった最初の穴に落ちます。同様に、値は`match`の各パターンを通り抜け、値が適合する最初のパターンで、 +各コインは、サイズのあった最初の穴に落ちます。同様に、値は`match`の各パターンを通り抜け、値が「適合する」最初のパターンで、 値は紐付けられたコードブロックに落ち、実行中に使用されるわけです。 @@ -63,7 +63,7 @@ fn value_in_cents(coin: Coin) -> u32 { -`value_in_cents`関数内の`match`を掘り下げてみましょう。まず、`match`キーワードに続けて式を並べています。 +`value_in_cents`関数内の`match`を分解してみましょう。まず、`match`キーワードに続けて式を並べています。 この式は今回の場合、値`coin`です。`if`で使用した式と非常に酷似していますね。しかし、大きな違いがあります: `if`では、式は論理値を返す必要があります。ここでは、どんな型でも構いません。この例における`coin`の型は、 リスト6-3で定義した`Coin`enumです。 @@ -257,14 +257,14 @@ fn value_in_cents(coin: Coin) -> u32 { 前節では、`Option`を使用する際に、`Some`ケースから中身の`T`の値を取得したくなりました。要するに、 `Coin`enumに対して行ったように、`match`を使って`Option`を扱うこともできるというわけです! -コインを比較する代わりに、`Option`のバリアントを比較するのですが、`match`式の動作の仕方は同じになったままです。 +コインを比較する代わりに、`Option`のバリアントを比較するのですが、`match`式の動作の仕方は同じままです。 -`Option`をとる関数を書きたくなったとし、中に値があったら、その値に1を足すことにしましょう。 +`Option`を取る関数を書きたくなったとし、中に値があったら、その値に1を足すことにしましょう。 中に値がなければ、関数は`None`値を返し、何も処理すべきではありません。 @@ -299,7 +299,7 @@ let none = plus_one(None); `plus_one`の最初の実行についてもっと詳しく検証しましょう。`plus_one(five)`と呼び出した時、 -`plus_one`の本体の変数`x`は`Some(5)`になります。そして、これを各マッチのアームに比較します。 +`plus_one`の本体の変数`x`は`Some(5)`になります。そして、これをマッチの各アームと比較します。 ```rust,ignore None => None, @@ -356,7 +356,7 @@ enumに対し`match`し、内部のデータに変数を束縛させ、それに - + ### マッチは包括的 @@ -397,7 +397,7 @@ error[E0004]: non-exhaustive patterns: `None` not covered 全可能性を網羅していないことをコンパイラは検知しています。もっと言えば、どのパターンを忘れているかさえ知っているのです。 -Rustにおけるマッチは、*包括的*です: 全てのあらゆる可能性を消費し尽くさなければ、コードは有効にならないのです。 +Rustにおけるマッチは、*包括的*です: 全てのあらゆる可能性を網羅し尽くさなければ、コードは有効にならないのです。 特に`Option`の場合には、コンパイラが明示的に`None`の場合を扱うのを忘れないようにする時、 nullになるかもしれない値があることを想定しないように、つまり、前に議論した10億ドルの失敗を犯さないよう、 保護してくれるわけです。 @@ -441,5 +441,5 @@ match some_u8_value { -ですが、一つのケースにしか興味がないような場面では、`match`式はちょっと長ったらしすぎます。 +ですが、*一つ*のケースにしか興味がないような場面では、`match`式はちょっと長ったらしすぎます。 このような場面用に、Rustには、`if let`が用意されています。 From e93be04b458f4339e01c3f347add41f419c3b2a7 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 28 Aug 2017 22:40:29 +0900 Subject: [PATCH 040/428] Fix an error in the Chapter 6-2 --- second-edition/src/ch06-02-match.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch06-02-match.md b/second-edition/src/ch06-02-match.md index c3c6a89e0..cc6ecb18b 100644 --- a/second-edition/src/ch06-02-match.md +++ b/second-edition/src/ch06-02-match.md @@ -63,7 +63,7 @@ fn value_in_cents(coin: Coin) -> u32 { -`value_in_cents`関数内の`match`を分解してみましょう。まず、`match`キーワードに続けて式を並べています。 +`value_in_cents`関数内の`match`を分解しましょう。まず、`match`キーワードに続けて式を並べています。 この式は今回の場合、値`coin`です。`if`で使用した式と非常に酷似していますね。しかし、大きな違いがあります: `if`では、式は論理値を返す必要があります。ここでは、どんな型でも構いません。この例における`coin`の型は、 リスト6-3で定義した`Coin`enumです。 From a2e0cc010b53c4945a57a99c66b2326ba7d1a6a6 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 28 Aug 2017 22:51:03 +0900 Subject: [PATCH 041/428] Fix some errors in the Chapter 6-3 --- second-edition/src/ch06-03-if-let.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/second-edition/src/ch06-03-if-let.md b/second-edition/src/ch06-03-if-let.md index 93a198b84..fd7b84a0e 100644 --- a/second-edition/src/ch06-03-if-let.md +++ b/second-edition/src/ch06-03-if-let.md @@ -1,6 +1,6 @@ -## `if let`で完結なフロー制御 +## `if let`で簡潔なフロー制御 @@ -66,8 +66,8 @@ if let Some(3) = some_u8_value { -言い換えると、`if let`は値が一つのパターンにマッチした時にコードを走らせ、他は無視する`match`への糖衣構文と、 -考えることができます。 +言い換えると、`if let`は値が一つのパターンにマッチした時にコードを走らせ、 +他は無視する`match`への糖衣構文と考えることができます。 @@ -81,7 +81,7 @@ if let Some(3) = some_u8_value { `if let`と`else`に等価な`match`式の`_`の場合に入るコードブロックと同じになります。 リスト6-4の`Coin`enum定義を思い出してください。ここでは、`Quarter`バリアントは、 `UsState`の値も保持していましたね。クォーターコインの状態を告げつつ、 -見かけたクォーター以外のコインの枚数を数えたいなら、以下のように`match`式ですることができます: +見かけたクォーター以外のコインの枚数を数えたいなら、以下のように`match`式で実現することができます: ```rust # #[derive(Debug)] From 7fa412c02697734fc5c7bad81224e547b086b44f Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 28 Aug 2017 23:05:09 +0900 Subject: [PATCH 042/428] Fix some errors in the Chapter 7-0 --- second-edition/src/ch07-00-modules.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/second-edition/src/ch07-00-modules.md b/second-edition/src/ch07-00-modules.md index b625cd0ed..6a625a735 100644 --- a/second-edition/src/ch07-00-modules.md +++ b/second-edition/src/ch07-00-modules.md @@ -12,7 +12,7 @@ Rustでのプログラミングをし始めた頃は、コードは全て`main`関数内に収まったかもしれません。コードが肥大化するにつれ、 最終的に機能を別の関数に移して再利用性とまとまりを高めるでしょう。コードを細切りにすることで、 個々のコード片はそれだけで理解しやすくなります。しかし、あまりにも多くの関数があったらどうなるでしょうか? -Rustにはコードの再利用を体系化された形で行うことのできるモジュールシステムが組み込まれています。 +Rustには、コードの再利用を体系化された形で行うことのできるモジュールシステムが組み込まれています。 @@ -34,11 +34,11 @@ Rustにはコードの再利用を体系化された形で行うことのでき * `mod`キーワードで新規モジュールを宣言します。モジュール内のコードは、この宣言の直後の波かっこ内か、 別のファイルに存在します。 -* 標準では、関数、型、定数、モジュールはプライベートです。`pub`キーワードで要素は公開され、 +* 標準では、関数、型、定数、モジュールは非公開です。`pub`キーワードで要素は公開され、 名前空間の外からも見えるようになります。 * `use`キーワードでモジュールやモジュール内の定義をスコープに入れることができるので、 参照するのが楽になります。 -この部品の各々を見て、それらが全体にどうはまり込むかを理解します。 +この各部品を見て、それらが全体にどうはまり込むかを理解します。 From d5138fd13de1ebe1a728f96182f4decc40a079c0 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 29 Aug 2017 19:10:32 +0900 Subject: [PATCH 043/428] Fix some errors in the Chapters 6-3 and 7-1 --- second-edition/src/ch06-03-if-let.md | 4 ++-- .../src/ch07-01-mod-and-the-filesystem.md | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/second-edition/src/ch06-03-if-let.md b/second-edition/src/ch06-03-if-let.md index fd7b84a0e..9f032231b 100644 --- a/second-edition/src/ch06-03-if-let.md +++ b/second-edition/src/ch06-03-if-let.md @@ -147,7 +147,7 @@ if let Coin::Quarter(state) = coin { -これで、enumを使用してワンセットの列挙された値のどれかになりうるカスタマイズされた型を生成する方法を解説しました。 +これで、enumを使用してワンセットの列挙された値のどれかになりうる独自の型を生成する方法を解説しました。 標準ライブラリの`Option`が型システムを使用して、エラーを回避する際に役立つ方法についても示しました。 enumの値がデータを内部に含む場合、処理すべきケースの数に応じて、`match`か`if let`を使用して値を取り出し、 使用できます。 @@ -157,7 +157,7 @@ enumの値がデータを内部に含む場合、処理すべきケースの数 -もうRustプログラムで構造体とenumを使用して、自分の領域の概念を表現できます。API内で使用するためにカスタマイズされた型を生成することで、 +もうRustプログラムで構造体とenumを使用して、自分の領域の概念を表現できます。API内で使用するために独自の型を生成することで、 型安全性を保証することができます: コンパイラが、各関数の予期する型の値のみを関数が得ることを確かめてくれるのです。 diff --git a/second-edition/src/ch07-01-mod-and-the-filesystem.md b/second-edition/src/ch07-01-mod-and-the-filesystem.md index 27355f89b..bc04ebff5 100644 --- a/second-edition/src/ch07-01-mod-and-the-filesystem.md +++ b/second-edition/src/ch07-01-mod-and-the-filesystem.md @@ -82,7 +82,7 @@ Cargoは、`--bin`オプションを使った時に得られる"Hello, world!" `communicator`ネットワークライブラリについて、まずは`connect`という関数定義を含む`network`という名前のモジュールを定義します。 -Rustにおいて、モジュール定義は、`mod`キーワードから開始します。このコードを*src/lib.rs*ファイルの頭、 +Rustにおいて、モジュール定義は全て、`mod`キーワードから開始します。このコードを*src/lib.rs*ファイルの頭、 テストコードの上に追記してください。 @@ -113,8 +113,8 @@ mod network { -同じ*src/lib.rs*ファイル内に複数のモジュールを並べることもできます。`connect`という関数を含む`client`モジュールを用意するには、 -リスト7-1に示したように追記すればいいわけです: +同じ*src/lib.rs*ファイル内に複数のモジュールを並べることもできます。例として、 +`connect`という関数を含む`client`モジュールを用意するには、リスト7-1に示したように追記すればいいわけです: @@ -364,7 +364,7 @@ fn connect() { このファイルには、`mod`宣言が必要ないことに着目してください。なぜなら、*src/lib.rs*に`mod`を使って、 -もう`client`モジュールを宣言しているからです。このファイルは、`client`モジュールの中身を提供するだけなのです。 +もう`client`モジュールを宣言しているからです。このファイルは、`client`モジュールの*中身*を提供するだけなのです。 ここにも`mod client`を記述したら、`client`に`client`という名前のサブモジュールを与えることになってしまいます! @@ -414,7 +414,8 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default これらの警告は、全く使用されていない関数があると忠告してくれています。今は、警告を危惧する必要はありません; -この章の後ほど、「`pub`で公開するか制御する」節で特定します。嬉しいことにただの警告です; プロジェクトはビルドに成功しました! +この章の後ほど、「`pub`で公開するか制御する」節で特定します。嬉しいことにただの警告です; +プロジェクトはビルドに成功しました! @@ -455,7 +456,7 @@ mod server { このモジュールファイル内にもまだ`mod`宣言があることに気付いてください; -`server`は`network`のサブモジュールにしたいからです。 +`server`はまだ`network`のサブモジュールにしたいからです。 @@ -574,7 +575,8 @@ $ mv src/server.rs src/network `cargo build`を走らせたら、ようやくコンパイルは通ります(まだ警告はありますけどね)。 -モジュールの配置は以下のような感じになります。これは、リスト7-3で*src/lib.rs*に全てのコードを収めていたときと全く変わらないですね: +それでも、モジュールの配置は以下のような感じになります。 +これは、リスト7-3で*src/lib.rs*に全てのコードを収めていたときと全く変わらないですね: ```text communicator @@ -585,7 +587,7 @@ communicator -対応するファイルの配置は、以下のようになりました: +対応するファイルの配置は、以下のようになっています: ```text ├── src From 9ce1cf3559fca16085d7fd1308a20a7373a3e690 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 29 Aug 2017 19:37:39 +0900 Subject: [PATCH 044/428] Fix some errors in the Chapter 7-2 --- .../ch07-02-controlling-visibility-with-pub.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/second-edition/src/ch07-02-controlling-visibility-with-pub.md b/second-edition/src/ch07-02-controlling-visibility-with-pub.md index 4973de011..b3b9f0319 100644 --- a/second-edition/src/ch07-02-controlling-visibility-with-pub.md +++ b/second-edition/src/ch07-02-controlling-visibility-with-pub.md @@ -12,7 +12,7 @@ リスト7-4に示したエラーメッセージを`network`と`network::server`のコードを、 *src/network/mod.rs*と*src/network/server.rs*ファイルにそれぞれ移動することで解決しました。 その時点で`cargo build`はプロジェクトをビルドできましたが、`client::connect`と`network::connect`と`network::server::connect`関数が、 -まだ使用されていないという警告メッセージが出ていました: +使用されていないという警告メッセージが出ていました: ```text warning: function is never used: `connect`, #[warn(dead_code)] on by default @@ -140,7 +140,7 @@ Rustの文脈において、*公開*とか*非公開*という概念にぶち当 関数が未使用であるという警告も消え去るわけです。関数を公開にすれば、コンパイラは、 関数が自分のプログラム外のコードからも使用されることがあると知ります。コンパイラは、 関数が「使用されている」という架空の外部使用の可能性を考慮してくれます。それ故に、何かが公開とマークされれば、 -コンパイラはそれが使用されるべきという要求をなくし、その要素が未使用という警告も止めるのです。 +コンパイラはそれが自分のプログラムで使用されるべきという要求をなくし、その要素が未使用という警告も止めるのです。 @@ -228,9 +228,9 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default コード未使用警告が必ずしも、コード内の要素を公開にしなければならないことを示唆しているわけではありません: -これらの関数を公開APIの一部にしたく*なかった*ら、未使用コード警告がもう必要なく、安全に削除できるコードに注意を向けてくれる可能性もあります。 +これらの関数を公開APIの一部にしたく*なかった*ら、未使用コード警告がもう必要なく、安全に削除できるコードに注意を向けてくれている可能性もあります。 また未使用コード警告は、ライブラリ内でこの関数を呼び出している箇所全てを誤って削除した場合に、 -バグに目を向けさせてくれる可能性もあります。 +バグに目を向けさせてくれている可能性もあります。 @@ -367,7 +367,7 @@ fn try_me() { このコードをコンパイルする前に、`try_me`関数のどの行がエラーになるか当ててみてください。 -それからコンパイルを試して、合ってたかどうか確かめ、エラーの議論を読み進めてください! +それからコンパイルを試して、合ってたかどうか確かめ、エラーの議論を求めて読み進めてください! @@ -380,7 +380,7 @@ fn try_me() { `try_me`関数は、プロジェクトのルートモジュールに存在しています。`outermost`という名前のモジュールは非公開ですが、 プライバシー規則の2番目にある通り、`try_me`そのままに、`outermost`は現在(ルート)のモジュールなので、 -`try_me`関数は、`outermost`にアクセスすることを許可されるのです。 +`try_me`関数は、`outermost`モジュールにアクセスすることを許可されるのです。 @@ -396,9 +396,10 @@ fn try_me() { -`outermost::middle_secret_function`の呼び出しは、コンパイルエラーになります。 +`outermost::middle_secret_function`の呼び出しは、コンパイルエラーになるでしょう。 `middle_secret_function`は非公開なので、2番目の規則が適用されます。ルートモジュールは、 -`middle_secret_function`の現在のモジュール(`outermost`がそうです)でも、`middle_secret_function`のモジュールの子供でもないのです。 +`middle_secret_function`の現在のモジュール(`outermost`がそうです)でも、 +`middle_secret_function`の現在のモジュールの子供でもないのです。 From f6626e2a88f81c44154141cc041a71b8d935d9e1 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 29 Aug 2017 19:52:28 +0900 Subject: [PATCH 045/428] Fix some errors in the Chapter 7-3 --- .../src/ch07-03-importing-names-with-use.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/second-edition/src/ch07-03-importing-names-with-use.md b/second-edition/src/ch07-03-importing-names-with-use.md index a22f0a510..90703eb8b 100644 --- a/second-edition/src/ch07-03-importing-names-with-use.md +++ b/second-edition/src/ch07-03-importing-names-with-use.md @@ -72,7 +72,7 @@ fn main() { -`use a::series::of`の行は、`of`モジュールを参照したい箇所全部でフルパスの`a::series::of`を使用するのではなく、 +`use a::series::of;`の行は、`of`モジュールを参照したい箇所全部でフルパスの`a::series::of`を使用するのではなく、 `of`を利用できることを意味しています。 @@ -85,7 +85,7 @@ fn main() { -以下のように、代わりに`use`で関数を指定して、関数をスコープに入れることもできます: +以下のように、代わりに`use`で関数を指定して、関数をスコープに入れることもできました: ```rust pub mod a { @@ -136,7 +136,7 @@ fn main() { -`Green`を`use`文に含んでいないので、まだ`Green`バリアント用に`TrafficLight`名前空間を参照しています。 +`Green`を`use`文に含んでいないので、まだ`Green`バリアント用に`TrafficLight`名前空間を指定しています。 @@ -169,7 +169,7 @@ fn main() { `*`は*glob*(塊)と呼ばれ、名前空間内で公開されている要素全てをインポートします。 あまりglobは使用するべきではありません: 便利ではありますが、予想以上の要素を引き込んで、 -名前衝突を引き起こすかもしれないのです。 +名前衝突を引き起こす可能性があるのです。 @@ -222,7 +222,7 @@ communicator テストは、ライブラリ内でコードの準備運動を行うためのものなので、この`it_works`関数から`client::connect`関数を呼び出してみましょう。 -まあ、今のところは、機能の検査は何もしないんですけどね: +まあ、最も今のところ、機能の検査は何もしないんですけどね: @@ -260,7 +260,7 @@ error[E0433]: failed to resolve. Use of undeclared type or module `client` -コンパイルが失敗しましたが、なぜでしょうか?*src/main.rs*でしたように、関数の直前に`communicator::`を配置する必要はありません。 +コンパイルが失敗しましたが、なぜでしょうか?*src/main.rs*のように、関数の直前に`communicator::`を配置する必要はありません。 なぜなら、間違いなくここでは、`communicator`ライブラリクレート内にいるからです。 原因は、パスが常に現在のモジュールに対して相対的になり、ここでは`tests`になっているからです。 唯一の例外は、`use`文内であり、パスは標準でクレートのルートに相対的になります。 From 1618fe17ecd95ffff320e2bce9033e31ce6f61b5 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 29 Aug 2017 23:04:27 +0900 Subject: [PATCH 046/428] Fix some errors and revise the content in the Chapter 2 so that the resulting html would not contain unnecessary whitespaces between words --- .../src/ch02-00-guessing-game-tutorial.md | 221 +++++++++--------- 1 file changed, 110 insertions(+), 111 deletions(-) diff --git a/second-edition/src/ch02-00-guessing-game-tutorial.md b/second-edition/src/ch02-00-guessing-game-tutorial.md index eceb55fda..8fea43e7d 100644 --- a/second-edition/src/ch02-00-guessing-game-tutorial.md +++ b/second-edition/src/ch02-00-guessing-game-tutorial.md @@ -105,7 +105,7 @@ Hello, world! -`run`コマンドは、プロジェクトに段階を踏んで取り掛かる必要がある場合に有用であり、 +`run`コマンドは、プロジェクトに迅速に段階を踏んで取り掛かる必要がある場合に有用であり、 このゲームはその類のプロジェクトになります。 つまり、次のステップに進む前に各段階を急速にテストする必要があるわけです。 @@ -151,8 +151,8 @@ fn main() { リスト2-1: ユーザに予想を入力してもらい、それを出力するコード -> 注釈: The programming language Rust第1版の翻訳者によると、ソースコードのコメント中以外に -> 日本語文字があるとコンパイルに失敗することがあるそうなので、文字列の英語は、コメントに和訳を載せます。 +> 注釈: The programming language Rust第1版の翻訳者によると、 +> ソースコードのコメント中以外に日本語文字があるとコンパイルに失敗することがあるそうなので、文字列の英語は、コメントに和訳を載せます。 > また、重複する内容の場合には、最初の1回だけ掲載するようにします。 @@ -162,7 +162,7 @@ fn main() { このコードには、たくさんの情報が詰め込まれてますね。なので、少しずつ噛み砕いていきましょう。 ユーザ入力を受け付け、結果を出力するためには、`io`(入/出力)ライブラリをスコープに導入する必要があります。 -`io`ライブラリは、標準ライブラリ(`std`として知られています)に存在します。: +`io`ライブラリは、標準ライブラリ(`std`として知られています)に存在します: ```rust,ignore use std::io; @@ -198,7 +198,7 @@ fn main() { -また、第1章で学んだように、`println!`マクロは、文字列を画面に表示するマクロになります: +また、第1章で学んだように、`println!`は、文字列を画面に表示するマクロになります: ```rust,ignore println!("Guess the number!"); @@ -240,8 +240,8 @@ let foo = bar; この行では、`foo`という名前の新しい変数を作成し、`bar`の値に束縛しています。 -Rustでは、変数は標準で不変(immutable)です。以下の例には、変数名の前に`mut`修飾子をつけて -変数を可変にする方法が示されています: +Rustでは、変数は標準で不変(immutable)です。以下の例には、 +変数名の前に`mut`修飾子をつけて変数を可変にする方法が示されています: ```rust let foo = 5; // immutable @@ -263,7 +263,7 @@ let mut bar = 5; // mutable さあ、`let mut guess`が`guess`という名前の可変変数を導入するとわかりましたね。 -イコール記号(`=`)の逆側には、変数`guess`が束縛される値があります。この値は、今回の場合、 +イコール記号(`=`)の逆側には、変数`guess`が束縛される値があります。この値は、 `String::new`関数の呼び出し結果であり、この関数は、`String`型のオブジェクトを返します。 [`String`][string]型は、標準ライブラリによって提供される文字列型で、 サイズ可変、UTF-8エンコードされたテキスト破片になります。 @@ -275,8 +275,8 @@ let mut bar = 5; // mutable -`::new`行にある`::`という記法は、`new`が`String`型の*関連付け関数*であることを表しています。 -関連付け関数とは、`String`型の特定のオブジェクトよりも型(この場合は`String`)に対して +`::new`行にある`::`という記法は、`new`が`String`型の*関連関数*であることを表しています。 +関連関数とは、`String`型の特定のオブジェクトよりも型(この場合は`String`)に対して 実装された関数のことであり、*静的メソッド*と呼ばれる言語もあります。 @@ -321,8 +321,8 @@ io::stdin().read_line(&mut guess) その次のコード破片、`.read_line(&mut guess)`は、標準入力ハンドルの[`read_line`][read_line] -メソッドを呼び出して、ユーザから入力を受け付けます。また、`read_line`メソッドに対して、引数を一つ渡していますね: `&mut -guess`. +メソッドを呼び出して、ユーザから入力を受け付けます。また、`read_line`メソッドに対して、引数を一つ渡していますね: +`&mut guess`です. [read_line]: ../../std/io/struct.Stdin.html#method.read_line @@ -366,7 +366,7 @@ guess`. -`.foo()`という記法で、メソッドを呼び出す時、改行と空白で長い行を分割するのは賢いことです。 +`.foo()`という記法で、メソッドを呼び出す時、改行と空白で長い行を分割するのは賢明なことです。 今回の場合、こう書くこともできますよね: ```rust,ignore @@ -390,8 +390,8 @@ io::stdin().read_line(&mut guess).expect("Failed to read line"); 以前にも述べたように、`read_line`メソッドは、渡された文字列にユーザが入力したものを入れ込むだけでなく、 -値も返します(今回は[`io::Result`][ioresult]です)。 Rustには`Result`と名のついた型が -標準ライブラリにたくさんあります: ジェネリクスバージョンの[`Result`][result]の他、 +値も返します(今回は[`io::Result`][ioresult]です)。 Rustには、 +`Result`と名のついた型が標準ライブラリにたくさんあります: ジェネリクスバージョンの[`Result`][result]の他、 サブモジュール用の`io::Result`などの特別版まで。 [ioresult]: ../../std/io/type.Result.html @@ -414,7 +414,7 @@ enumについては、第6章で詳しく解説します。 `Result`型に関しては、取りうる型の値(variant)は`Ok`か`Err`です。値`Ok`は、処理が成功したことを表し、 -中に生成された値を保持します。`Err`は、処理が失敗したことを意味し、`Err`は、処理が失敗した過程や、 +中に生成された値を保持します。`Err`は、処理が失敗したことを意味し、処理が失敗した過程や、 理由などの情報を含有します。 @@ -429,14 +429,13 @@ enumについては、第6章で詳しく解説します。 -これら`Result`型の目的は、エラー処理の情報をエンコードすることです。`Result`型の値も、他の型同様、 -メソッドが定義されています。`io::Result`オブジェクトには、呼び出し可能な -[`expect`メソッド][expect]があります。 -この`io::Result`オブジェクトが`Err`値の場合、`expect`メソッドはプロラグムをクラッシュさせ、 +これら`Result`型の目的は、エラー処理の情報をコード化することです。`Result`型の値も、他の型同様、 +メソッドが定義されています。`io::Result`オブジェクトには、呼び出し可能な[`expect`メソッド][expect]があります。 +この`io::Result`オブジェクトが`Err`値の場合、`expect`メソッドはプログラムをクラッシュさせ、 引数として渡されたメッセージを表示します。`read_line`メソッドが`Err`を返したら、 根底にあるOSによるエラーに起因する可能性が高くなります。 -この`io::Result`オブジェクトが`Ok`値の場合、`expect`メソッドは、`Ok`バリアントが保持する -返り値を取り出して、ただその値を返すので、これを使用することができるかもしれません。 +この`io::Result`オブジェクトが`Ok`値の場合、`expect`メソッドは、 +`Ok`バリアントが保持する返り値を取り出して、ただその値を返すので、これを使用することができるかもしれません。 今回の場合、その返り値とは、ユーザが標準入力に入力したバイト数になります。 [expect]: ../../std/result/enum.Result.html#method.expect @@ -462,9 +461,9 @@ src/main.rs:10 io::stdin().read_line(&mut guess); コンパイラは、私たちが`read_line`メソッドから返ってきた`Result`値を使用していないと警告してきており、 -これは、プログラムがエラーの可能性に対処していないことを示します。警告を抑制する正しい手段は、実際にエラー対処 -コードを書くことですが、今は、問題が起きた時にプロラグムをただ単にクラッシュさせたいので、`expect`を使用できるわけです。 -エラーから復旧する方法については、第9章で学ぶでしょう。 +これは、プログラムがエラーの可能性に対処していないことを示します。警告を抑制する正しい手段は、 +実際にエラー対処コードを書くことですが、今は、問題が起きた時にプロラグムをただ単にクラッシュさせたいので、 +`expect`を使用できるわけです。エラーから復旧する方法については、第9章で学ぶでしょう。 @@ -486,8 +485,8 @@ println!("You guessed: {}", guess); この行は、ユーザ入力を保存した文字列の中身を出力します。1組の`{}`は、値を保持しておくプレースホルダーの役目を果たします。 -`{}`記法を使って一つ以上の値を出力できます: 最初の`{}`の組は、フォーマット文字列の後に列挙された最初の値に対応し、 -2組目は、2つ目の値、とそんな感じで続いていきます。1回の`println!`マクロの呼び出しで複数値を出力するコードは、 +`{}`を使って一つ以上の値を出力できます: 最初の`{}`の組は、フォーマット文字列の後に列挙された最初の値に対応し、 +2組目は、2つ目の値、とそんな感じで続いていきます。1回の`println!`の呼び出しで複数値を出力するコードは、 以下のような感じになります: ```rust @@ -508,7 +507,7 @@ println!("x = {} and y = {}", x, y); -数当てゲームの最初の部分をテストしてみましょう。`cargo run`コマンドでプログラムを走らせることができます: +数当てゲームの最初の部分をテストしてみましょう。`cargo run`でプログラムを走らせることができます: ```text $ cargo run @@ -537,8 +536,8 @@ You guessed(次のように予想したよ): 6 次に、ユーザが数当てに挑戦する秘密の数字を生成する必要があります。毎回この秘密の数字は、変わるべきです。 ゲームが何回も楽しめるようにですね。ゲームが難しくなりすぎないように、1から100までの乱数を使用しましょう。 -Rustの標準ライブラリには、乱数機能はまだ含まれていません。ですが、Rustチームが[`rand`クレート][randcrate]を -用意してくれています。 +Rustの標準ライブラリには、乱数機能はまだ含まれていません。ですが、 +Rustチームが[`rand`クレート][randcrate]を用意してくれています。 [randcrate]: https://crates.io/crates/rand @@ -552,7 +551,7 @@ Rustの標準ライブラリには、乱数機能はまだ含まれていませ *クレート*はRustコードのパッケージであることを思い出してください。私たちがここまで作ってきたプロジェクトは、 *バイナリークレート*であり、これは実行可能形式になります。`rand`クレートは*ライブラリクレート*であり、 -他のプロラグムで使用する用のコードが含まれています。 +他のプログラムで使用する用のコードが含まれています。 @@ -560,9 +559,9 @@ Rustの標準ライブラリには、乱数機能はまだ含まれていませ -Cargoを使って外部クレートを使用すると、Cargoがとても輝きます。`rand`を使ったコードを書くためには、 +Cargoを使って外部クレートを使用すると、Cargoがとても輝きます。`rand`を使ったコードを書く前に、 *Cargo.toml*ファイルを編集して、`rand`クレートを依存ファイルとして取り込む必要があります。 -このファイルを開いて、以下の行をCargoが自動生成した`[dependencies]`セクションヘッダーの一番下に追記しましょう: +今このファイルを開いて、以下の行をCargoが自動生成した`[dependencies]`セクションヘッダーの一番下に追記しましょう: @@ -588,8 +587,8 @@ rand = "0.3.14" `[dependecies]`セクションは、プロジェクトが依存する外部クレートと必要とするバージョンを記述するところです。 今は、`rand`クレートで、意味論的バージョンには`0.3.14`を指定します。Cargoは[意味論的バージョン付け][semver] (時に*SemVer*と呼ばれる)を理解し、 意味論的バージョン付けは、バージョンナンバー記述の標準規格です。 -`0.3.14`という数字は、実際には`^0.3.14`の省略記法で、これは、「バージョン0.3.14と互換性のある公開APIを持つ -バージョンならなんでも」を意味します。 +`0.3.14`という数字は、実際には`^0.3.14`の省略記法で、これは、 +「バージョン0.3.14と互換性のある公開APIを持つバージョンならなんでも」という意味です。 [semver]: http://semver.org @@ -624,8 +623,8 @@ $ cargo build -今や、外部依存ファイルを持つようになったので、Cargoは*registry*(登録所)から最新バージョンを拾ってきます。 -*レジストリ*とは、[Crates.io][cratesio]のデータのコピーです. Crates.ioとは、Rustのエコシステムにいる人間が +今や、外部依存ファイルが存在するようになったので、Cargoは*registry*(登録所)から最新バージョンを拾ってきます。 +*レジストリ*とは、[Crates.io][cratesio]のデータのコピーです. Crates.ioとは、Rustのエコシステムにいる人間が、 他の人も使えるように自分のオープンソースのRustプロジェクトを投稿する場所です。 [cratesio]: https://crates.io @@ -650,9 +649,10 @@ $ cargo build 何も変更せず即座に`cargo build`コマンドを走らせたら、何も出力されないでしょう。 -Cargoは、すでに依存ファイルをダウンロードしてコンパイル済みであることを検知し、プログラマが -*Cargo.toml*ファイルを弄ってないからです。さらに、Cargoはプログラマがコードを変更していないことも -検知するので、再度コンパイルすることもありません。することがないので、ただ単に終了します。 +すでに依存ファイルをダウンロードしてコンパイル済みであることと、 +プログラマが*Cargo.toml*ファイルを弄ってないことをCargoが知っています。さらに、 +Cargoはプログラマがコードを変更していないことも検知するので、再度コンパイルすることもありません。 +することがないので、ただ単に終了します。 *src/main.rs*ファイルを開き、些細な変更をし、保存して再度ビルドを行えば、1行だけ出力があるでしょう: ```text @@ -666,8 +666,8 @@ $ cargo build この行は、Cargoが*src/main.rs*ファイルへの取るに足らない変更に対してビルドを更新していることを示しています。 -依存ファイルは変更していないので、Cargoは、すでにダウンロードし、コンパイル済みの依存ファイルを使用できると -検知します。自分で書いたコードのみ再ビルドをかけるわけです。 +依存ファイルは変更していないので、Cargoは、すでにダウンロードし、コンパイル済みの依存ファイルを使用できると検知します。 +自分で書いたコードのみ再ビルドをかけるわけです。 @@ -680,8 +680,8 @@ $ cargo build -Cargoには、プログラマが自分のコードを更新するたびに同じ生成物を再構成することを保証してくれるメカニズムを -備えています: Cargoは、プログラマが明示するまで、指定したバージョンの依存ファイルのみを使用してくれるでしょう。 +Cargoには、プログラマが自分のコードを構成するたびに同じ生成物を再構成することを保証してくれる機構を備えています: +Cargoは、プログラマが明示するまで、指定したバージョンの依存ファイルのみを使用してくれるでしょう。 例として、`rand`クレートの次週のバージョン`v0.3.15`が登場し、重要なバグ修正がなされているけれども、 自分のコードを破壊してしまう互換性破壊があった場合はどうなるでしょう? @@ -696,10 +696,10 @@ Cargoには、プログラマが自分のコードを更新するたびに同じ -この問題に対する回答は、*Cargo.lock*ファイルであり、このファイルは、初めて`cargo build`コマンドを -走らせた時に生成され、*guessing_game*ディレクトリに存在しています。プロジェクトを始めてビルドする際に、 +この問題に対する回答は、*Cargo.lock*ファイルであり、このファイルは、初めて`cargo build`コマンドを走らせた時に生成され、 +今は*guessing_game*ディレクトリに存在しています。プロジェクトを初めてビルドする際に、 Cargoは判断基準(criteria)に合致する依存ファイルのバージョンを割り出し、*Cargo.lock*ファイルに記述します。 -次にプロジェクトをビルドする際には、Cargoは*Cargo.lock*ファイルが存在することを確かめ、 +将来プロジェクトをビルドする際には、Cargoは*Cargo.lock*ファイルが存在することを確かめ、 再度バージョン割り出しの作業を行うのではなく、そこに指定されているバージョンを使用するでしょう。 このことにより、自動的に再生成可能なビルドを構成できるのです。つまり、明示的にアップグレードしない限り、 プロジェクトが使用するバージョンは`0.3.14`に保たれるのです。*Cargo.lock*ファイルのおかげでね。 @@ -724,9 +724,9 @@ Cargoは判断基準(criteria)に合致する依存ファイルのバージョ -しかし標準でCargoは、`0.3.0`以上、`0.4.0`未満のバージョンのみを検索します。`rand`クレートの新バージョンが -2つリリースされていたら(`0.3.15`と`0.4.0`ですね)、`cargo update`コマンドを走らせた時に以下のような -メッセージを目の当たりにするでしょう: +しかし標準でCargoは、`0.3.0`以上、`0.4.0`未満のバージョンのみを検索します。 +`rand`クレートの新バージョンが2つリリースされていたら(`0.3.15`と`0.4.0`ですね)、 +`cargo update`コマンドを走らせた時に以下のようなメッセージを目の当たりにするでしょう: ```text $ cargo update @@ -769,10 +769,10 @@ rand = "0.4.0" -まだ第14章で議論する[Cargo][doccargo]と[そのエコシステム][doccratesio] -については述べたいことが山ほどありますが、とりあえずは、これで知っておくべきことは全てです。 -Cargoのおかげでライブラリはとても簡単に再利用ができるので、Rust市民(Rustaceans)は数多くのパッケージから -構成された小規模のプロジェクトを書くことができるのです。 +まだ第14章で議論する[Cargo][doccargo]と[そのエコシステム][doccratesio]については、 +述べたいことが山ほどありますが、とりあえずは、これで知っておくべきことは全てです。 +Cargoのおかげでライブラリはとても簡単に再利用ができるので、 +Rust市民(Rustaceans)は数多くのパッケージから構成された小規模のプロジェクトを書くことができるのです。 [doccargo]: http://doc.crates.io [doccratesio]: http://doc.crates.io/crates-io.html @@ -825,15 +825,15 @@ fn main() { 冒頭に`extern crate rand;`行を追加して、コンパイラにこの外部依存ファイルを使用することを知らせています。 -これにより、`use rand`を呼ぶのと同じ効果が得られるので、`rand`クレートのものを`rand::` -という接頭辞をつけて呼び出せるようになりました。 +これにより、`use rand`を呼ぶのと同じ効果が得られるので、 +`rand`クレートのものを`rand::`という接頭辞をつけて呼び出せるようになりました。 -次に、別の`use`行を追加しています: `use rand::Rng`ですね。`Rng`とは乱数生成器が実装するメソッドを定義した -トレイトであり、このトレイトがスコープにないと、メソッドを使用できないのです。トレイトについて詳しくは、 +次に、別の`use`行を追加しています: `use rand::Rng`ですね。`Rng`とは乱数生成器が実装するメソッドを定義したトレイトであり、 +このトレイトがスコープにないと、メソッドを使用できないのです。トレイトについて詳しくは、 第10章を解説します。 @@ -846,12 +846,12 @@ fn main() { -また、途中に2行追加もしています。`rand::thread_rng`関数は、私たちが使う特定の乱数生成器を -返してくれます: この乱数生成器は、実行スレッドに特有で、OSにより、シード値を与えられています。 -次に、この乱数生成器の`gen_range`メソッドを呼び出しています。このメソッドは、`use rand::Rng`文で -スコープに導入した`Rng`トレイトで定義されています。`gen_range`メソッドは二つの数字を引数に取り、 -それらの間の乱数を生成してくれます。最低値は含むものの、最高値は含まないため、`1`と`101`と指定しないと -1から100の範囲の数字は得られません。 +また、途中に2行追加もしています。`rand::thread_rng`関数は、私たちが使う特定の乱数生成器を返してくれます: +この乱数生成器は、実行スレッドに特有で、OSにより、シード値を与えられています。 +次に、この乱数生成器の`gen_range`メソッドを呼び出しています。このメソッドは、 +`use rand::Rng`文でスコープに導入した`Rng`トレイトで定義されています。`gen_range`メソッドは二つの数字を引数に取り、 +それらの間の乱数を生成してくれます。最低値は含むものの、最高値は含まないため、 +`1`と`101`と指定しないと1から100の範囲の数字は得られません。 @@ -862,10 +862,10 @@ fn main() { 使用すべきトレイトとクレートから呼び出すべき関数とメソッドを知ることが、単純に*知っている*ことではないでしょう。 -クレートの使用方法は、各クレートのドキュメントにある。Cargoの別の巧妙な機能は、`cargo doc --open`コマンドを -走らせてローカルに存在する依存ファィルすべてのドキュメントをビルドし、Webブラウザで閲覧できる機能です。例えば、 -`rand`クレートの他の機能に興味があるなら、`cargo doc --open`コマンドを走らせて、左側のサイドバーから -`rand`をクリックすればいいわけです。 +クレートの使用方法は、各クレートのドキュメントにあります。Cargoの別の巧妙な機能は、 +`cargo doc --open`コマンドを走らせてローカルに存在する依存ファィルすべてのドキュメントをビルドし、Webブラウザで閲覧できる機能です。 +例えば、`rand`クレートの他の機能に興味があるなら、`cargo doc --open`コマンドを走らせて、 +左側のサイドバーから`rand`をクリックすればいいわけです。 @@ -958,8 +958,8 @@ fn main() { -最初の新しい点は、別の`use`文です。これで、`std::cmp::Ordering`という型を標準ライブラリから -スコープに導入しています。`Ordering`もenumです。`Result`のようにね。ただ、`Ordering`が取りうる値は、 +最初の新しい点は、別の`use`文です。`std::cmp::Ordering`という型を標準ライブラリからスコープに導入しています。 +`Ordering`もenumです。`Result`のようにね。ただ、`Ordering`が取りうる値は、 `Less`、`Greater`そして、`Equal`です。これらは、2値比較した時に発生しうる3種類の結果です。 @@ -985,8 +985,8 @@ match guess.cmp(&secret_number) { `cmp`メソッドは、2値を比較し、比較できるものに対してならなんに対しても呼び出せます。このメソッドは、 比較したいものへの参照を取ります: ここでは、`guess`変数と`secret_number`変数を比較しています。 `cmp`メソッドは`use`文でスコープに導入した`Ordering`列挙型の値を返します。 -[`match`][match]式を使用して、`guess`変数と`secret_number`を`cmp`に渡して -返ってきた`Ordering`の値に基づき、次の動作を決定しています。 +[`match`][match]式を使用して、`guess`変数と`secret_number`を`cmp`に渡して返ってきた`Ordering`の値に基づき、 +次の動作を決定しています。 [match]: ch06-02-match.html @@ -998,11 +998,11 @@ match guess.cmp(&secret_number) { -`match`式は、複数の*アーム*(腕)からできています。一つのアームは、パターンとそのパターンに -`match`式の冒頭で与えた値がマッチした時に走るコードから構成されています。Rustは、`match`に与えられた -値を取り、各アームのパターンを順番に吟味していきます。`match`式とパターンは、コードを書く際に -目の当たりにする様々なシチュエーションを表現させてくれ、すべてのシチュエーションに対処する手助けをしてくれる -Rustの強力な機能です。これらの機能は、それぞれ、第6章と第18章で詳しく解説することにします。 +`match`式は、複数の*アーム*(arm)からできています。一つのアームは、*パターン*とそのパターンに +`match`式の冒頭で与えた値がマッチした時に走るコードから構成されています。Rustは、`match`に与えられた値を取り、 +各アームのパターンを順番に吟味していきます。`match`式とパターンは、コードを書く際に目の当たりにする様々なシチュエーションを表現させてくれ、 +すべてのシチュエーションに対処する手助けをしてくれるRustの強力な機能です。 +これらの機能は、それぞれ、第6章と第18章で詳しく解説することにします。 @@ -1060,7 +1060,7 @@ Could not compile `guessing_game`. (`guessing_game`をコンパイルでき このエラーの核は、*型の不一致*があると言っています。Rustは、強力な静的型付けシステムを持っています。 しかし、型推論にも対応しています。`let guess = String::new()`と書いた時、コンパイラは、 `guess`が`String`型であるべきと推論してくれ、その型を明示させられることはありませんでした。 -一方で、`secret_number`変数は、数値型です。少数の数値型しか1から100を表すことはできません: +一方で、`secret_number`は、数値型です。少数の数値型しか1から100を表すことはできません: `i32`は32ビットの数字; `u32`は32ビットの非負数字; `i64`は64ビットの数字;などです。 Rustでの標準は、`i32`型であり、型情報をどこかに追加して、コンパイラに異なる数値型だと推論させない限り、 `secret_number`の型はこれになります。エラーの原因は、Rustでは、文字列と数値型を比較できないことです。 @@ -1069,8 +1069,8 @@ Rustでの標準は、`i32`型であり、型情報をどこかに追加して -究極的には、プログラムが入力として読み込む`String`型を現実の数値型に変換し、予想と数値として比較できるように -したいわけです。これは、以下の2行を`main`関数の本体に追記することでできます: +究極的には、プログラムが入力として読み込む`String`型を現実の数値型に変換し、 +予想と数値として比較できるようにしたいわけです。これは、以下の2行を`main`関数の本体に追記することでできます: @@ -1112,7 +1112,7 @@ fn main() { -その2行とは以下のようなものです: +その2行とは: ```rust,ignore let guess: u32 = guess.trim().parse() @@ -1127,11 +1127,11 @@ let guess: u32 = guess.trim().parse() -`guess`という名前の変数を生成しています。あれ、でも待って。もうプログラムには`guess`という名前の変数が -ありませんでしたっけ?確かにありますが、Rustでは、新しい値で`guess`の値を*多重定義*(shadow)することが -許されているのです。この機能は、今回のような、値を別の型に変換したいシチュエーションでよく使われます。 -多重定義のおかげで別々の変数を2つ作らされることなく、`guess`という変数名を再利用することができるのです。 -`guess_str`と`guess`みたいなね(多重定義については、第3章でもっと掘り下げます)。 +`guess`という名前の変数を生成しています。あれ、でも待って。もうプログラムには`guess`という名前の変数がありませんでしたっけ? +確かにありますが、Rustでは、新しい値で`guess`の値を*上書き*(shadow)することが許されているのです。 +この機能は、今回のような、値を別の型に変換したいシチュエーションでよく使われます。 +上書きのおかげで別々の変数を2つ作らされることなく、`guess`という変数名を再利用することができるのです。 +`guess_str`と`guess`みたいなね(上書きについては、第3章でもっと掘り下げます)。 @@ -1151,8 +1151,8 @@ let guess: u32 = guess.trim().parse() `read_line`の処理を終えるためにリターンキーを押さなければなりません。 ユーザがリターンキーを押したら、改行文字が文字列に追加されます。 具体例として、ユーザが5を入力して、 -リターンキーを押せば、`guess`変数は次のようになります: `5\n`。 -この`\n`が改行、つまりリターンキーを表しているわけです。 +リターンキーを押せば、`guess`は次のようになります: `5\n`。 +この`\n`が「改行」、つまりリターンキーを表しているわけです。 `trim`メソッドは、`\n`を削除するので、ただの`5`になります。 @@ -1189,9 +1189,9 @@ Rustには、組み込みの数値型がいくつかあります; ここで見 `parse`メソッドの呼び出しは、エラーになりやすいです。例としては、文字列が`A👍%`を含んでいたら、 -数値に変換できるわけがないわけです。失敗する可能性があるので、`parse`メソッドは、`Result`型を -返すわけです。ちょうど、「Result型で失敗する可能性に対処する」節で先ほど議論した`read_line`メソッドが -するようにというわけですね。今回も、`expect`メソッドを使用して`Result`型を同じように扱います。 +数値に変換できるわけがありません。失敗する可能性があるので、`parse`メソッドは、 +`Result`型を返すわけです。ちょうど、「Result型で失敗する可能性に対処する」節で先ほど議論した`read_line`メソッドがするようにというわけですね。 +今回も、`expect`メソッドを使用して`Result`型を同じように扱います。 もし、文字列から数値を生成できなかったために、`parse`メソッドが`Result`型の`Err`値を返したら、 `expect`メソッドの呼び出しは、ゲームをクラッシュさせ、与えたメッセージを表示します。 もし、`parse`メソッドが文字列の数値への変換に成功したら、`Result`型の`Ok`値を返し、 @@ -1218,8 +1218,8 @@ Too big! -いいですね!予想の前にスペースを追加したにもかかわらず、プログラムはちゃんとユーザが76と予想したことを -導き出しました。プログラムを何回か走らせて、異なる入力の異なる振る舞いを確認してください: つまり、 +いいですね!予想の前にスペースを追加したにもかかわらず、プログラムはちゃんとユーザが76と予想したことを導き出しました。 +プログラムを何回か走らせて、異なる入力の異なる振る舞いを確認してください: つまり、 数字を正しく言い当てたり、大きすぎる値を予想したり、低すぎる数字を入力したりということです。 @@ -1389,8 +1389,8 @@ fn main() { -`break`文の1行を`You win!`の後に追記することで、ユーザが秘密の数字を正確に予想したら、プログラムは -ループを抜けるようになりました。ついでに、ループを抜けることは、プログラムを終了することを意味します。 +`break`文の1行を`You win!`の後に追記することで、ユーザが秘密の数字を正確に予想したら、 +プログラムはループを抜けるようになりました。ついでに、ループを抜けることは、プログラムを終了することを意味します。 ループが`main`関数の最後の部分だからですね。 @@ -1403,8 +1403,8 @@ fn main() { さらにゲームの振る舞いを改善するために、ユーザが数値以外を入力した時にプログラムをクラッシュさせるのではなく、 -非数値を無視してユーザが数当てを続けられるようにしましょう!これは、`guess`が`String`型から -`u32`方に変換される行を改変することで達成できます: +非数値を無視してユーザが数当てを続けられるようにしましょう!これは、 +`guess`が`String`型から`u32`型に変換される行を改変することで達成できます: ```rust,ignore let guess: u32 = match guess.trim().parse() { @@ -1419,9 +1419,9 @@ let guess: u32 = match guess.trim().parse() { -`expect`メソッドの呼び出しから`match`式に切り替えることは、エラーでクラッシュする動作から -実際にエラー処理を行う処理へ変更する一般的な手段になります。`parse`メソッドは、`Result`型を -返し、`Result`は`Ok`か`Err`の値を取りうるenumであることを思い出してください。 +`expect`メソッドの呼び出しから`match`式に切り替えることは、 +エラーでクラッシュする動作から実際にエラー処理を行う処理へ変更する一般的な手段になります。`parse`メソッドは、 +`Result`型を返し、`Result`は`Ok`か`Err`の値を取りうるenumであることを思い出してください。 ここでは`match`式を使っています。`cmp`メソッドの`Ordering`という結果でしたのと同じですね。 @@ -1432,8 +1432,7 @@ let guess: u32 = match guess.trim().parse() { `parse`メソッドは、文字列から数値への変換に成功したら、結果の数値を保持する`Ok`値を返します。 この`Ok`値は、最初のアームのパターンにマッチし、この`match`式は`parse`メソッドが生成し、 -`Ok`値に格納した`num`の値を返すだけです。その数値が最終的に生成した新しい`guess`変数に -含まれます。 +`Ok`値に格納した`num`の値を返すだけです。その数値が最終的に生成した新しい`guess`変数に含まれます。 @@ -1445,18 +1444,18 @@ let guess: u32 = match guess.trim().parse() { -`parse`メソッドは、文字列から数値への変換に*失敗*したら、エラーに関する情報を多く含む`Err`値を -返します。この`Err`値は、最初の`match`アームの`Ok(num)`というパターンにはマッチしないものの、 +`parse`メソッドは、文字列から数値への変換に*失敗*したら、エラーに関する情報を多く含む`Err`値を返します。 +この`Err`値は、最初の`match`アームの`Ok(num)`というパターンにはマッチしないものの、 2番目のアームの`Err(_)`というパターンにはマッチするわけです。この`_`は、包括値です; この例では、 保持している情報がどんなものでもいいから全ての`Err`値にマッチさせたいと宣言しています。 -従って、プログラムは2番目のアームのコードを実行し(`continue`ですね)、これは、`loop`の -次の段階に移り、再度予想入力を求めることを意味します。故に実効的には、プログラムは`parse`メソッドが -遭遇しうる全てのエラーを無視するようになります! +従って、プログラムは2番目のアームのコードを実行し(`continue`ですね)、これは、 +`loop`の次の段階に移り、再度予想入力を求めることを意味します。故に実効的には、 +プログラムは`parse`メソッドが遭遇しうる全てのエラーを無視するようになります! -さて、プログラムの全てがうまく予想通りに動くはずです。`cargo run`コマンドで走らせて、試してみましょう: +さて、プログラムの全てがうまく予想通りに動くはずです。`cargo run`を走らせて、試してみましょう: ```text $ cargo run @@ -1485,9 +1484,9 @@ You win! -素晴らしい!最後にひとつまみ変更を加えて、数当てゲームを完了にしましょう: プログラムが未だに -秘密の数字を出力していることを思い出してください。テスト中はうまく動くけど、 -ゲームを台無しにしてしまいます。秘密の数字を出力する`println!`マクロを削除しましょう。 +素晴らしい!最後にひとつまみ変更を加えて、数当てゲームを完了にしましょう: + プログラムが未だに秘密の数字を出力していることを思い出してください。テスト中はうまく動くけど、 +ゲームを台無しにしてしまいます。秘密の数字を出力する`println!`を削除しましょう。 リスト2-5が成果物のコードです: From b4e70d8483eed7416e6288abe0afa3c1ae69d561 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 19 Sep 2017 19:59:40 +0900 Subject: [PATCH 047/428] Fix some errors in the chapters 3-1 and 3-2 --- second-edition/src/ch03-01-variables-and-mutability.md | 2 +- second-edition/src/ch03-02-data-types.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/second-edition/src/ch03-01-variables-and-mutability.md b/second-edition/src/ch03-01-variables-and-mutability.md index e6b777453..b4266f73f 100644 --- a/second-edition/src/ch03-01-variables-and-mutability.md +++ b/second-edition/src/ch03-01-variables-and-mutability.md @@ -165,7 +165,7 @@ The value of x is: 6 変数の値を変更できないようにするといえば、他の多くの言語も持っている別のプログラミング概念を思い浮かべるかもしれません: -*定数*です. 不変変数のように、定数も名前に紐付き、変更することが叶わない値のことですが、 +*定数*です。不変変数のように、定数も名前に紐付き、変更することが叶わない値のことですが、 定数と変数の間にはいくつかの違いがあります。 diff --git a/second-edition/src/ch03-02-data-types.md b/second-edition/src/ch03-02-data-types.md index 1cdbd73a9..72bd17352 100644 --- a/second-edition/src/ch03-02-data-types.md +++ b/second-edition/src/ch03-02-data-types.md @@ -173,7 +173,7 @@ Rustでの動作方法について見ていきましょう。 では、どの整数型を使うべきかはどう把握すればいいのでしょうか?もし確信が持てないのならば、 -Rustの基準型は一般的にいい選択になります。整数型の基準は`i32`型です: 64ビットシステム上でも、 +Rustの基準型は一般的にいい選択肢になります。整数型の基準は`i32`型です: 64ビットシステム上でも、 普通最速になります。`isize`と`usize`を使う主な状況は、何らかのコレクションにアクセスすることです。 From c91e5146c1952b187933564c841ce00ec0dd270c Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 19 Sep 2017 20:09:59 +0900 Subject: [PATCH 048/428] Fix another error in the chapter 3-2 --- second-edition/src/ch03-02-data-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch03-02-data-types.md b/second-edition/src/ch03-02-data-types.md index 72bd17352..b14f7c228 100644 --- a/second-edition/src/ch03-02-data-types.md +++ b/second-edition/src/ch03-02-data-types.md @@ -399,7 +399,7 @@ fn main() { 変数`tup`は、タプル全体に束縛されています。なぜなら、タプルは、一つの複合要素と考えられるからです。 -タプルから個々の値を取り出すには、パターンマッチングにより分解を使用することができます。以下のように: +タプルから個々の値を取り出すには、パターンマッチングを使用して分解することができます。以下のように: From 8fc32c4d437c7e0f929c225f1041967279000c6c Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 19 Sep 2017 20:12:01 +0900 Subject: [PATCH 049/428] Fix another error in the chapter 3-2 again --- second-edition/src/ch03-02-data-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch03-02-data-types.md b/second-edition/src/ch03-02-data-types.md index b14f7c228..0218bba53 100644 --- a/second-edition/src/ch03-02-data-types.md +++ b/second-edition/src/ch03-02-data-types.md @@ -466,7 +466,7 @@ fn main() { *配列*によっても、複数の値のコレクションを得ることができます。タプルと異なり、配列の全要素は、 -同じ型でなければなりません。Rustの配列は、他の言語と異なっている場合があります。Rustの配列は、 +同じ型でなければなりません。Rustの配列は、他の言語と異なっています。Rustの配列は、 固定長なのです: 一度宣言されたら、サイズを伸ばすことも縮めることもできません。 From 052727e9bf088c002e99edb5113b1356e496fdf7 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 20 Sep 2017 19:24:33 +0900 Subject: [PATCH 050/428] Change some word choices for parts of texts and revise the content in the Chapter 4 so that the resulting html would not contain unnecessary whitespaces between words --- .../src/ch04-01-what-is-ownership.md | 208 +++++++++--------- .../src/ch04-02-references-and-borrowing.md | 10 +- second-edition/src/ch04-03-slices.md | 6 +- 3 files changed, 110 insertions(+), 114 deletions(-) diff --git a/second-edition/src/ch04-01-what-is-ownership.md b/second-edition/src/ch04-01-what-is-ownership.md index 56cc028f5..e016b5a8e 100644 --- a/second-edition/src/ch04-01-what-is-ownership.md +++ b/second-edition/src/ch04-01-what-is-ownership.md @@ -4,7 +4,7 @@ -Rustの中心的な機能は、*所有権*です。機能は説明するのに実直なのですが、言語の残りの機能全てにかかるほど +Rustの中心的な機能は、*所有権*です。機能は説明するのに単純なのですが、言語の残りの機能全てにかかるほど 深い裏の意味を含んでいるのです。 @@ -18,15 +18,15 @@ Rustの中心的な機能は、*所有権*です。機能は説明するのに 定期的に使用されていないメモリを検索するガベージコレクションを持つ言語もありますが、他の言語では、 プログラマが明示的にメモリを確保したり、解放したりしなければなりません。Rustでは第3の選択肢を取っています: メモリは、コンパイラがコンパイル時にチェックする一定の規則とともに所有権システムを通じて管理されています。 -実行コストを、所有権機能に負担することはありません。 +実行コストを、所有権機能のために負担することはありません。 -所有権は多くのプログラマにとって新しい概念なので、慣れるまでに時間がかかります。Rustと -所有権システムの経験を積むにつれて、自然に安全かつ効率的なコードを構築できるようになることは、 +所有権は多くのプログラマにとって新しい概念なので、慣れるまでに時間がかかります。 +Rustと所有権システムの経験を積むにつれて、自然に安全かつ効率的なコードを構築できるようになることは、 素晴らしいお知らせです。その調子でいきましょう! @@ -109,15 +109,15 @@ Rustの中心的な機能は、*所有権*です。機能は説明するのに > この章の後半でスタックとヒープを絡めて所有権について解説するので、ここでちょっと予行演習をしておきましょう。 > > スタックもヒープも、実行時にコードが使用できるメモリの一部になりますが、異なる手段で構成されています。 -> スタックは、得た順番に値を並べ、逆の順で値を取り除いていきます。これは、*last in, first out* -> (あえて日本語にするなら、けつ入れ頭出しといったところでしょうか)と呼ばれます。お皿の山を思い浮かべてください: -> お皿を追加する時には、山の一番上に置き、お皿が必要になったら、一番上から1枚を取り去りますよね。 +> スタックは、得た順番に値を並べ、逆の順で値を取り除いていきます。これは、 +> *last in, first out*(`脚注`: あえて日本語にするなら、けつ入れ頭出しといったところでしょうか)と呼ばれます。 +> お皿の山を思い浮かべてください: お皿を追加する時には、山の一番上に置き、お皿が必要になったら、一番上から1枚を取り去りますよね。 > 途中や一番下に追加したり、取り除いたりすることは同じようにはできません。データを追加することは、 -> *スタックにpushする*といい、データを取り除くことは、*スタックからpopする*と表現します(`脚注`: これらの動作に対する -> 画一的な日本語訳を見かけたことはありません)。 +> *スタックにpushする*といい、データを取り除くことは、*スタックからpopする*と表現します(`脚注`: +> これらの動作に対する画一的な日本語訳を見かけたことはありません)。 > -> データへのアクセス方法のおかげで、スタックは高速です: 新データを置いたり、データを取得する場所を -> 探す必要が絶対にないわけです。というのも、その場所は常に一番上だからですね。スタックを高速にする要素は、 +> データへのアクセス方法のおかげで、スタックは高速です: 新データを置いたり、 +> データを取得する場所を探す必要が絶対にないわけです。というのも、その場所は常に一番上だからですね。スタックを高速にする特性は、 > 他にもあり、それはスタック上のデータは全て既知の固定サイズにならなければならないということです。 > > コンパイル時にサイズがわからなかったり、サイズが可変のデータについては、代わりにヒープに格納することができます。 @@ -125,24 +125,24 @@ Rustの中心的な機能は、*所有権*です。機能は説明するのに > OSはヒープ上に十分な大きさの空の領域を見つけ、使用中にし、その場所へのポインタを返してきます。 > この過程は、*ヒープに領域を確保する*と呼ばれ、時としてそのフレーズを単に*allocateする*などと省略したりします。 > (`脚注`: こちらもこなれた日本語訳はないでしょう。allocateはメモリを確保すると訳したいところですが) -> スタックに値を載せることは、メモリ確保とは考えられません。ポインタは、既知の固定サイズなので、スタックに -> 保管することができますが、実データが必要になったら、ポインタを追いかける必要があります。 +> スタックに値を載せることは、メモリ確保とは考えられません。ポインタは、既知の固定サイズなので、 +> スタックに保管することができますが、実データが必要になったら、ポインタを追いかける必要があります。 > -> レストランで席を確保することを考えましょう。入店したら、グループの人数を告げ、店員が全員座れる -> 空いている席を探し、そこまで誘導します。もしグループの誰かが遅れて来るのなら、着いた席の場所を尋ねて -> あなたを発見することができます。 +> レストランで席を確保することを考えましょう。入店したら、グループの人数を告げ、 +> 店員が全員座れる空いている席を探し、そこまで誘導します。もしグループの誰かが遅れて来るのなら、 +> 着いた席の場所を尋ねてあなたを発見することができます。 > -> ヒープへのデータアクセスは、スタックのデータへのアクセスよりも低速です。ポインタを追って目的の場所に -> 到達しなければならないからです。現代のプロセッサは、メモリをあちこち行き来しなければ、より速くなります。 -> 似た例えを続けましょう。レストランで多くのテーブルから注文を受ける給仕人を考えましょう。最も効率的なのは、 +> ヒープへのデータアクセスは、スタックのデータへのアクセスよりも低速です。 +> ポインタを追って目的の場所に到達しなければならないからです。現代のプロセッサは、メモリをあちこち行き来しなければ、 +> より速くなります。似た例えを続けましょう。レストランで多くのテーブルから注文を受ける給仕人を考えましょう。最も効率的なのは、 > 次のテーブルに移らずに、一つのテーブルで全部の注文を受け付けてしまうことです。テーブルAで注文を受け、 -> それからテーブルBの注文、さらにまたA、それからまたBと渡り歩くのは、かなり低速な過程になってしまいます。 -> 同じ意味で、プロセッサは、データが隔離されている(ヒープではそうなっている可能性がある)よりも近くにある -> (スタックではこうなる)ほうが、仕事をうまくこなせるのです。ヒープに大きな領域を確保する行為も時間が -> かかることがあります。 +> それからテーブルBの注文、さらにまたA、それからまたBと渡り歩くのは、かなり低速な過程になってしまうでしょう。 +> 同じ意味で、プロセッサは、 +> データが隔離されている(ヒープではそうなっている可能性がある)よりも近くにある(スタックではこうなる)ほうが、 +> 仕事をうまくこなせるのです。ヒープに大きな領域を確保する行為も時間がかかることがあります。 > -> コードが関数を呼び出すと、関数に渡された値(可能性として、ヒープのデータへのポインタも含めて)と関数の -> ローカル変数がスタックに載ります。関数の実行が終了すると、それらの値はスタックから取り除かれます。 +> コードが関数を呼び出すと、関数に渡された値(ヒープのデータへのポインタも含まれる可能性あり)と、 +> 関数のローカル変数がスタックに載ります。関数の実行が終了すると、それらの値はスタックから取り除かれます。 > > どの部分のコードがどのヒープ上のデータを使用しているか把握すること、ヒープ上の重複するデータを最小化すること、 > メモリ不足にならないようにヒープ上の未使用のデータを掃除することは全て、所有権が解決する問題です。 @@ -181,17 +181,17 @@ Rustの中心的な機能は、*所有権*です。機能は説明するのに -第2章で、Rustプログラムの例はすでに見ています。もう基本的な記法は通り過ぎたので、`fn main() {` -というコードはもう例に含みません。従って、例をなぞっているなら、これからの例は`main`関数に手動で -入れ込まなければいけなくなるでしょう。結果的に、例は少々簡潔になり、定型コードよりも -具体的な詳細に集中しやすくなります。 +第2章で、Rustプログラムの例はすでに見ています。もう基本的な記法は通り過ぎたので、 +`fn main() {`というコードはもう例に含みません。従って、例をなぞっているなら、 +これからの例は`main`関数に手動で入れ込まなければいけなくなるでしょう。結果的に、例は少々簡潔になり、 +定型コードよりも具体的な詳細に集中しやすくなります。 -所有権の最初の例として、何らかの変数の*スコープ*について見ていきましょう。スコープとは、要素が有効になる -プログラム内の範囲のことです。以下のような変数があるとしましょう: +所有権の最初の例として、何らかの変数の*スコープ*について見ていきましょう。スコープとは、 +要素が有効になるプログラム内の範囲のことです。以下のような変数があるとしましょう: ```rust let s = "hello"; @@ -203,8 +203,8 @@ let s = "hello"; 変数`s`は、文字列リテラルを参照し、ここでは、文字列の値はプログラムのテキストとしてハードコードされています。 -この変数は、宣言された地点から、現在の*スコープ*の終わりまで有効になります。リスト4-1には、変数`s`が -有効な場所に関する注釈がコメントで付記されています: +この変数は、宣言された地点から、現在の*スコープ*の終わりまで有効になります。リスト4-1には、 +変数`s`が有効な場所に関する注釈がコメントで付記されています: @@ -256,8 +256,8 @@ valid --> 所有権の規則を具体化するには、第3章で解説したものよりも、より複雑なデータ型が必要になります。 以前見たデータ型は全てスタックに保管され、スコープが終わるとスタックから取り除かれますが、 -ヒープに確保されるデータ型を観察して、コンパイラがどうそのデータを掃除すべきタイミングを把握しているか -を掘り下げていきたいです。 +ヒープに確保されるデータ型を観察して、 +コンパイラがどうそのデータを掃除すべきタイミングを把握しているかを掘り下げていきたいです。 @@ -279,12 +279,12 @@ valid --> すでに文字列リテラルは見かけましたね。文字列リテラルでは、文字列の値はプログラムにハードコードされます。 -文字列リテラルは便利ですが、テキストを使いたい場面全てに最適なわけではありません。一因は、文字列リテラルが -不変であることに起因します。別の原因は、コードを書く際に、全ての文字列値が判明するわけではないからです: +文字列リテラルは便利ですが、テキストを使いたい場面全てに最適なわけではありません。一因は、 +文字列リテラルが不変であることに起因します。別の原因は、コードを書く際に、全ての文字列値が判明するわけではないからです: 例えば、ユーザ入力を受け付け、それを保持したいとしたらどうでしょうか?このような場面用に、Rustには、 -2種類目の文字列型、`String`型があります。この型はヒープにメモリを確保するので、コンパイル時には -サイズが不明なテキストも保持することができるのです。`from`関数を使用して、文字列リテラルから -`String`型を生成できます。以下のように: +2種類目の文字列型、`String`型があります。この型はヒープにメモリを確保するので、 +コンパイル時にはサイズが不明なテキストも保持することができるのです。`from`関数を使用して、 +文字列リテラルから`String`型を生成できます。以下のように: ```rust let s = String::from("hello"); @@ -296,9 +296,9 @@ let s = String::from("hello"); -この二重コロンは、`string_from`などの名前を使うのではなく、`String`型直下の`from`関数を特定する働きをする -演算子です。この記法について詳しくは、第5章の「メソッド記法」節と、第7章のモジュールを使った名前空間分け -について話をするときに議論します。 +この二重コロンは、`string_from`などの名前を使うのではなく、 +`String`型直下の`from`関数を特定する働きをする演算子です。この記法について詳しくは、 +第5章の「メソッド記法」節と、第7章のモジュールを使った名前空間分けについて話をするときに議論します。 @@ -338,9 +338,9 @@ println!("{}", s); // これは`hello, world!`と出力する 文字列リテラルの場合、中身はコンパイル時に判明しているので、テキストは最終的なバイナリファイルに直接ハードコードされます。 -その結果、文字列リテラルは、高速で効率的になるのです。しかし、これらの特性は、その不変性にのみ -端を発するものです。残念なことに、コンパイル時にサイズが不明だったり、プログラム実行に合わせてサイズが -可変なテキスト片用に一塊のメモリをバイナリに確保しておくことは不可能です。 +その結果、文字列リテラルは、高速で効率的になるのです。しかし、これらの特性は、 +その不変性にのみ端を発するものです。残念なことに、コンパイル時にサイズが不明だったり、 +プログラム実行に合わせてサイズが可変なテキスト片用に一塊のメモリをバイナリに確保しておくことは不可能です。 @@ -378,8 +378,8 @@ println!("{}", s); // これは`hello, world!`と出力する しかしながら、2番目の部分は異なります。*ガベージコレクタ*(GC)付きの言語では、GCがこれ以上、 使用されないメモリを検知して片付けるため、私たちプログラマは、そのことを考慮する必要はありません。 GCがないなら、メモリがもう使用されないことを見計らって、明示的に返還するコードを呼び出すのは、 -プログラマの責任になります。ちょうど要求の際にしたようにですね。これを正確にすることは、歴史的にも -難しいプログラミング問題の一つであり続けています。もし、忘れていたら、メモリを無駄にします。 +プログラマの責任になります。ちょうど要求の際にしたようにですね。これを正確にすることは、 +歴史的にも難しいプログラミング問題の一つであり続けています。もし、忘れていたら、メモリを無駄にします。 タイミングが早すぎたら、無効な変数を作ってしまいます。2回解放してしまっても、バグになるわけです。 `allocate`と`free`は1対1対応にしなければならないのです。 @@ -388,8 +388,8 @@ GCがないなら、メモリがもう使用されないことを見計らって Rustは、異なる道を歩んでいます: ひとたび、メモリを所有している変数がスコープを抜けたら、 -メモリは自動的に返還されます。こちらの例は、リスト4-1のスコープ例を文字列リテラルから -`String`型を使うものに変更したバージョンになります: +メモリは自動的に返還されます。こちらの例は、 +リスト4-1のスコープ例を文字列リテラルから`String`型を使うものに変更したバージョンになります: @@ -416,24 +416,24 @@ Rustは、異なる道を歩んでいます: ひとたび、メモリを所有 `String`型が必要とするメモリをOSに返還することが自然な地点があります: `s`変数がスコープを抜ける時です。 -変数がスコープを抜ける時、Rustは特別な関数を呼んでくれます。この関数は、`drop`と呼ばれ、ここに`String`型の -書き手はメモリ返還するコードを配置することができます。Rustは、閉じ`}`で自動的に`drop`関数を呼び出します。 +変数がスコープを抜ける時、Rustは特別な関数を呼んでくれます。この関数は、`drop`と呼ばれ、 +ここに`String`型の書き手はメモリ返還するコードを配置することができます。Rustは、閉じ`}`で自動的に`drop`関数を呼び出します。 -> 注釈: C++では、要素の生存期間の終了地点でリソースを解放するこのパターンを時に、*RAII*(Resource Aquisition -> Is Initialization)と呼んだりします。Rustの`drop`関数は、あなたがRAIIパターンを使ったことがあれば、 -> 馴染み深いものでしょう。 +> 注釈: C++では、要素の生存期間の終了地点でリソースを解放するこのパターンを時に、 +> *RAII*(Resource Aquisition Is Initialization: リソースの獲得は、初期化である)と呼んだりします。 +> Rustの`drop`関数は、あなたがRAIIパターンを使ったことがあれば、馴染み深いものでしょう。 -このパターンは、Rustコードの書かれ方に甚大な衝撃をもたらします。現状は簡単そうに見えるかもしれませんが、 +このパターンは、Rustコードの書かれ方に甚大な影響をもたらします。現状は簡単そうに見えるかもしれませんが、 ヒープ上に確保されたデータを複数の変数に使用させるようなもっと複雑な場面では、コードの振る舞いは、 予期しないものになる可能性もあります。これから、そのような場面を掘り下げてみましょう。 @@ -464,8 +464,8 @@ to `y` --> もしかしたら、他の言語の経験に基づいて、何をしているのか予想することができるでしょう: -「値`5`を`x`に束縛する; それから`x`の値をコピーして`y`に束縛する。」これで、二つの変数(`x`と -`y`)が存在し、両方、値は`5`になりました。これは確かに起こっている現象を説明しています。 +「値`5`を`x`に束縛する; それから`x`の値をコピーして`y`に束縛する。」これで、 +二つの変数(`x`と`y`)が存在し、両方、値は`5`になりました。これは確かに起こっている現象を説明しています。 なぜなら、整数は既知の固定サイズの単純な値で、これら二つの`5`という値は、スタックに積まれるからです。 @@ -482,8 +482,8 @@ let s2 = s1; このコードは先ほどのコードに酷似していますので、動作方法も同じだと思い込んでしまうかもしれません: -要するに、2行目で`s1`の値をコピーし、`s2`に束縛するということです。ところが、これは全く起こることを -言い当てていません。 +要するに、2行目で`s1`の値をコピーし、`s2`に束縛するということです。ところが、 +これは全く起こることを言い当てていません。 @@ -492,9 +492,9 @@ let s2 = s1; これをもっと徹底的に説明するために、図4-3を見て`String`型のベールを剥がしてみましょう。 -`String`型は、左側に示されているように、3つの部品でできています: 文字列の中身を保持する -メモリへのポインタと長さ、そして、許容量です。この種のデータは、スタックに保持されます。 -右側には、ヒープ上の中身を保持したメモリがあります。 +`String`型は、左側に示されているように、3つの部品でできています: +文字列の中身を保持するメモリへのポインタと長さ、そして、許容量です。この種のデータは、スタックに保持されます。 +右側には、中身を保持したヒープ上のメモリがあります。 @@ -503,8 +503,7 @@ let s2 = s1; -図4-3: `s1`に束縛された`"hello"`という値を保持する`String` - のメモリ上の表現 +図4-3: `s1`に束縛された`"hello"`という値を保持する`String`のメモリ上の表現 @@ -512,8 +511,8 @@ holding the value `"hello"` bound to `s1` --> -長さは、`String`型の中身が現在使用しているメモリ量をバイトで表したものです。許容量は、`String`型が -OSから受け取った全メモリ量をバイトで表したものです。長さと許容量の違いは問題になることですが、 +長さは、`String`型の中身が現在使用しているメモリ量をバイトで表したものです。許容量は、 +`String`型がOSから受け取った全メモリ量をバイトで表したものです。長さと許容量の違いは問題になることですが、 この文脈では違うので、とりあえずは、許容量を無視しても構わないでしょう。 @@ -521,9 +520,9 @@ OSから受け取った全メモリ量をバイトで表したものです。長 -`s1`を`s2`に代入すると、`String`型のデータがコピーされます。つまり、スタックにあるポインタ、長さ、許容量を -コピーするということです。ポインタが指すヒープ上のデータはコピーしません。言い換えると、メモリ上のデータ表現は -図4-4のようになるということです。 +`s1`を`s2`に代入すると、`String`型のデータがコピーされます。つまり、スタックにあるポインタ、長さ、 +許容量をコピーするということです。ポインタが指すヒープ上のデータはコピーしません。言い換えると、 +メモリ上のデータ表現は図4-4のようになるということです。 @@ -532,17 +531,16 @@ OSから受け取った全メモリ量をバイトで表したものです。長 -図4-4: `s1`のポインタ、長さ、許容量のコピーを保持する変数`s2`の - メモリ上での表現 +図4-4: `s1`のポインタ、長さ、許容量のコピーを保持する変数`s2`のメモリ上での表現 -メモリ上の表現は、図4-5のようにはなり*ません*。これは、Rustが代わりにヒープデータもコピーする -という選択をしていた場合のメモリ表現ですね。Rustがこれをしていたら、ヒープ上のデータが大きい時に -`s2 = s1`という処理の実行時性能がとても悪くなっていた可能性があるでしょう。 +メモリ上の表現は、図4-5のようにはなり*ません*。これは、 +Rustが代わりにヒープデータもコピーするという選択をしていた場合のメモリ表現ですね。Rustがこれをしていたら、 +ヒープ上のデータが大きい時に`s2 = s1`という処理の実行時性能がとても悪くなっていた可能性があるでしょう。 @@ -551,8 +549,7 @@ that has a copy of the pointer, length, and capacity of `s1` --> -図4-5: Rustがヒープデータもコピーしていた場合に`s2 = s1`という - 処理が行なった可能性のあること +図4-5: Rustがヒープデータもコピーしていた場合に`s2 = s1`という処理が行なった可能性のあること @@ -562,10 +559,10 @@ do if Rust copied the heap data as well --> -先ほど、変数がスコープを抜けたら、Rustは自動的に`drop`関数を呼び出し、その変数が使っていた -ヒープメモリを片付けると述べました。しかし、図4-4は、両方のデータポインタが同じ場所を指していることを -示しています。これは問題です: `s2`と`s1`がスコープを抜けたら、両方とも同じメモリを解放しようとします。 -これは*二重解放*エラーとして知られ、以前触れたメモリ安全性上のバグの一つになります。 +先ほど、変数がスコープを抜けたら、Rustは自動的に`drop`関数を呼び出し、 +その変数が使っていたヒープメモリを片付けると述べました。しかし、図4-4は、 +両方のデータポインタが同じ場所を指していることを示しています。これは問題です: `s2`と`s1`がスコープを抜けたら、 +両方とも同じメモリを解放しようとします。これは*二重解放*エラーとして知られ、以前触れたメモリ安全性上のバグの一つになります。 メモリを2回解放することは、メモリの退廃につながり、さらにセキュリティ上の脆弱性を生む可能性があります。 @@ -577,8 +574,8 @@ do if Rust copied the heap data as well --> メモリ安全性を保証するために、Rustにおいてこの場面で知っておきたい起こる事の詳細がもう一つあります。 -確保されたメモリをコピーしようとする代わりに、コンパイラは、`s1`が最早有効ではないと考え、故に -`s1`がスコープを抜けた際に何も解放する必要がなくなるわけです。`s2`の生成後に`s1`を使用しようとしたら、 +確保されたメモリをコピーしようとする代わりに、コンパイラは、`s1`が最早有効ではないと考え、 +故に`s1`がスコープを抜けた際に何も解放する必要がなくなるわけです。`s2`の生成後に`s1`を使用しようとしたら、 どうなるかを確認してみましょう: ```rust,ignore @@ -642,8 +639,8 @@ invalidated --> -付け加えると、これにより暗示されるデザイン上の選択があります: Rustでは、自動的にデータの"deep copy"が -行われることは絶対にないわけです。それ故に、あらゆる*自動*コピーは、実行時性能の観点で言うと、 +付け加えると、これにより暗示される設計上の選択があります: Rustでは、 +自動的にデータの"deep copy"が行われることは絶対にないわけです。それ故に、あらゆる*自動*コピーは、実行時性能の観点で言うと、 悪くないと考えてよいことになります。 @@ -673,7 +670,7 @@ println!("s1 = {}, s2 = {}", s1, s2); -これは単純にうまく動き、図4-5で示した動作を明示的に生み出す手段です。ここでは、 +これは単純にうまく動き、こうして図4-5で示した動作を明示的に生み出すことができます。ここでは、 ヒープデータが*実際に*コピーされています。 @@ -703,8 +700,8 @@ println!("x = {}, y = {}", x, y); -ですが、このコードは一見、今学んだことと矛盾しているように見えます: `clone`メソッドの呼び出しが -ないのに、`x`は有効で、`y`にムーブされませんでした。 +ですが、このコードは一見、今学んだことと矛盾しているように見えます: +`clone`メソッドの呼び出しがないのに、`x`は有効で、`y`にムーブされませんでした。 @@ -714,10 +711,10 @@ println!("x = {}, y = {}", x, y); その理由は、整数のようなコンパイル時に既知のサイズを持つ型は、スタック上にすっぽり保持されるので、 -実際の値を生成するのも高速だからです。これは、変数`y`を生成した後にも`x`を無効化したくなる -理由がないことを意味します。換言すると、ここでは、shallow copyとdeep copyの違いがないことになり、 -`clone`メソッドを呼び出しても、一般的なshallow copy以上のことをしなくなり、そのまま放置しておける -ということです。 +実際の値をコピーするのも高速だからです。これは、変数`y`を生成した後にも`x`を無効化したくなる理由がないことを意味します。 +換言すると、ここでは、shallow copyとdeep copyの違いがないことになり、 +`clone`メソッドを呼び出しても、一般的なshallow copy以上のことをしなくなり、 +そのまま放置しておけるということです。 @@ -729,13 +726,12 @@ println!("x = {}, y = {}", x, y); -Rustには`Copy`トレイトと呼ばれる特別な注釈があり、整数のようなスタックに保持される型に対して -配置することができます(トレイトについては第10章でもっと詳しく話します)。型が`Copy`トレイトに -適合していれば、代入後も古い変数が使用可能になります。コンパイラは、型やその一部分でも`Drop` -トレイトを実装している場合、`Copy`トレイトによる注釈をさせてくれません。型の値がスコープを外れた時に -何か特別なことを起こす必要がある場合に、`Copy`注釈を追加すると、コンパイルエラーが出ます。 -型に`Copy`注釈をつける方法について学ぶには、付録Cの継承可能トレイト(Derivable Traits)についてを -ご覧ください。 +Rustには`Copy`トレイトと呼ばれる特別な注釈があり、 +整数のようなスタックに保持される型に対して配置することができます(トレイトについては第10章でもっと詳しく話します)。 +型が`Copy`トレイトに適合していれば、代入後も古い変数が使用可能になります。コンパイラは、 +型やその一部分でも`Drop`トレイトを実装している場合、`Copy`トレイトによる注釈をさせてくれません。 +型の値がスコープを外れた時に何か特別なことを起こす必要がある場合に、`Copy`注釈を追加すると、コンパイルエラーが出ます。 +型に`Copy`注釈をつける方法について学ぶには、付録Cの継承可能トレイト(Derivable Traits)についてをご覧ください。 @@ -755,7 +751,7 @@ Rustには`Copy`トレイトと呼ばれる特別な注釈があり、整数の * あらゆる整数型。`u32`など。 * 論理値型、`bool`、`true`と`false`という値がある。 * あらゆる浮動小数点型、`f64`など。 -* タプル。ただ、`Copy`の型だけを含む場合。`(i32, i32)`は`Copy`だが +* タプル。ただ、`Copy`の型だけを含む場合。`(i32, i32)`は`Copy`だが、 `(i32, String)`は違う。 @@ -768,8 +764,8 @@ Rustには`Copy`トレイトと呼ばれる特別な注釈があり、整数の 意味論的に、関数に値を渡すことと、値を変数に代入することは似ています。関数に変数を渡すと、 -代入のようにムーブやコピーされます。リスト4-7は変数がスコープに入ったり、抜けたりする地点に -ついて注釈してある例です: +代入のようにムーブやコピーされます。リスト4-7は変数がスコープに入ったり、 +抜けたりする地点について注釈してある例です: @@ -918,8 +914,8 @@ fn takes_and_gives_back(a_string: String) -> String { // a_stringがスコープ 変数の所有権は、毎回同じパターンを辿っています: 別の変数に値を代入すると、ムーブされます。 -ヒープにデータを含む変数がスコープを抜けると、データが別の変数に所有されるようムーブされていない -限り、`drop`により片付けられるでしょう。 +ヒープにデータを含む変数がスコープを抜けると、データが別の変数に所有されるようムーブされていない限り、 +`drop`により片付けられるでしょう。 @@ -928,8 +924,8 @@ fn takes_and_gives_back(a_string: String) -> String { // a_stringがスコープ 所有権を得ては返すを全ての関数でしていたら、ちょっとめんどくさいですね。関数に値を使わせたいけど、 -所有権は保持させたくない場合はどうすればいいのでしょうか?返したいと思うかもしれない関数本体で発生した -あらゆるデータとともに再利用したかったら、渡されたものをまた返さなきゃいけないのは、 +所有権は保持させたくない場合はどうすればいいのでしょうか? +返したいと思うかもしれない関数本体で発生したあらゆるデータとともに再利用したかったら、渡されたものをまた返さなきゃいけないのは、 非常に煩わしいことです。 diff --git a/second-edition/src/ch04-02-references-and-borrowing.md b/second-edition/src/ch04-02-references-and-borrowing.md index 0e7114694..b6da88984 100644 --- a/second-edition/src/ch04-02-references-and-borrowing.md +++ b/second-edition/src/ch04-02-references-and-borrowing.md @@ -60,7 +60,7 @@ fn calculate_length(s: &String) -> usize { -ここの関数呼び出しについてついてもっと詳しく見てみましょう: +ここの関数呼び出しについて、もっと詳しく見てみましょう: ```rust # fn calculate_length(s: &String) -> usize { @@ -147,7 +147,7 @@ fn change(some_string: &String) { ```text error: cannot borrow immutable borrowed content `*some_string` as mutable -(エラー: 不変な借用した中身`*some_string`を可変で借用できません) +(エラー: 不変な借用をした中身`*some_string`を可変で借用できません) --> error.rs:8:5 | 8 | some_string.push_str(", world"); @@ -394,9 +394,9 @@ error[E0106]: missing lifetime specifier | = 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 lifetimeを与えることを考慮してみてください) + ('staticライフタイムを与えることを考慮してみてください) error: aborting due to previous error ``` @@ -445,7 +445,7 @@ fn dangle() -> &String { // dangleはStringへの参照を返す -`s`は、`dangle`関数内で生成されているので、`dangle`関数のコードが終わったら、`s`は解放されてしまいますが、 +`s`は、`dangle`内で生成されているので、`dangle`のコードが終わったら、`s`は解放されてしまいますが、 そこへの参照を返そうとしました。つまり、この参照は無効な`String`を指していると思われるのです。 よくないことです。コンパイラは、これを阻止してくれるのです。 diff --git a/second-edition/src/ch04-03-slices.md b/second-edition/src/ch04-03-slices.md index 5a6341cf0..658c94e75 100644 --- a/second-edition/src/ch04-03-slices.md +++ b/second-edition/src/ch04-03-slices.md @@ -31,7 +31,7 @@ fn first_word(s: &String) -> ? この関数、`first_word`は引数に`&String`をとります。所有権はいらないので、これで十分です。 -ですが、何を返すべきでしょうか?文字列の一部について語る方法が全くありません。しかし、 +ですが、何を返すべきでしょうか?文字列の*一部*について語る方法が全くありません。しかし、 単語の終端の番号を返すことができますね。リスト4-10に示したように、その方法を試してみましょう: @@ -96,7 +96,7 @@ for (i, &item) in bytes.iter().enumerate() { `enumerate`メソッドがタプルを返すので、Rustのあらゆる場所同様、パターンを使って、そのタプルを分解できます。 従って、`for`ループ内で、タプルの番号に対する`i`とタプルの1バイトに対応する`&item`を含むパターンを指定しています。 -`.iter().enumerate()`から要素への参照を取得するので、パターンにも`&`を使っています。 +`.iter().enumerate()`から要素への参照を取得するので、パターンに`&`を使っています。 @@ -225,7 +225,7 @@ fn second_word(s: &String) -> (usize, usize) { -文字列スライスとは、`String`の一部への参照で、こんな見た目をしています: +*文字列スライス*とは、`String`の一部への参照で、こんな見た目をしています: ```rust let s = String::from("hello world"); From 455910053c1c43176d1d17ba816d036f1a5c2ec6 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 21 Sep 2017 20:04:22 +0900 Subject: [PATCH 051/428] First drafts of the chapters 8-0, 8-1, and 8-2 --- second-edition/src/SUMMARY.md | 13 +- .../src/ch08-00-common-collections.md | 64 +- second-edition/src/ch08-01-vectors.md | 480 ++++++++---- second-edition/src/ch08-02-strings.md | 713 ++++++++++++------ 4 files changed, 851 insertions(+), 419 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index 8a3142144..75e35fbf2 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -70,10 +70,15 @@ - [`pub`で公開するか制御する](ch07-02-controlling-visibility-with-pub.md) - [`use`で名前をインポートする](ch07-03-importing-names-with-use.md) -- [Common Collections](ch08-00-common-collections.md) - - [Vectors](ch08-01-vectors.md) - - [Strings](ch08-02-strings.md) - - [Hash Maps](ch08-03-hash-maps.md) + + + + + +- [一般的なコレクション](ch08-00-common-collections.md) + - [ベクタ型](ch08-01-vectors.md) + - [文字列型](ch08-02-strings.md) + - [ハッシュマップ](ch08-03-hash-maps.md) - [Error Handling](ch09-00-error-handling.md) - [Unrecoverable Errors with `panic!`](ch09-01-unrecoverable-errors-with-panic.md) diff --git a/second-edition/src/ch08-00-common-collections.md b/second-edition/src/ch08-00-common-collections.md index b45e49d99..b17936787 100644 --- a/second-edition/src/ch08-00-common-collections.md +++ b/second-edition/src/ch08-00-common-collections.md @@ -1,25 +1,45 @@ -# Common Collections - -Rust’s standard library includes a number of very useful data structures called -*collections*. Most other data types represent one specific value, but -collections can contain multiple values. Unlike the built-in array and tuple -types, the data these collections point to is stored on the heap, which means -the amount of data does not need to be known at compile time and can grow or -shrink as the program runs. Each kind of collection has different capabilities -and costs, and choosing an appropriate one for your current situation is a -skill you’ll develop over time. In this chapter, we’ll discuss three -collections that are used very often in Rust programs: - -* A *vector* allows us to store a variable number of values next to each other. -* A *string* is a collection of characters. We’ve discussed the `String` type - previously, but in this chapter we’ll talk about it in depth. -* A *hash map* allows us to associate a value with a particular key. It’s a - particular implementation of the more general data structure called a *map*. - -To learn about the other kinds of collections provided by the standard library, -see [the documentation][collections]. + + +# 一般的なコレクション + + + + + + + + + + + +Rustの標準ライブラリは、*コレクション*と呼ばれる多くの非常に有益なデータ構造を含んでいます。他の多くのデータ型は、 +ある一つの値を表しますが、コレクションは複数の値を含むことができます。組み込みの配列とタプル型とは異なり、 +これらのコレクションが指すデータはヒープに確保され、データ量はコンパイル時にわかる必要はなく、 +プログラムの実行にあわせて、伸縮可能であることになります。各種のコレクションには異なる能力とコストが存在し、 +自分の現在の状況に最適なものを選び取るスキルは、時間とともに育っていきます。この章では、 +Rustのプログラムにおいて、非常に頻繁に使用される3つのコレクションについて議論しましょう。 + + + + + + + +* *ベクタ型*は、可変長の値を並べて保持できる。 +* *文字列*は、文字のコレクションである。以前、`String`型については議論したが、 +この章ではより掘り下げていく。 +* *ハッシュマップ*は、値を特定のキーと紐付けさせてくれる。より一般的なデータ構造である、 +*マップ*の特定の実装である。 + + + + +標準ライブラリで提供されている他の種のコレクションについて学ぶには、 +[ドキュメント][collections]を参照されたし。 [collections]: ../../std/collections/index.html -We’ll discuss how to create and update vectors, strings, and hash maps, as well -as what makes each special. + + + +ベクタ型、文字列、ハッシュマップの生成と更新方法や、各々が特別な点について議論していきましょう。 diff --git a/second-edition/src/ch08-01-vectors.md b/second-edition/src/ch08-01-vectors.md index c6d6fed7b..c55d5e04c 100644 --- a/second-edition/src/ch08-01-vectors.md +++ b/second-edition/src/ch08-01-vectors.md @@ -1,55 +1,89 @@ -## Vectors + -The first collection type we’ll look at is `Vec`, also known as a *vector*. -Vectors allow us to store more than one value in a single data structure that -puts all the values next to each other in memory. Vectors can only store values -of the same type. They are useful in situations in which you have a list of -items, such as the lines of text in a file or the prices of items in a shopping -cart. +## ベクタ型 -### Creating a New Vector + + + + + + -To create a new, empty vector, we can call the `Vec::new` function as shown in -Listing 8-1: +最初に見るコレクションは、`Vec`であり、*ベクタ型*としても知られています。ベクタ型は、 +メモリ上に値を隣り合わせに並べる単独のデータ構造に2つ以上の値を保持させてくれます。 +ベクタ型には、同じ型の値しか保持できません。要素のリストがあるような場面で有用です。 +例えば、テキストファイルの各行とか、ショッピングカートのアイテムの価格などです。 + + + +### 新しいベクタ型を生成する + + + + +新しい空のベクタ型を作るには、リスト8-1に示されたように、`Vec::new`関数を呼ぶことができます。 ```rust let v: Vec = Vec::new(); ``` -Listing 8-1: Creating a new, empty vector to hold values -of type `i32` - -Note that we added a type annotation here. Because we aren’t inserting any -values into this vector, Rust doesn’t know what kind of elements we intend to -store. This is an important point. Vectors are implemented using generics; -we’ll cover how to use generics with your own types in Chapter 10. For now, -know that the `Vec` type provided by the standard library can hold any type, -and when a specific vector holds a specific type, the type is specified within -angle brackets. In Listing 8-1, we’ve told Rust that the `Vec` in `v` will -hold elements of the `i32` type. - -In more realistic code, Rust can often infer the type of value we want to store -once we insert values, so you rarely need to do this type annotation. It’s more -common to create a `Vec` that has initial values, and Rust provides the -`vec!` macro for convenience. The macro will create a new vector that holds the -values we give it. Listing 8-2 creates a new `Vec` that holds the values -`1`, `2`, and `3`: + + + +リスト8-1: 新しい空のベクタ型を生成して`i32`型の値を保持する + + + + + + + + + + +こちらには、型注釈を付け足したことに注目してください。このベクタ型に対して、何も値を挿入していないので、 +コンパイラには、どんなデータを保持させるつもりなのかわからないのです。これは重要な点です。ベクタ型は、 +ジェネリクスを使用して実装されているのです; 独自の型でジェネリクスを使用する方法については、 +第10章で解説します。今は、標準ライブラリにより提供されている`Vec`型は、どんな型でも保持でき、 +特定のベクタ型が特定の型を保持するとき、その型は山かっこ内に指定されることを知っておいてください。 +リスト8-1では、コンパイラに`v`の`Vec`は、`i32`型の要素を保持すると指示しました。 + + + + + + + + +より現実的なコードでは、一旦値を挿入したら、コンパイラは保持させたい値の型をしばしば推論できるので、 +この型注釈をすることは滅多にありません。初期値のある`Vec`を生成する方が一般的ですし、 +Rustには、利便性のために`vec!`というマクロも用意されています。このマクロは、 +与えた値を保持する新しいベクタ型を生成します。リスト8-2では、`1`、`2`、`3`という値を持つ新しい`Vec`を生成しています: ```rust let v = vec![1, 2, 3]; ``` -Listing 8-2: Creating a new vector containing -values + + + +リスト8-2: 値を含む新しいベクタ型を生成する -Because we’ve given initial `i32` values, Rust can infer that the type of `v` -is `Vec`, and the type annotation isn’t necessary. Next, we’ll look at how -to modify a vector. + + + -### Updating a Vector +初期値の`i32`値を与えたので、コンパイラは、`v`の型が`Vec`であると推論でき、型注釈は必要なくなりました。 +次は、ベクタ型を変更する方法を見ましょう。 -To create a vector and then add elements to it, we can use the `push` method as -shown in Listing 8-3: + + +### ベクタ型を更新する + + + + +ベクタ型を生成し、要素を追加するには、リスト8-3に示したように、`push`メソッドを使用できます。 ```rust let mut v = Vec::new(); @@ -60,45 +94,78 @@ v.push(7); v.push(8); ``` -Listing 8-3: Using the `push` method to add values to a -vector + + + +リスト8-3: `push`メソッドを使用してベクタ型に値を追加する -As with any variable, as discussed in Chapter 3, if we want to be able to -change its value, we need to make it mutable using the `mut` keyword. The -numbers we place inside are all of type `i32`, and Rust infers this from the -data, so we don’t need the `Vec` annotation. + + + + -### Dropping a Vector Drops Its Elements +あらゆる変数同様、第3章で議論したように、値を変化させたかったら、`mut`キーワードで可変にする必要があります。 +中に配置する数値は全て`i32`型であり、コンパイラはこのことをデータから推論するので、 +`Vec`という注釈は必要なくなります。 -Like any other `struct`, a vector will be freed when it goes out of scope, as -annotated in Listing 8-4: + + +### ベクタ型をドロップすれば、要素もドロップする + + + + +他のあらゆる`構造体`同様、ベクタ型もスコープを抜ければ、解放されます。リスト8-4に注釈したようにね: + + + + + + + + + ```rust { let v = vec![1, 2, 3, 4]; - // do stuff with v + // vで作業をする -} // <- v goes out of scope and is freed here +} // <- vはここでスコープを抜け、解放される ``` -Listing 8-4: Showing where the vector and its elements -are dropped + + + +リスト8-4: ベクタ型とその要素がドロップされる箇所を示す + + + + + + +ベクタ型がドロップされると、その中身もドロップされます。つまり、保持されていた整数値が、 +片付けられるということです。これは一見単純な点に見えるかもしれませんが、ベクタの要素への参照を導入した途端、 +もうちょっと複雑になる可能性を秘めています。次は、それに挑んでいきましょう! -When the vector gets dropped, all of its contents will also be dropped, meaning -those integers it holds will be cleaned up. This may seem like a -straightforward point but can get a bit more complicated when we start to -introduce references to the elements of the vector. Let’s tackle that next! + -### Reading Elements of Vectors +### ベクタ型の要素を読む -Now that you know how to create, update, and destroy vectors, knowing how to -read their contents is a good next step. There are two ways to reference a -value stored in a vector. In the examples, we’ve annotated the types of the -values that are returned from these functions for extra clarity. + + + + -Listing 8-5 shows both methods of accessing a value in a vector either with -indexing syntax or the `get` method: +もうベクタ型を生成し、更新し、破壊する方法を知ったので、コンテンツを読む方法を知るのはいいステップアップです。 +ベクタ型に保持された値を参照する方法は2つあります。例では、さらなる明瞭性を求めて、 +これらの関数から返る値の型を注釈しました。 + + + + +リスト8-5に示したのは、両メソッドがベクタ型の値に対して、添字記法と`get`メソッドによりアクセスするところです: ```rust let v = vec![1, 2, 3, 4, 5]; @@ -107,20 +174,30 @@ let third: &i32 = &v[2]; let third: Option<&i32> = v.get(2); ``` -Listing 8-5: Using indexing syntax or the `get` method to -access an item in a vector + + + +リスト8-5: 添字記法か`get`メソッドを使用してベクタ型の要素にアクセスする + + + + + + + +ここでは、2つのことに気付いてください。まず、3番目の要素を得るのに`2`という添え字の値を使用していることです: +ベクタ型は、数値により順序付けされ、添え字は0から始まります。2番目に、3番目の要素を得る2つの方法は、 +`&`と`[]`を使用して参照を得るものと、番号を引数として`get`メソッドに渡して、`Option<&T>`を得るものということです。 -Note two details here. First, we use the index value of `2` to get the third -element: vectors are indexed by number, starting at zero. Second, the two -different ways to get the third element are by using `&` and `[]`, which gives -us a reference, or by using the `get` method with the index passed as an -argument, which gives us an `Option<&T>`. + + + + + -The reason Rust has two ways to reference an element is so you can choose how -the program behaves when you try to use an index value that the vector doesn’t -have an element for. As an example, what should a program do if it has a vector -that holds five elements and then tries to access an element at index 100, as -shown in Listing 8-6: +Rustに要素を参照する方法が2通りある理由は、ベクタ型に要素が含まれない番号の値を使用しようとした時に、 +プログラムの振る舞いを選択できるようにするためです。例として、ベクタ型に5つ要素があり、 +番号100の要素にアクセスを試みた場合、プログラムはどう振る舞うべきでしょうか?リスト8-6に示したようにね: ```rust,should_panic let v = vec![1, 2, 3, 4, 5]; @@ -129,32 +206,54 @@ let does_not_exist = &v[100]; let does_not_exist = v.get(100); ``` -Listing 8-6: Attempting to access the element at index -100 in a vector containing 5 elements - -When you run this code, the first `[]` method will cause a `panic!` because it -references a nonexistent element. This method is best used when you want your -program to consider an attempt to access an element past the end of the vector -to be a fatal error that crashes the program. - -When the `get` method is passed an index that is outside the vector, it returns -`None` without panicking. You would use this method if accessing an element -beyond the range of the vector happens occasionally under normal circumstances. -Your code will then have logic to handle having either `Some(&element)` or -`None`, as discussed in Chapter 6. For example, the index could be coming from -a person entering a number. If they accidentally enter a number that’s too -large and the program gets a `None` value, you could tell the user how many -items are in the current `Vec` and give them another chance to enter a valid -value. That would be more user-friendly than crashing the program due to a typo! - -#### Invalid References - -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 we 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: + + + +リスト8-6: 5つの要素を含むベクタ型の100番目の要素にアクセスしようとする + + + + + + +このコードを走らせると、最初の`[]`メソッドは`panic!`を引き起こします。存在しない要素を参照しているからです。 +このメソッドは、プログラムがベクタの終端を超えて要素にアクセスしようしたことを、 +プログラムをクラッシュさせるような重大なエラーとして捉えてほしい場合に最適です。 + + + + + + + + + + + +`get`メソッドがベクタ外の番号を渡されると、パニックすることなく`None`を返します。 +普通の状態でも、ベクタの範囲外にアクセスする可能性がある場合に、このメソッドを使用することでしょう。 +そうしたら、コードには`Some(&element)`か`None`を扱うロジックが存在することになります。そう、 +第6章で議論したように。例えば、番号は人間に数値を入力してもらうことで得ることもできます。 +もし大きすぎる値を誤って入力し、プログラムが`None`値を得てしまったら、現在`Vec`に幾つ要素があるかをユーザに教え、 +再度正しい値を入力してもらうことができるでしょう。その方が、タイプミスでプログラムをクラッシュさせるより、 +ユーザに優しくなるでしょう。 + + + +#### 無効な参照 + + + + + + + + +プログラムに有効な参照がある場合、borrow checker(借用精査機)は(第4章で解説しましたが)、 +所有権と借用規則を強制し、ベクタ型の中身へのこの参照や他のいかなる参照も有効であり続けることを保証してくれます。 +同一スコープ上では、可変と不変な参照を同時には存在させられないというルールを思い出してください。 +このルールはリスト8-7にも適用され、リスト8-7ではベクタの最初の要素への不変参照を保持し、 +終端に要素を追加しようとしています: ```rust,ignore let mut v = vec![1, 2, 3, 4, 5]; @@ -164,42 +263,65 @@ let first = &v[0]; v.push(6); ``` -Listing 8-7: Attempting to add an element to a vector -while holding a reference to an item + + -Compiling this code will result in this error: +リスト8-7: 要素への参照を保持しつつ、ベクタに要素を追加しようとする + + + +このコードをコンパイルすると、こんなエラーになります: ```text error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable +(エラー: 不変としても借用されているので、`v`を可変で借用できません) | 4 | let first = &v[0]; | - immutable borrow occurs here + | (不変借用はここで発生しています) 5 | 6 | v.push(6); | ^ mutable borrow occurs here + | (可変借用は、ここで発生しています) 7 | } | - immutable borrow ends here + | (不変借用はここで終了しています) ``` -The code in Listing 8-7 might look like it should work: why should a reference -to the first element care about what changes at the end of the vector? The -reason behind this error is due to the way vectors work: adding a new element -onto the end of the vector might require allocating new memory and copying the -old elements to the new space if there isn’t enough room to put all the -elements next to each other where the vector was. In that case, the reference -to the first element would be pointing to deallocated memory. The borrowing -rules prevent programs from ending up in that situation. + + + + + + + + + +リスト8-7のコードは、一見動くはずのように見えるかもしれません: なぜ、最初の要素への参照が、 +ベクタの終端への変更を気にかける必要があるのでしょうか?このエラーの背後にある理由は、 +ベクタの動作法にあります: 新規要素をベクタの終端に追加すると、ベクタが存在した位置に隣り合って要素を入れるだけの領域がなかった場合に、 +メモリの新規確保をして古い要素を新しいスペースにコピーする必要があるかもしれないからです。 +その場合、最初の要素を指す参照は、解放されたメモリを指すことになるでしょう。借用規則により、 +そのような場面にならないよう回避されるのです。 + + + -> Note: For more on the implementation details of the `Vec` type, see “The -> Nomicon” at https://doc.rust-lang.org/stable/nomicon/vec.html. +> 注釈: `Vec`の実装に関する詳細については、https://doc.rust-lang.org/stable/nomicon/vec.htmlの、 +> "The Nomicon"を参照されたし。 -### Iterating Over the Values in a Vector + -If we want to access each element in a vector in turn, rather than using -indexing to access one element, we can iterate through all of the elements. -Listing 8-8 shows how to use a `for` loop to get immutable references to each -element in a vector of `i32` values and print them out: +### ベクタの値を走査する + + + + + + +ベクタの要素に順番にアクセスしたいなら、添え字で1要素にアクセスするのではなく、全要素を走査することができます。 +リスト8-8で`for`ループを使い、`i32`のベクタの各要素に対する不変な参照を得て、それらを出力する方法を示しています: ```rust let v = vec![100, 32, 57]; @@ -208,12 +330,17 @@ for i in &v { } ``` -Listing 8-8: Printing each element in a vector by -iterating over the elements using a `for` loop + + + +リスト8-8: `for`ループで要素を走査し、ベクタの各要素を出力する -We can also iterate over mutable references to each element in a mutable vector -if we want to make changes to all the elements. The `for` loop in Listing 8-9 -will add `50` to each element: + + + + +全要素に変更を加えたかったら、可変なベクタの各要素への可変な参照を走査することもできます。 +リスト8-9の`for`ループでは、各要素に`50`を足しています: ```rust let mut v = vec![100, 32, 57]; @@ -222,27 +349,44 @@ for i in &mut v { } ``` -Listing 8-9: Iterating over mutable references to -elements in a vector + + + +リスト8-9: ベクタの要素への可変な参照を走査する + + + + + +可変参照が参照する値を変更するには、`i`に対して`+=`演算子を使用する前に、 +参照外し演算子(`*`)を使用して値に辿り着かないといけません。 + + + +### Enumを使って複数の型を保持する -In order to change the value that the mutable reference refers to, before we -can use the `+=` operator with `i`, we have to use the dereference operator -(`*`) to get to the value. + + + + + -### Using an Enum to Store Multiple Types +この章の冒頭で、ベクタは同じ型の値しか保持できないと述べました。これは不便に考えられることもあります; +異なる型の要素を保持する必要性が出てくるユースケースも確かにあるわけです。幸運なことに、 +enumのバリアントは、同じenumの型の元に定義されるので、ベクタに異なる型の要素を保持する必要が出たら、 +enumを定義して使用することができます! -At the beginning of this chapter, we said that vectors can only store values -that are the same type. This can be inconvenient; there are definitely use -cases for needing to store a list of items of different types. Fortunately, the -variants of an enum are defined under the same enum type, so when we need to -store elements of a different type in a vector, we can define and use an enum! + + + + + + -For example, let’s say we want to get values from a row in a spreadsheet where -some of the columns in the row contain integers, some floating-point numbers, -and some strings. We can define an enum whose variants will hold the different -value types, and then all the enum variants will be considered the same type, -that of the enum. Then we can create a vector that holds that enum and so, -ultimately, holds different types. We’ve demonstrated this in Listing 8-8: +例えば、スプレッドシートの行から値を得たくなったとしましょう。ここで行の列には、整数を含むものや、 +浮動小数点数を含むもの、文字列を含むものがあります。バリアントが異なる値の型を保持するenumを定義できます。 +そして、このenumのバリアントは全て同じ型、つまり、enumの型と考えられるわけです。それからそのenumを保持するベクタを生成でき、 +結果的に異なる型を保持できるようになるわけです。リスト8-8でこれを模擬しています。 ```rust enum SpreadsheetCell { @@ -258,24 +402,42 @@ let row = vec![ ]; ``` -Listing 8-8: Defining an `enum` to store values of -different types in one vector - -The reason Rust needs to know what types will be in the vector at compile time -is so it knows exactly how much memory on the heap will be needed to store each -element. A secondary advantage is that we can be explicit about what types are -allowed in this vector. If Rust allowed a vector to hold any type, there would -be a chance that one or more of the types would cause errors with the -operations performed on the elements of the vector. Using an enum plus a -`match` expression means that Rust will ensure at compile time that we always -handle every possible case, as discussed in Chapter 6. - -If you don’t know when you’re writing a program the exhaustive set of types the -program will get at runtime to store in a vector, the enum technique won’t -work. Instead, you can use a trait object, which we’ll cover in Chapter 17. - -Now that we’ve discussed some of the most common ways to use vectors, be sure -to review the API documentation for all the many useful methods defined on -`Vec` by the standard library. For example, in addition to `push`, a `pop` -method removes and returns the last element. Let’s move on to the next -collection type: `String`! + + + +リスト8-8: `enum`を定義して、一つのベクタに異なる型の値を保持する + + + + + + + + + + +コンパイラがコンパイル時にベクタに入る型を知る必要がある理由は、 +各要素を保持するのにヒープ上でズバリどれくらいのメモリが必要になるかを知るためです。副次的な利点は、 +このベクタではどんな型が許容されるのか明示できることです。もしRustでベクタがどんな型でも保持できたら、 +ベクタの要素に対して行われる処理に対して一つ以上の型がエラーを引き起こす可能性があったでしょう。 +enumに加えて`match`式を使うことは、第6章で議論した通り、コンパイル時にありうる場合全てに対処していることをコンパイラが、 +確認できることを意味します。 + + + + + + + +ベクタに実行時に保持される一連の型をプログラムに記述してあげる場合を知らない場合、このenumテクニックはうまくいかないでしょう。 +代わりに、トレイトオブジェクトを使用することができ、こちらは第17章で解説します。 + + + + + + + +今や、ベクタを使用するべきありふれた方法について議論したので、標準ライブラリで`Vec`に定義されている多くの有益なメソッドについては、 +APIドキュメントを確認することを心得てください。例として、`push`に加えて、`pop`メソッドは最後の要素を削除して返します。 +次のコレクション型に移りましょう: `String`です! diff --git a/second-edition/src/ch08-02-strings.md b/second-edition/src/ch08-02-strings.md index 0b4d6e5c1..4c17b3cca 100644 --- a/second-edition/src/ch08-02-strings.md +++ b/second-edition/src/ch08-02-strings.md @@ -1,62 +1,106 @@ -## Strings - -We talked about strings in Chapter 4, but we’ll look at them in more depth now. -New Rustaceans commonly get stuck on strings due to a combination of three -concepts: Rust’s propensity for exposing possible errors, strings being a more -complicated data structure than many programmers give them credit for, and -UTF-8. These concepts combine in a way that can seem difficult when you’re -coming from other programming languages. - -This discussion of strings is in the collections chapter because strings are -implemented as a collection of bytes plus some methods to provide useful -functionality when those bytes are interpreted as text. In this section, we’ll -talk about the operations on `String` that every collection type has, such as -creating, updating, and reading. We’ll also discuss the ways in which `String` -is different than the other collections, namely how indexing into a `String` is -complicated by the differences between how people and computers interpret -`String` data. - -### What Is a String? - -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. - -The `String` type is provided in Rust’s standard library rather than coded into -the core language and is a growable, mutable, owned, UTF-8 encoded string type. -When Rustaceans refer to “strings” in Rust, they usually mean the `String` and -the string slice `&str` types, not just one of those types. Although this -section is largely about `String`, both types are used heavily in Rust’s -standard library and both `String` and string slices are UTF-8 encoded. - -Rust’s standard library also includes a number of other string types, such as -`OsString`, `OsStr`, `CString`, and `CStr`. Library crates can provide even -more options for storing string data. Similar to the `*String`/`*Str` naming, -they often provide an owned and borrowed variant, just like `String`/`&str`. -These string types can store text in different encodings or be represented in -memory in a different way, for example. We won’t discuss these other string -types in this chapter; see their API documentation for more about how to use -them and when each is appropriate. - -### Creating a New String - -Many of the same operations available with `Vec` are available with `String` as -well, starting with the `new` function to create a string, shown in Listing 8-9: + + +## 文字列 + + + + + + + + +第4章で文字列について語りましたが、今度はより掘り下げていきましょう。新参者のRust市民は、 +3つの概念の組み合わせにより、文字列でよく行き詰まります: Rustのありうるエラーを晒す性質、 +多くのプログラマが思っている以上に文字列が複雑なデータ構造であること、そしてUTF-8です。 +これらの概念は、他のプログラミング言語から移ってきた場合、一見困難に見えるように絡み合うわけです。 + + + + + + + + + + +この文字列の議論は、コレクションの章に存在します。なぜなら、文字列はテキストとして解釈された時に有用になる機能を提供するメソッドと、 +バイトの塊で実装されているからです。この節では、生成、更新、読み込みのような全コレクションが持つ`String`の処理について語ります。 +また、`String`が他のコレクションと異なる点についても議論します。具体的には、人間とコンピュータが`String`データを解釈する方法の差異により、 +`String`に添え字アクセスする方法がどう複雑なのかということです。 + + + +### 文字列とは? + + + + + + + + +まずは、*文字列*という用語の意味を定義しましょう。Rustには、言語の核として1種類しか文字列型を持ちません。 +文字列スライスの`str`で、通常借用された形態`&str`で見かけます。第4章で、*文字列スライス*について語りました。 +これは、別の場所に保持されたUTF-8エンコードされた文字列データへの参照です。例えば、文字列リテラルは、 +プログラムのバイナリ出力に保持されるので、文字列スライスになります。 + + + + + + + + +`String`型は、言語の核として組み込まれるのではなく、Rustの標準ライブラリで提供され、伸長可能、 +可変、所有権のあるUTF-8エンコードされた文字列型です。Rust市民がRustにおいて「文字列」を指したら、 +どちらかではなく、`String`と文字列スライスの`&str`のことを通常意味します。この節は、大方、 +`String`型についてですが、どちらの型もRustの標準ライブラリで重宝されており、 +どちらもUTF-8エンコードされています。 + + + + + + + + + + +また、Rustの標準ライブラリには、他の文字列型も含まれています。`OsString`、`OsStr`、`CString`、`CStr`などです。 +ライブラリクレートにより、文字列データを保持する選択肢はさらに増えます。 +`*String`と`*Str`の名前付けに似て、所有権ありと借用されたバージョンがしばしば提供されます。 +ちょうど`String`と`&str`のような関係ですね。例えば、これらの文字列型は、異なるエンコード方法でテキストを保持していたり、 +メモリ上の表現が異なったりします。この章では、これらの他の種類の文字列については議論しません; +使用方法やどれが最適かについては、APIドキュメントを参照してください。 + + + +### 新規文字列を生成する + + + + +`Vec`で使用可能な処理の多くが`String`でも使用できます。文字列を生成する`new`関数から始めましょうか。 +リスト8-9に示したようにね: ```rust let mut s = String::new(); ``` -Listing 8-9: Creating a new, empty `String` + -This line creates a new empty string called `s` that we can then load data -into. Often, we’ll have some initial data that we want to start the string -with. For that, we use the `to_string` method, which is available on any type -that implements the `Display` trait, which string literals do. Listing 8-10 -shows two examples: +リスト8-9: 新しい空の`String`を生成する + + + + + + + +この行は、新しい空の`s`という文字列を生成しています。それからここにデータを読み込むことができるわけです。 +だいたい、文字列の初期値を決めるデータがあるでしょう。そのために、`to_string`メソッドを使用します。 +このメソッドは、`Display`トレイトを実装する型ならなんでも使用でき、文字列リテラルはこれに適合しています。 +リスト8-10に2例、示しています: ```rust let data = "initial contents"; @@ -67,29 +111,45 @@ let s = data.to_string(); let s = "initial contents".to_string(); ``` -Listing 8-10: Using the `to_string` method to create a -`String` from a string literal + + + +リスト8-10: `to_string`メソッドを使用して文字列リテラルから`String`を生成する + + -This code creates a string containing `initial contents`. +このコードは、`initial contents`(初期値)を含む文字列を生成します。 -We can also use the function `String::from` to create a `String` from a string -literal. The code in Listing 8-11 is equivalent to the code from Listing 8-10 -that uses `to_string`: + + + + +さらに、`String::from`関数を使っても、文字列リテラルから`String`を生成することができます。 +リスト8-11のコードは、`to_string`を使用するリスト8-10のコードと等価です: ```rust let s = String::from("initial contents"); ``` -Listing 8-11: Using the `String::from` function to create -a `String` from a string literal + + + +リスト8-11: `String::from`関数を使って文字列リテラルから`String`を作る + + + + + + +文字列は、非常に多くのものに使用されるので、多くの異なる一般的なAPIを使用でき、たくさんの選択肢があるわけです。 +冗長に思われるものもありますが、適材適所です!今回の場合、`String::from`と`to_string`は全く同じことをします。 +従って、どちらを選ぶかは、スタイル次第です。 -Because strings are used for so many things, we can use many different generic -APIs for strings, providing us with a lot of options. Some of them can seem -redundant, but they all have their place! In this case, `String::from` and -`to_string` do the same thing, so which you choose is a matter of style. + + -Remember that strings are UTF-8 encoded, so we can include any properly encoded -data in them, as shown in Listing 8-12: +文字列はUTF-8エンコードされていることを覚えていますか?要するに文字列には、適切にエンコードされていればどんなものでも含めます。 +リスト8-12に示したように: ```rust let hello = String::from("السلام عليكم"); @@ -105,34 +165,55 @@ let hello = String::from("Здравствуйте"); let hello = String::from("Hola"); ``` -Listing 8-12: Storing greetings in different languages in -strings + + -All of these are valid `String` values. +リスト8-12: いろんな言語の挨拶を文字列に保持する -### Updating a String + -A `String` can grow in size and its contents can change, just like the contents -of a `Vec`, by pushing more data into it. In addition, we can conveniently use -the `+` operator or the `format!` macro to concatenate `String` values together. +これらは全て、有効な`String`の値です。 -#### Appending to a String with `push_str` and `push` + -We can grow a `String` by using the `push_str` method to append a string slice, -as shown in Listing 8-13: +### 文字列を更新する + + + + + +`String`は、サイズを伸ばすことができ、中身も変化します。`Vec`の中身のようですね。それは、 +追加のデータをプッシュすることで行います。付け加えると、`String`値を連結する`+`演算子や、 +`format!`マクロを便利に使用することができます。 + + + +#### `push_str`と`push`で文字列に追加する + + + + +`push_str`メソッドで文字列スライスを追記することで、`String`を伸ばすことができます。 +リスト8-13の通りです: ```rust let mut s = String::from("foo"); s.push_str("bar"); ``` -Listing 8-13: Appending a string slice to a `String` -using the `push_str` method + + + +リスト8-13: `push_str`メソッドで`String`に文字列スライスを追記する + + + + + -After these two lines, `s` will contain `foobar`. The `push_str` method takes a -string slice because we don’t necessarily want to take ownership of the -parameter. For example, the code in Listing 8-14 shows that it would be -unfortunate if we weren’t able to use `s2` after appending its contents to `s1`: +この2行の後、`s`は`foobar`を含むことになります。`push_str`メソッドは、必ずしも引数の所有権を得なくていいので、 +文字列スライスを取ります。例えば、リスト8-14のコードは、中身を`s1`に追加した後、 +`s2`を使えなかったら不幸だということを示しています: ```rust let mut s1 = String::from("foo"); @@ -141,79 +222,131 @@ s1.push_str(&s2); println!("s2 is {}", s2); ``` -Listing 8-14: Using a string slice after appending its -contents to a `String` + + -If the `push_str` method took ownership of `s2`, we wouldn’t be able to print -out its value on the last line. However, this code works as we’d expect! +リスト8-14: 中身を`String`に追加した後に、文字列スライスを使用する -The `push` method takes a single character as a parameter and adds it to the -`String`. Listing 8-15 shows code that adds an l to a `String` using the `push` -method: + + + +もし、`push_str`メソッドが`s2`の所有権を奪っていたら、最後の行でその値を出力することは不可能でしょう。 +ところが、このコードは予想通りに動きます! + + + + + +`push`メソッドは、1文字を引数として取り、`String`に追加します。リスト8-15は、 +`push`メソッドでlを`String`に追加するコードを提示しています。 ```rust let mut s = String::from("lo"); s.push('l'); ``` -Listing 8-15: Adding one character to a `String` value -using `push` + + + +リスト8-15: `push`で`String`値に1文字を追加する + + + +このコードの結果、`s`は`lol`を含むことになるでしょう。 + + + +#### `+`演算子、または`format!`マクロで連結 -As a result of this code, `s` will contain `lol`. + + -#### Concatenation with the `+` Operator or the `format!` Macro +2つのすでにある文字列を組み合わせたくなることがよくあります。リスト8-16に示したように、 +一つ目の方法は、`+`演算子を使用することです: -Often, we’ll want to combine two existing strings. One way is to use the `+` -operator, as shown in Listing 8-16: + + + + + ```rust let s1 = String::from("Hello, "); let s2 = String::from("world!"); -let s3 = s1 + &s2; // Note that s1 has been moved here and can no longer be used +let s3 = s1 + &s2; // s1はムーブされ、もう使用できないことに注意 ``` -Listing 8-16: Using the `+` operator to combine two -`String` values into a new `String` value + + -As a result of this code, the string `s3` will contain `Hello, world!`. The -reason `s1` is no longer valid after the addition and the reason we used a -reference to `s2` has to do with the signature of the method that gets called -when we use the `+` operator. The `+` operator uses the `add` method, whose -signature looks something like this: +リスト8-16: `+`演算子を使用して二つの`String`値を新しい`String`値にする + + + + + + + +このコードの結果、`s3`という文字列は、`Hello, world!`を含むことになるでしょう。 +追記の後、`s1`がもう有効でなくなった理由と、`s2`への参照を使用した理由は、 +`+`演算子を使用した時に呼ばれるメソッドのシグニチャと関係があります。`+`演算子は、`add`メソッドを使用し、 +そのシグニチャは以下のような感じです: ```rust,ignore fn add(self, s: &str) -> String { ``` -This isn’t the exact signature that’s in the standard library: in the standard -library, `add` is defined using generics. Here, we’re looking at the signature -of `add` with concrete types substituted for the generic ones, which is what -happens when we call this method with `String` values. We’ll discuss generics -in Chapter 10. This signature gives us the clues we need to understand the -tricky bits of the `+` operator. - -First, `s2` has an `&`, meaning that we’re adding a *reference* of the second -string to the first string because of the `s` parameter in the `add` function: -we can only add a `&str` to a `String`; we can’t add two `String` values -together. But wait - the type of `&s2` is `&String`, not `&str`, as specified -in the second parameter to `add`. Why does Listing 8-16 compile? We are able to -use `&s2` in the call to `add` because the compiler can *coerce* the `&String` -argument into a `&str`. When we call the `add` method, Rust uses something -called a *deref coercion*, which you could think of here as turning `&s2` into -`&s2[..]`. We’ll discuss deref coercion in more depth in Chapter 15. Because -`add` does not take ownership of the `s` parameter, `s2` will still be a valid -`String` after this operation. - -Second, we can see in the signature that `add` takes ownership of `self`, -because `self` does *not* have an `&`. This means `s1` in Listing 8-16 will be -moved into the `add` call and no longer be valid after that. So although `let -s3 = s1 + &s2;` looks like it will copy both strings and create a new one, this -statement actually takes ownership of `s1`, appends a copy of the contents of -`s2`, and then returns ownership of the result. In other words, it looks like -it’s making a lot of copies but isn’t: the implementation is more efficient -than copying. - -If we need to concatenate multiple strings, the behavior of `+` gets unwieldy: + + + + + + + +これは、標準ライブラリにあるシグニチャそのものではありません: 標準ライブラリでは、`add`はジェネリクスで定義されています。 +ここでは、ジェネリックな型を具体的な型に置き換えた`add`のシグニチャを見ており、これは、 +このメソッドを`String`値とともに呼び出した時に起こることです。ジェネリクスについては、第10章で議論します。 +このシグニチャが、`+`演算子の巧妙な部分を理解するのに必要な手がかりになるのです。 + + + + + + + + + + + + + +まず、`s2`には`&`がついてます。つまり、`add`関数の`s`引数のために最初の文字列に2番目の文字列の参照を追加するということです: +`String`には`&str`を追加することしかできません。要するに2つの`String`値を追加することはできないのです。 +でも待ってください。`add`の第2引数で指定されているように、`&s2`の型は、`&str`ではなく、 +`&String`ではないですか。なぜ、リスト8-16は、コンパイルできるのでしょうか?`add`呼び出しで`&s2`を使える理由は、 +コンパイラが`&String`引数を`&str`に*型強制*してくれるためです。`add`メソッド呼び出しの際、 +コンパイラは、*参照外し型強制*というものを使用し、ここでは、`&s2`を`&s2[..]`に変えるものと考えることができます。 +参照外し型強制について詳しくは、第15章で議論します。`add`が`s`引数の所有権を奪わないので、 +この処理後も`s2`が有効な`String`になるわけです。 + + + + + + + + + + +2番目に、シグニチャから`add`は`self`の所有権をもらうことがわかります。`self`には`&`がついてい*ない*からです。 +これはつまり、リスト8-16において`s1`は`add`呼び出しにムーブされ、その後は有効ではなくなるということです。 +故に、`s3 = s1 + &s2;`は両文字列をコピーして新しいものを作るように見えますが、 +この文は実際には`s1`の所有権を奪い、`s2`の中身のコピーを追記し、結果の所有権を返すのです。言い換えると、 +たくさんのコピーをしているように見えますが、違います: 実装は、コピーよりも効率的です。 + + + +複数の文字列を連結する必要が出ると、`+`の振る舞いは扱いにくくなります: ```rust let s1 = String::from("tic"); @@ -223,9 +356,12 @@ let s3 = String::from("toe"); let s = s1 + "-" + &s2 + "-" + &s3; ``` -At this point, `s` will be `tic-tac-toe`. With all of the `+` and `"` -characters, it’s difficult to see what’s going on. For more complicated string -combining, we can use the `format!` macro: + + + + +ここで、`s`は`tic-tac-toe`になるでしょう。`+`と`"`文字のせいで何が起きているのかわかりにくいです。 +もっと複雑な文字列の連結には、`format!`マクロを使用することができます: ```rust let s1 = String::from("tic"); @@ -235,131 +371,202 @@ let s3 = String::from("toe"); let s = format!("{}-{}-{}", s1, s2, s3); ``` -This code also sets `s` to `tic-tac-toe`. The `format!` macro works in the same -way as `println!`, but instead of printing the output to the screen, it returns -a `String` with the contents. The version of the code using `format!` is much -easier to read and also doesn’t take ownership of any of its parameters. + + + + + +このコードでも、`s`は`tic-tac-toe`になります。`format!`マクロは、`println!`と同様の動作をしますが、 +出力をスクリーンに行う代わりに、中身を`String`で返すのです。`format!`を使用したコードの方がはるかに読みやすく、 +引数の所有権を奪うこともありません。 -### Indexing into Strings + -In many other programming languages, accessing individual characters in a -string by referencing them by index is a valid and common operation. However, -if we try to access parts of a `String` using indexing syntax in Rust, we’ll -get an error. Consider the code in Listing 8-17: +### 文字列に添え字アクセスする + + + + + + +他の多くのプログラミング言語では、文字列中の文字に、番号で参照してアクセスすることは、有効なコードであり、 +一般的な処理です。しかしながら、Rustにおいて、添え字記法で`String`の一部にアクセスしようとすると、 +エラーが発生するでしょう。リスト8-17のコードを考えてください: ```rust,ignore let s1 = String::from("hello"); let h = s1[0]; ``` -Listing 8-17: Attempting to use indexing syntax with a -String + + + +リスト8-17: 文字列に対して添え字記法を試みる -This code will result in the following error: + + +このコードは、以下のようなエラーに落ち着きます: ```text error: the trait bound `std::string::String: std::ops::Index<_>` is not satisfied [--explain E0277] +(エラー: トレイト境界`std::string::String: std::ops::Index<_>`が満たされていません) |> |> let h = s1[0]; |> ^^^^^ note: the type `std::string::String` cannot be indexed by `_` +(注釈: 型`std::string::String`は`_`で添え字アクセスできません) ``` -The error and the note tell the story: Rust strings don’t support indexing. But -why not? To answer that question, we need to discuss how Rust stores strings in -memory. + + + + +エラーと注釈が全てを物語っています: Rustの文字列は、添え字アクセスをサポートしていないのです。 +でも、なぜでしょうか?その疑問に答えるには、Rustがメモリにどのように文字列を保持しているかについて議論する必要があります。 + + + +#### 内部表現 -#### Internal Representation + + -A `String` is a wrapper over a `Vec`. Let’s look at some of our properly -encoded UTF-8 example strings from Listing 8-12. First, this one: +`String`は`Vec`のラッパです。リスト8-12から適切にUTF-8でエンコードされた文字列の例をご覧ください。 +まずは、これ: ```rust let len = String::from("Hola").len(); ``` -In this case, `len` will be four, which means the `Vec` storing the string -“Hola” is four bytes long. Each of these letters takes one byte when encoded in -UTF-8. But what about the following line? + + + + +この場合、`len`は4になり、これは、文字列"Hola"を保持する`Vec`の長さが4バイトであることを意味します。 +これらの各文字は、UTF-8でエンコードすると、1バイトになるのです。しかし、以下の行ではどうでしょうか? ```rust let len = String::from("Здравствуйте").len(); ``` -Asked how long the string is, you might say 12. However, Rust’s answer is 24: -that’s the number of bytes it takes to encode “Здравствуйте” in UTF-8, because -each Unicode scalar value takes two bytes of storage. Therefore, an index into -the string’s bytes will not always correlate to a valid Unicode scalar value. -To demonstrate, consider this invalid Rust code: + + + + + + +文字列の長さはと問われたら、あなたは12と答えるかもしれません。ところが、Rustの答えは、24です: +“Здравствуйте”をUTF-8でエンコードすると、この長さになります。各Unicodeスカラー値は、2バイトの領域を取るからです。 +それ故に、文字列のバイト番号は、必ずしも有効なUnicodeのスカラー値とは相互に関係しないのです。 +デモ用に、こんな無効なRustコードを考えてください: ```rust,ignore let hello = "Здравствуйте"; let answer = &hello[0]; ``` -What should the value of `answer` be? Should it be `З`, the first letter? When -encoded in UTF-8, the first byte of `З` is `208`, and the second is `151`, so -`answer` should in fact be `208`, but `208` is not a valid character on its -own. Returning `208` is likely not what a user would want if they asked for the -first letter of this string; however, that’s the only data that Rust has at -byte index 0. Returning the byte value is probably not what users want, even if -the string contains only Latin letters: if `&"hello"[0]` was valid code that -returned the byte value, it would return `104`, not `h`. To avoid returning an -unexpected value and causing bugs that might not be discovered immediately, -Rust doesn’t compile this code at all and prevents misunderstandings earlier in -the development process. + + + + + + + + + + + + +`answer`の値は何になるべきでしょうか?最初の文字の`З`になるべきでしょうか?UTF-8エンコードされた時、 +`З`の最初のバイトは`208`、2番目は`151`になるので、`answer`は実際、`208`になるべきですが、 +`208`は単独では有効な文字ではありません。この文字列の最初の文字を求めている場合、`208`を返すことは、 +ユーザの望んでいるものではないでしょう; しかしながら、Rustには、番号0の位置には、そのデータしかないのです。 +バイト値を返すことは、文字列がラテン文字のみを含む場合でも、おそらくユーザが望むものではないでしょう: +`&"hello"[0]`がバイト値を返す有効なコードだったら、`h`ではなく、`104`を返すでしょう。 +予期しない値を返し、すぐには判明しないバグを引き起こさないために、Rustはこのコードを全くコンパイルせず、 +開発作業の早い段階で誤解を防いでくれるのです。 + + -#### Bytes and Scalar Values and Grapheme Clusters! Oh My! +#### バイトとスカラー値と書記素クラスタ!なんてこった! -Another point about UTF-8 is that there are actually three relevant ways to -look at strings from Rust’s perspective: as bytes, scalar values, and grapheme -clusters (the closest thing to what we would call *letters*). + + + -If we look at the Hindi word “नमस्ते” written in the Devanagari script, it is -ultimately stored as a `Vec` of `u8` values that looks like this: +UTF-8について別の要点は、実際Rustの観点から文字列を見るには3つの関連した方法があるということです: +バイトとして、スカラー値として、そして、書記素クラスタ(人間が*文字*と呼ぶものに一番近い)としてです。 + + + + +ヒンディー語の単語、“नमस्ते”をデーヴァナーガリー(`脚注`: サンスクリット語とヒンディー語を書くときに使われる書記法)で表記したものを見たら、 +最終的に以下のような見た目の`u8`値の`Vec`として保持されます: ```text [224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164, 224, 165, 135] ``` -That’s 18 bytes and is how computers ultimately store this data. If we look at -them as Unicode scalar values, which are what Rust’s `char` type is, those -bytes look like this: + + + + +18バイトになり、このようにしてコンピュータは最終的にこのデータを保持しているわけです。これをUnicodeスカラー値として見たら、 +Rustの`char`型はこれなのですが、このバイトは以下のような見た目になります: ```text ['न', 'म', 'स', '्', 'त', 'े'] ``` -There are six `char` values here, but the fourth and sixth are not letters: -they’re diacritics that don’t make sense on their own. Finally, if we look at -them as grapheme clusters, we’d get what a person would call the four letters -that make up the Hindi word: + + + + + +ここでは、6つ`char`値がありますが、4番目と6番目は文字ではありません: 単独では意味をなさないダイアクリティックです。 +最後に、書記素クラスタとして見たら、このヒンディー語の単語を作り上げる人間が4文字と呼ぶであろうものが得られます: ```text ["न", "म", "स्", "ते"] ``` -Rust provides different ways of interpreting the raw string data that computers -store so that each program can choose the interpretation it needs, no matter -what human language the data is in. + + + + +Rustには、データが表す自然言語に関わらず、各プログラムが必要な解釈方法を選択できるように、 +コンピュータが保持する生の文字列データを解釈する方法がいろいろ用意されています。 + + + + + + + +Rustで文字を得るのに`String`に添え字アクセスすることが許されない最後の理由は、 +添え字アクセスという処理が常に定数時間(O(1))になると期待されるからです。 +しかし、`String`でそのパフォーマンスを保証することはできません。というのも、 +有効な文字がいくつあるか決定するのに、最初から番号まで中身を走査する必要があるからです。 -A final reason Rust doesn’t allow us to index into a `String` to get a -character is that indexing operations are expected to always take constant time -(O(1)). But it isn’t possible to guarantee that performance with a `String`, -because Rust would have to walk through the contents from the beginning to the -index to determine how many valid characters there were. + -### Slicing Strings +### 文字列をスライスする -Indexing into a string is often a bad idea because it’s not clear what the -return type of the string indexing operation should be: a byte value, a -character, a grapheme cluster, or a string slice. Therefore, Rust asks you to -be more specific if you really need to use indices to create string slices. To -be more specific in your indexing and indicate that you want a string slice, -rather than indexing using `[]` with a single number, you can use `[]` with a -range to create a string slice containing particular bytes: + + + + + + + + +文字列に添え字アクセスするのは、しばしば悪い考えです。文字列添え字処理の戻り値の型が明瞭ではないからです: +バイト値、文字、書記素クラスタ、あるいは文字列スライスにもなります。故に、文字列スライスを生成するのに、 +添え字を使う必要が本当に出た場合にコンパイラは、もっと特定するよう求めてきます。添え字アクセスを特定し、 +文字列スライスが欲しいと示唆するためには、`[]`で1つの数値により添え字アクセスするのではなく、 +範囲とともに`[]`を使って、特定のバイトを含む文字列スライスを作ることができます: ```rust let hello = "Здравствуйте"; @@ -367,29 +574,46 @@ let hello = "Здравствуйте"; let s = &hello[0..4]; ``` -Here, `s` will be a `&str` that contains the first four bytes of the string. -Earlier, we mentioned that each of these characters was two bytes, which means -`s` will be `Зд`. + + + + +ここで、`s`は文字列の最初の4バイトを含む`&str`になります。先ほど、これらの文字は各々2バイトになると指摘しましたから、 +`s`は`Зд`になります。 -What would happen if we used `&hello[0..1]`? The answer: Rust will panic at -runtime in the same way that accessing an invalid index in a vector does: + + + +`&hello[0..1]`と使用したら、何が起きるでしょうか?答え: Rustはベクタの無効な番号にアクセスした時のように、 +実行時にパニックするでしょう: ```text thread 'main' panicked at 'index 0 and/or 1 in `Здравствуйте` do not lie on character boundary', ../src/libcore/str/mod.rs:1694 +('main'スレッドは「番号0かつ/または1は`Здравствуйте`において文字境界になっていません」でパニックしました) ``` -You should use ranges to create string slices with caution, because it can -crash your program. + + + +範囲を使用して文字列スライスを作る際にはプログラムをクラッシュさせる可能性があるので、気をつけるべきです。 -### Methods for Iterating Over Strings + -Fortunately, we can access elements in a string in other ways. +### 文字列を操作するメソッド群 -If we need to perform operations on individual Unicode scalar values, the best -way to do so is to use the `chars` method. Calling `chars` on “नमस्ते” separates -out and returns six values of type `char`, and you can iterate over the result -in order to access each element: + + +幸いなことに、他の方法でも文字列の要素にアクセスすることができます。 + + + + + + +もし、個々のUnicodeスカラー値に対して処理を行う必要があったら、最適な方法は`chars`メソッドを使用するものです。 +“नमस्ते”に対して`chars`を呼び出したら、分解して6つの`char`型の値を返すので、各要素にアクセスするには、 +その結果を走査すればいいわけです: ```rust for c in "नमस्ते".chars() { @@ -397,7 +621,9 @@ for c in "नमस्ते".chars() { } ``` -This code will print the following: + + +このコードは、以下のように出力します: ```text न @@ -408,8 +634,10 @@ This code will print the following: े ``` -The `bytes` method returns each raw byte, which might be appropriate for your -domain: + + + +`bytes`メソッドは、各バイトをそのまま返すので、最適になることもあるかもしれません: ```rust for b in "नमस्ते".bytes() { @@ -417,7 +645,9 @@ for b in "नमस्ते".bytes() { } ``` -This code will print the 18 bytes that make up this `String`, starting with: + + +このコードは、`String`をなす18バイトを出力し、こう始まります: ```text 224 @@ -427,22 +657,37 @@ This code will print the 18 bytes that make up this `String`, starting with: // ... etc ``` -But be sure to remember that valid Unicode scalar values may be made up of more -than one byte. + + + +ですが、有効なUnicodeスカラー値は、2バイト以上からなる場合もあることは心得ておいてください。 + + + + + +書記素クラスタを文字列から得る方法は複雑なので、この機能は標準ライブラリでは提供されていません。 +この機能が必要なら、[crates.io](https://crates.io)でクレートを入手可能です。 + + + +### 文字列はそう単純じゃない -Getting grapheme clusters from strings is complex, so this functionality is not -provided by the standard library. Crates are available on -[crates.io](https://crates.io) if this is the functionality you need. + + + + + + + + -### Strings Are Not So Simple +まとめると、文字列は複雑です。プログラミング言語ごとにこの複雑性をプログラマに提示する方法は違います。 +Rustでは、`String`データを正しく扱うことが全てのRustプログラムにとっての規定動作になっているわけであり、 +これは、プログラマがUTF-8データを素直に扱う際により思考しないといけないことを意味します。 +このトレードオフにより、他のプログラミング言語よりも文字列の複雑性がより露出していますが、 +ASCII以外の文字に関するエラーを開発の後半で扱わなければならない可能性を排除してくれているのです。 -To summarize, strings are complicated. Different programming languages make -different choices about how to present this complexity to the programmer. Rust -has chosen to make the correct handling of `String` data the default behavior -for all Rust programs, which means programmers have to put more thought into -handling UTF-8 data upfront. This trade-off exposes more of the complexity of -strings than other programming languages do but prevents you from having to -handle errors involving non-ASCII characters later in your development life -cycle. + -Let’s switch to something a bit less complex: hash maps! +もう少し複雑でないものに切り替えていきましょう: ハッシュマップです! From 0588794c6f560cff144faaf4e02b92d09a7a70b5 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 21 Sep 2017 23:04:16 +0900 Subject: [PATCH 052/428] Very first draft of the chapter 8-3(I didn't even look through it) --- second-edition/src/ch08-02-strings.md | 4 +- second-edition/src/ch08-03-hash-maps.md | 485 ++++++++++++++++-------- 2 files changed, 322 insertions(+), 167 deletions(-) diff --git a/second-edition/src/ch08-02-strings.md b/second-edition/src/ch08-02-strings.md index 4c17b3cca..e7df6e41c 100644 --- a/second-edition/src/ch08-02-strings.md +++ b/second-edition/src/ch08-02-strings.md @@ -682,8 +682,8 @@ for b in "नमस्ते".bytes() { -まとめると、文字列は複雑です。プログラミング言語ごとにこの複雑性をプログラマに提示する方法は違います。 -Rustでは、`String`データを正しく扱うことが全てのRustプログラムにとっての規定動作になっているわけであり、 +まとめると、文字列は込み入っています。プログラミング言語ごとにこの複雑性をプログラマに提示する方法は違います。 +Rustでは、`String`データを正しく扱うことが、全てのRustプログラムにとっての規定動作になっているわけであり、 これは、プログラマがUTF-8データを素直に扱う際により思考しないといけないことを意味します。 このトレードオフにより、他のプログラミング言語よりも文字列の複雑性がより露出していますが、 ASCII以外の文字に関するエラーを開発の後半で扱わなければならない可能性を排除してくれているのです。 diff --git a/second-edition/src/ch08-03-hash-maps.md b/second-edition/src/ch08-03-hash-maps.md index 6ac862a32..1e08b0fe2 100644 --- a/second-edition/src/ch08-03-hash-maps.md +++ b/second-edition/src/ch08-03-hash-maps.md @@ -1,28 +1,48 @@ -## Hash Maps + -The last of our common collections is the *hash map*. The type `HashMap` -stores a mapping of keys of type `K` to values of type `V`. It does this via a -*hashing function*, which determines how it places these keys and values into -memory. Many different programming languages support this kind of data -structure, but often use a different name, such as hash, map, object, hash -table, or associative array, just to name a few. +## ハッシュマップ -Hash maps are useful for when you want to look up data not by an index, as you -can with vectors, but by using a key that can be of any type. For example, in a -game, you could keep track of each team’s score in a hash map where each key is -a team’s name and the values are each team’s score. Given a team name, you can -retrieve its score. + + + + + + -We’ll go over the basic API of hash maps in this section, but many more goodies -are hiding in the functions defined on `HashMap` by the standard library. -As always, check the standard library documentation for more information. +一般的なコレクションのトリを飾るのは、*ハッシュマップ*です。型`HashMap`は、 +`K`型のキーと`V`型の値の対応関係を保持します。これを*ハッシュ関数*を介して行います。 +これは、キーと値のメモリ配置方法を決めるものです。色々なプログラミング言語でもこの種のデータ構造はサポートされていますが、 +しばしば名前が違います。hash、map、object、ハッシュテーブル、連想配列など、枚挙に(いとま)はありません。 -### Creating a New Hash Map + + + + + -We can create an empty hash map with `new` and add elements with `insert`. In -Listing 8-18, we’re keeping track of the scores of two teams whose names are -Blue and Yellow. The Blue team will start with 10 points, and the Yellow team -starts with 50: +ハッシュマップは、ベクタで可能なように番号ではなく、どんな型にもなりうるキーを使ってデータを参照したいときに有用です。 +例えば、ゲームにおいて、各チームのスコアをハッシュマップで追いかけることができます。ここで、各キーはチーム名、 +値が各チームのスコアになります。チーム名が与えられれば、スコアを扱うことができるわけです。 + + + + + +この説でマッシュマップの基礎的なAPIを見ていきますが、より多くのグッズが標準ライブラリにより、 +`HashMap`状に定義された関数に隠されています。いつものように、 +もっと情報が欲しければ、標準ライブラリのドキュメントをチェックしてください。 + + + +### 新規ハッシュマップを生成する + + + + + + +空のハッシュマップを`new`で作り、要素を`insert`で追加することができます。リスト8-18では、 +名前がブルーとイエローの2チームのスコアを追いかけています。ブルーチーム10点から、イエローチームは50点から始まります: ```rust use std::collections::HashMap; @@ -33,27 +53,43 @@ scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); ``` -Listing 8-18: Creating a new hash map and inserting some -keys and values + + + +リスト8-18: ハッシュマップを生成してキーと値を挿入する + + + + + + + +最初に標準ライブラリからコレクション部分の`HashMap`を`use`する必要があることに注意してください。 +今までの3つの一般的なコレクションの内、これが最も使用頻度が低いので、初期化処理で自動的にインポートされる機能には含まれていません。 +また、標準ライブラリからのサポートもハッシュマップは少ないです; 例えば、生成するための組み込みマクロがありません。 -Note that we need to first `use` the `HashMap` from the collections portion of -the standard library. Of our three common collections, this one is the least -often used, so it’s not included in the features imported automatically in the -prelude. Hash maps also have less support from the standard library; there’s no -built-in macro to construct them, for example. + + + + -Just like vectors, hash maps store their data on the heap. This `HashMap` has -keys of type `String` and values of type `i32`. Like vectors, hash maps are -homogeneous: all of the keys must have the same type, and all of the values -must have the same type. +ベクタと全く同様に、ハッシュマップはデータをヒープに保持します。この`HashMap`はキーが`String`型、 +値は`i32`型です。ベクタのように、ハッシュマップは均質です: キーは全て同じ型でなければならず、 +値も全て同じ型でなければなりません。 -Another way of constructing a hash map is by using the `collect` method on a -vector of tuples, where each tuple consists of a key and its value. The -`collect` method gathers data into a number of collection types, including -`HashMap`. For example, if we had the team names and initial scores in two -separate vectors, we can use the `zip` method to create a vector of tuples -where “Blue” is paired with 10, and so forth. Then we can use the `collect` -method to turn that vector of tuples into a `HashMap` as shown in Listing 8-19: + + + + + + + + +ハッシュマップを生成する別の方法は、タプルのベクタに対して`collect`メソッドを使用するものです。 +ここで、各タプルは、キーと値から構成されています。`collect`メソッドはいろんなコレクション型にデータをまとめ上げ、 +そこには`HashMap`も含まれています。例として、チームメイト初期スコアが別々のベクタに含まれていたら、 +`zip`メソッドを使ってタプルのベクタを作り上げることができ、そこでは「ブルー」は10とペアになるなどします。 +リスト8-19に示したように、それから`collect`メソッドを使って、そのタプルのベクタを`HashMap`に変換することができるわけです: ```rust use std::collections::HashMap; @@ -64,20 +100,32 @@ let initial_scores = vec![10, 50]; let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect(); ``` -Listing 8-19: Creating a hash map from a list of teams -and a list of scores + + + +リスト8-19: チームのリストとスコアのリストからハッシュマップを作る + + + + + + + +ここでは、`HashMap<_, _>`という型注釈が必要になります。なぜなら、いろんなデータ構造に`まとめ上げる`ことができ、 +コンパイラは指定しない限りどれがいるのかわからないからです。ところが、キーと値の型引数については、 +アンダースコアを使用しており、コンパイラはベクタのデータ型に基づいてハッシュマップが含む型を推論することができるのです。 + + -The type annotation `HashMap<_, _>` is needed here because it’s possible to -`collect` into many different data structures, and Rust doesn’t know which you -want unless you specify. For the type parameters for the key and value types, -however, we use underscores, and Rust can infer the types that the hash map -contains based on the types of the data in the vectors. +### ハッシュマップと所有権 -### Hash Maps and Ownership + + + -For types that implement the `Copy` trait, like `i32`, the values are copied -into the hash map. For owned values like `String`, the values will be moved and -the hash map will be the owner of those values as demonstrated in Listing 8-20: +`i32`のような`Copy`トレイトを実装する型について、値はハッシュマップにコピーされます。 +`String`のような所有権のある値なら、値はムーブされ、リスト8-20でデモされているように、 +ハッシュマップはそれらの値の所有者になるでしょう: ```rust use std::collections::HashMap; @@ -89,23 +137,38 @@ let mut map = HashMap::new(); 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はこの時点で無効になる。試しに使ってみて +// どんなコンパイルエラーが出るか確認してみて! ``` -Listing 8-20: Showing that keys and values are owned by -the hash map once they’re inserted + + + +リスト8-20: 一旦挿入されたら、キーと値はハッシュマップに所有されることを示す + + + + +`insert`を呼び出して`field_name`と`field_value`がハッシュマップにムーブされた後は、 +これらの変数を使用することは叶いません。 + + + + + -We aren’t able to use the variables `field_name` and `field_value` after -they’ve been moved into the hash map with the call to `insert`. +値への参照をハッシュマップに挿入したら、値はハッシュマップにムーブされません。参照が指している値は、 +最低でもハッシュマップが有効な間は、有効でなければなりません。これらの問題について詳細には、 +第10章の「ライフタイムで参照を有効化する」節で語ります。 -If we insert references to values into the hash map, the values won’t be moved -into the hash map. The values that the references point to must be valid for at -least as long as the hash map is valid. We’ll talk more about these issues in -the “Validating References with Lifetimes” section in Chapter 10. + -### Accessing Values in a Hash Map +### ハッシュマップの値にアクセスする -We can get a value out of the hash map by providing its key to the `get` method -as shown in Listing 8-21: + + + +リスト8-21に示したように、キーを`get`メソッドに提供することで、ハッシュマップから値を取り出すことができます: ```rust use std::collections::HashMap; @@ -119,17 +182,25 @@ let team_name = String::from("Blue"); let score = scores.get(&team_name); ``` -Listing 8-21: Accessing the score for the Blue team -stored in the hash map + + + +リスト8-21: ハッシュマップに保持されたブルーチームのスコアにアクセスする + + + + + + -Here, `score` will have the value that’s associated with the Blue team, and the -result will be `Some(&10)`. The result is wrapped in `Some` because `get` -returns an `Option<&V>`; if there’s no value for that key in the hash map, -`get` will return `None`. The program will need to handle the `Option` in one -of the ways that we covered in Chapter 6. +ここで、`score`はブルーチームに紐づけられた値になり、結果は`Some(&10)`となるでしょう。 +結果は`Some`に包まれます。というのも、`get`は`Option<&V>`を返すからです; キーに対応する値がハッシュマップになかったら、 +`get`は`None`を返すでしょう。プログラムは、この`Option`を第6章で解説した方法のどれかで扱う必要があるでしょう。 -We can iterate over each key/value pair in a hash map in a similar manner as we -do with vectors, using a `for` loop: + + + +ベクタでしたように、`for`ループでハッシュマップのキーと値のペアを走査することができます: ```rust use std::collections::HashMap; @@ -144,31 +215,47 @@ for (key, value) in &scores { } ``` -This code will print each pair in an arbitrary order: + + +このコードは、各ペアを任意の順番で出力します: ```text Yellow: 50 Blue: 10 ``` -### Updating a Hash Map + + +### ハッシュマップを更新する + + + + + + + + + + +キーと値の数は伸長可能なものの、各キーには1回に1つの値しか紐づけることができません。 +ハッシュマップ内のデータを変えたい時は、すでにキーに値が紐づいている場合の扱い方を決めなければなりません。 +古い値を新しい値で置き換えて、古い値を完全に無視することもできます。古い値を保持して、 +新しい値を無視し、キーにまだ値が*ない*場合に新しい値を追加するだけにすることもできます。 +あるいは、古い値と新しい値を組み合わせることもできます。各方法について見ていきましょう! + + -Although the number of keys and values is growable, each key can only have one -value associated with it at a time. When we want to change the data in a hash -map, we have to decide how to handle the case when a key already has a value -assigned. We could replace the old value with the new value, completely -disregarding the old value. We could keep the old value and ignore the new -value, and only add the new value if the key *doesn’t* already have a value. Or -we could combine the old value and the new value. Let’s look at how to do each -of these! +#### 値を上書きする -#### Overwriting a Value + + + + + -If we insert a key and a value into a hash map, and then insert that same key -with a different value, the value associated with that key will be replaced. -Even though the code in Listing 8-22 calls `insert` twice, the hash map will -only contain one key/value pair because we’re inserting the value for the Blue -team’s key both times: +キーと値をハッシュマップに挿入し、同じキーを異なる値で挿入したら、そのキーに紐づけられている値は置換されます。 +リスト8-22のコードは、`insert`を二度呼んでいるものの、ハッシュマップには一つのキーと値の組みしか含まれません。 +なぜなら、ブルーチームキーに対する値を2回とも挿入しているからです: ```rust use std::collections::HashMap; @@ -181,22 +268,34 @@ scores.insert(String::from("Blue"), 25); println!("{:?}", scores); ``` -Listing 8-22: Replacing a value stored with a particular -key + + -This code will print `{"Blue": 25}`. The original value of `10` has been -overwritten. +リスト8-22: 特定のキーで保持された値を置き換える -#### Only Insert If the Key Has No Value + + -It’s common to check whether a particular key has a value, and if it doesn’t, -insert a value for it. Hash maps have a special API for this called `entry` -that takes the key we want to check as a parameter. The return value of the -`entry` function is an enum called `Entry` that represents a value that might -or might not exist. Let’s say we want to check whether the key for the Yellow -team has a value associated with it. If it doesn’t, we want to insert the value -50, and the same for the Blue team. Using the `entry` API, the code looks like -Listing 8-23: +このコードは、`{"Blue": 25}`と出力するでしょう。`10`という元の値は上書きされたのです。 + + + +#### キーに値がなかった時のみ挿入する + + + + + + + + + + +特定のキーに値があるか確認することは一般的であり、存在しない時に値を挿入することも一般的です。 +ハッシュマップには、これを行う`entry`と呼ばれる特別なAPIがあり、これは、引数としてチェックしたいキーを取ります。 +この`entry`関数の戻り値は、`Entry`と呼ばれるenumであり、これは存在したりしなかったりするかもしれない値を表します。 +イエローチームに対するキーに値が紐づけられているか否か確認したくなったとしましょう。存在しなかったら、 +50という値を挿入したく、ブルーチームに対しても同様です。`entry`APIを使用すれば、コードはリスト8-23のようになります: ```rust use std::collections::HashMap; @@ -210,29 +309,46 @@ scores.entry(String::from("Blue")).or_insert(50); println!("{:?}", scores); ``` -Listing 8-23: Using the `entry` method to only insert if -the key does not already have a value + + + +リスト8-23: `entry`メソッドを使ってキーに値がない場合だけ挿入する + + + + + + + +`Entry`上の`or_insert`メソッドは、対応する`Entry`キーが存在した時にそのキーに対する値を返すために定義されており、 +もしなかったら、引数をこのキーの新しい値として挿入し、変更された`Entry`を返します。このテクニックの方が、 +そのロジックを自分で書くよりもはるかに綺麗な上に、borrow checkerとも親和性が高くなります。 + + + + + + + +リスト8-23のコードを実行すると、`{"Yellow": 50, "Blue": 10}`と出力するでしょう。 +最初の`entry`呼び出しは、まだイエローチームに対する値がないので、値`50`でイエローチームのキーを挿入します。 +`entry`の2回目の呼び出しはハッシュマップを変更しません。なぜなら、ブルーチームはすでに`10`という値があるからです。 -The `or_insert` method on `Entry` is defined to return the value for the -corresponding `Entry` key if that key exists, and if not, inserts the parameter -as the new value for this key and returns the modified `Entry`. This technique -is much cleaner than writing the logic ourselves, and in addition, plays more -nicely with the borrow checker. + -Running the code in Listing 8-23 will print `{"Yellow": 50, "Blue": 10}`. The -first call to `entry` will insert the key for the Yellow team with the value -`50` because the Yellow team doesn’t have a value already. The second call to -`entry` will not change the hash map because the Blue team already has the -value `10`. +#### 古い値に基づいて値を更新する -#### Updating a Value Based on the Old Value + + + + + + -Another common use case for hash maps is to look up a key’s value and then -update it based on the old value. For instance, Listing 8-24 shows code that -counts how many times each word appears in some text. We use a hash map with -the words as keys and increment the value to keep track of how many times we’ve -seen that word. If it’s the first time we’ve seen a word, we’ll first insert -the value `0`: +ハッシュマップの別の一般的なユースケースは、キーの値を探し、古い値に基づいてそれを更新することです。 +例えば、リスト8-24は、各単語があるテキストに何回出現するかをかぞえあげるコードを示しています。 +キーに単語を入れたハッシュマップを使用し、その単語を何回見かけたか追いかけるために値を増やします。 +ある単語を見かけたのが最初だったら、まず`0`という値を挿入します: ```rust use std::collections::HashMap; @@ -249,51 +365,90 @@ for word in text.split_whitespace() { println!("{:?}", map); ``` -Listing 8-24: Counting occurrences of words using a hash -map that stores words and counts - -This code will print `{"world": 2, "hello": 1, "wonderful": 1}`. The -`or_insert` method actually returns a mutable reference (`&mut V`) to the value -for this key. Here we store that mutable reference in the `count` variable, so -in order to assign to that value we must first dereference `count` using the -asterisk (`*`). The mutable reference goes out of scope at the end of the `for` -loop, so all of these changes are safe and allowed by the borrowing rules. - -### Hashing Function - -By default, `HashMap` uses a cryptographically secure hashing function that can -provide resistance to Denial of Service (DoS) attacks. This is not the fastest -hashing algorithm available, but the trade-off for better security that comes -with the drop in performance is worth it. If you profile your code and find -that the default hash function is too slow for your purposes, you can switch to -another function by specifying a different *hasher*. A hasher is a type that -implements the `BuildHasher` trait. We’ll talk about traits and how to -implement them in Chapter 10. You don’t necessarily have to implement your own -hasher from scratch; [crates.io](https://crates.io) has libraries shared by -other Rust users that provide hashers implementing many common hashing -algorithms. - -## Summary - -Vectors, strings, and hash maps will provide a large amount of functionality -that you need in programs where you need to store, access, and modify data. -Here are some exercises you should now be equipped to solve: - -* Given a list of integers, use a vector and return the mean (average), median - (when sorted, the value in the middle position), and mode (the value that - occurs most often; a hash map will be helpful here) of the list. -* Convert strings to pig latin. The first consonant of each word is moved to - the end of the word and “ay” is added, so “first” becomes “irst-fay.” Words - that start with a vowel have “hay” added to the end instead (“apple” becomes - “apple-hay”). Keep in mind the details about UTF-8 encoding! -* Using a hash map and vectors, create a text interface to allow a user to add - employee names to a department in a company. For example, “Add Sally to - Engineering” or “Add Amir to Sales.” Then let the user retrieve a list of all - people in a department or all people in the company by department, sorted - alphabetically. - -The standard library API documentation describes methods that vectors, strings, -and hash maps have that will be helpful for these exercises! - -We’re getting into more complex programs in which operations can fail; so, it’s -a perfect time to discuss error handling next! + + + +単語とカウントを保持するハッシュマップを使って単語の出現数をカウントする + + + + + + + + +このコードは、`{"world": 2, "hello": 1, "wonderful": 1}`と出力するでしょう。 +`or_insert`関数は実際、このキーに対する値への可変参照(`&mut V`)を返すのです。 +ここでその可変参照を`count`変数に保持しているので、その値に代入するには、 +まずアスタリスク(`*`)で`count`を参照外ししなければならないのです。この可変参照は、 +`for`ループの終端でスコープを抜けるので、これらの変更は全て安全であり、借用規則により許可されるのです。 + + + +### ハッシュ関数 + + + + + + + + + + + + + +標準では、`HashMap`はサービス拒否(DoS)アタックに対して抵抗を示す暗号学的に安全なハッシュ関数を使用します。 +これは、利用可能な最速のハッシュアルゴリズムではありませんが、パフォーマンスの欠落と引き換えに安全性を得るというトレードオフは、 +価値があります。自分のコードをプロファイリングして、自分の目的では標準のハッシュ関数は遅すぎると判明したら、 +異なる*hasher*を指定することで別の関数に切り替えることができます。hasherとは、 +`BuildeHasher`トレイトを実装する型のことです。トレイトについてとその実装方法については、第10章で語ります。 +必ずしも独自のhasherを1から作り上げる必要はありません; [crates.io](https://crates.io)には、 +他のRustユーザによって共有された多くの一般的なハッシュアルゴリズムを実装したhasherを提供するライブラリがあります。 + + + +## まとめ + + + + + +ベクタ、文字列、ハッシュマップはデータを保持し、アクセスし、変更する必要のあるプログラムで必要になる、 +多くの機能を提供してくれるでしょう。今なら解決可能なはずの練習問題を用意しました: + + + + + + + + + + + + + + +* 整数のリストが与えられ、ベクタを使ってmean(平均)、median(ソートされた時に真ん中に来る値)、 +mode(最も頻繁に出現する値; ハッシュマップがここでは有効活用できるでしょう)を返してください。 +* 文字列をピッグ・ラテン(`脚注`: 英語の言葉遊びの一つ)に変換してください。各単語の最初の子音は、 +単語の終端に移り、"ay"が足されます。従って、"first"は"irst-fay"になります。ただし、 +母音で始まる単語にはお尻に"hay"が付け足されます("apple"は"apple-hay"になります)。 +UTF-8エンコードに関する詳細を心に留めておいてください! +* ハッシュマップとベクタを使用して、ユーザに会社の部署に雇用者の名前を追加させられるテキストインターフェイスを作ってください。 +例えば、"Add Sally to Engineering"(開発部門にサリーを追加)や"Add Amir to Sales"(販売部門にアミールを追加)などです。 +それからユーザにある部署にいる人間の一覧や部署ごとにアルファベット順で並べ替えられた会社の全人間の一覧を、 +扱わせてあげてください。 + + + + +標準ライブラリのAPIドキュメントには、この練習問題に有用な、ベクタ、文字列、ハッシュマップのメソッドが解説されています。 + + + + +処理が失敗する可能性のあるようなより複雑なプログラムに入り込んできています; ということは、 +次にエラーの処理法について議論するのにぴったりということですね! From aaeaffb0bc6ea33f9b97dc75bfcdcf2927a55352 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 22 Sep 2017 19:07:41 +0900 Subject: [PATCH 053/428] First draft of the chapter 8-3 and make some small changes on the chapters 5, 6-0, 6-1, and 6-2 --- .../src/ch05-01-defining-structs.md | 2 +- second-edition/src/ch05-02-example-structs.md | 2 +- second-edition/src/ch05-03-method-syntax.md | 2 +- second-edition/src/ch06-00-enums.md | 6 ++--- .../src/ch06-01-defining-an-enum.md | 20 ++++++++--------- second-edition/src/ch06-02-match.md | 4 ++-- second-edition/src/ch08-03-hash-maps.md | 22 +++++++++---------- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/second-edition/src/ch05-01-defining-structs.md b/second-edition/src/ch05-01-defining-structs.md index b1fa1c181..4781dee70 100644 --- a/second-edition/src/ch05-01-defining-structs.md +++ b/second-edition/src/ch05-01-defining-structs.md @@ -393,7 +393,7 @@ let origin = Point(0, 0, 0); > > 構造体に、他の何かに所有されたデータへの参照を保持させることもできますが、 > そうするには*ライフタイム*という第10章で議論されるRustの機能を使用しなければなりません。 -> ライフタイムのおかげで構造体に参照されたデータが、構造体自体が有効な間ずっと有効であることを保証してくれるのです。 +> ライフタイムのおかげで構造体に参照されたデータが、構造体自体が有効な間、ずっと有効であることを保証してくれるのです。 > ライフタイムを指定せずに構造体に参照を保持させようとしたとしましょう。このように: > > ファイル名: src/main.rs diff --git a/second-edition/src/ch05-02-example-structs.md b/second-edition/src/ch05-02-example-structs.md index 50ee6de8b..ff4455282 100644 --- a/second-edition/src/ch05-02-example-structs.md +++ b/second-edition/src/ch05-02-example-structs.md @@ -16,7 +16,7 @@ Cargoで*rectangles*という新規バイナリプロジェクトを作成しましょう。このプロジェクトは、 四角形の長さと幅をピクセルで指定し、その面積を求めます。リスト5-8に、プロジェクトの*src/main.rs*で、 -そうする一例を短いプログラムとして示しました。 +そうする一例を短いプログラムとして示しました: diff --git a/second-edition/src/ch05-03-method-syntax.md b/second-edition/src/ch05-03-method-syntax.md index 03552be3b..286c61136 100644 --- a/second-edition/src/ch05-03-method-syntax.md +++ b/second-edition/src/ch05-03-method-syntax.md @@ -420,7 +420,7 @@ impl Rectangle { 構造体により、自分の領域で意味のある独自の型を作成することができます。構造体を使用することで、 関連のあるデータ片を相互に結合させたままにし、各部品に名前を付け、コードを明確にすることができます。 メソッドにより、構造体のインスタンスが行う動作を指定することができ、関連関数により、 -構造体に特有の機能をインスタンスを利用することなく名前空間分けすることができます。 +構造体に特有の機能をインスタンスを利用することなく、名前空間分けすることができます。 diff --git a/second-edition/src/ch06-00-enums.md b/second-edition/src/ch06-00-enums.md index 356207e52..fa7eb4d2e 100644 --- a/second-edition/src/ch06-00-enums.md +++ b/second-edition/src/ch06-00-enums.md @@ -15,10 +15,10 @@ この章では、*列挙型*について見ていきます。列挙型は、*enum*とも称されます。enumは、取りうる値を列挙することで、 -型を定義させてくれます。最初に、enumを定義し、使用して、enumがデータとともに意味をエンコードする方法を示します。 +型を定義させてくれます。最初に、enumを定義し、使用して、enumがデータとともに意味をコード化する方法を示します。 次に、特別に有用なenumである`Option`について掘り下げていきましょう。この型は、 値が何かかなんでもないかを表現します。それから、`match`式のパターンマッチングにより、 -どうenumの異なる値に対して異なるコードを走らせやすくなるかを見ます。最後に、`if let`文法要素も、 +どうenumの色々な値に対して異なるコードを走らせやすくなるかを見ます。最後に、`if let`文法要素も、 如何(いか)にenumをコードで扱う際に使用可能な便利で簡潔な慣用句であるかを解説します。 @@ -26,4 +26,4 @@ enumは多くの言語に存在する機能ですが、その能力は言語ごとに異なります。Rustのenumは、F#、OCaml、Haskellなどの、 -関数型言語に存在する*数学的データ型*に非常に酷似しています。 +関数型言語に存在する*数学的データ型*に最も酷似しています。 diff --git a/second-edition/src/ch06-01-defining-an-enum.md b/second-edition/src/ch06-01-defining-an-enum.md index 0ee2813eb..c6273b458 100644 --- a/second-edition/src/ch06-01-defining-an-enum.md +++ b/second-edition/src/ch06-01-defining-an-enum.md @@ -69,10 +69,10 @@ let six = IpAddrKind::V6; -enumのバリアントは、その識別子の元に名前空間わけされていることと、 +enumのバリアントは、その識別子の元に名前空間分けされていることと、 2連コロンを使ってその二つを区別していることに注意してください。 これが有効な理由は、こうすることで、値`IpAddrKind::V4`と`IpAddrKind::V6`という値は両方とも、 -同じ型`IpAddrKind`になったことです。そうしたら、例えば、どんな`IpAddrKind`を取る関数も定義できるようになります。 +同じ型`IpAddrKind`になったからです。そうしたら、例えば、どんな`IpAddrKind`を取る関数も定義できるようになります。 ```rust # enum IpAddrKind { @@ -105,7 +105,7 @@ route(IpAddrKind::V6); enumの利用には、さらなる利点さえもあります。このIPアドレス型についてもっと考えてみると、現状では、 -実際のIPアドレスの*データ*を保持する方法がありません。つまり、どんな種類であるかを知っているだけです。 +実際のIPアドレスの*データ*を保持する方法がありません。つまり、どんな*種類*であるかを知っているだけです。 構造体について第5章で学んだばっかりとすると、この問題に対しては、リスト6-1のように対処するかもしれません。 ```rust @@ -209,8 +209,8 @@ let loopback = IpAddr::V6(String::from("::1")); enumを使用して、コード内で二つの異なるバラエティを持つIPアドレスを定義するいくつかの異なる可能性を示してきました。 -しかしながら、蓋を開けてみれば、IPアドレスを格納してその種類をエンコードしたくなるということは一般的なので、 -[標準ライブラリに使用可能な定義があります!][IpAddr] 標準ライブラリでの`IpAddr`の定義のされ方を見てみましょう。 +しかしながら、蓋を開けてみれば、IPアドレスを格納してその種類をコード化したくなるということは一般的なので、 +[標準ライブラリに使用可能な定義があります!][IpAddr] 標準ライブラリでの`IpAddr`の定義のされ方を見てみましょう: 私たちが定義し、使用したのと全く同じenumとバリアントがありますが、アドレスデータを二種の異なる構造体の形でバリアントに埋め込み、 この構造体は各バリアント用に異なる形で定義されています。 @@ -305,7 +305,7 @@ enum Message { リスト6-2のようなバリアントを含むenumを定義することは、enumの場合、`struct`キーワードを使わず、 全部のバリアントが`Message`型の元に分類される点を除いて、異なる種類の構造体定義を定義するのと類似しています。 -以下の構造体も、先ほどのenumのバリアントが保持しているのと同じデータを格納することができます: +以下の構造体も、先ほどのenumのバリアントが保持しているのと同じデータを格納することができるでしょう: @@ -368,7 +368,7 @@ m.call(); -メソッドの本体では、`self`を使用して、メソッドを呼び出した相手の値を取得できます。この例では、 +メソッドの本体では、`self`を使用して、メソッドを呼び出した相手の値を取得できるでしょう。この例では、 `Message::Write(String::from("hello"))`という値を持つ、変数`m`を生成したので、これが`m.call()`を走らせた時に、 `call`メソッドの本体内で`self`が表す値になります。 @@ -390,7 +390,7 @@ m.call(); -前節で、`IpAddr`enumがRustの型システムを使用して、プログラムにデータ以上の情報をエンコードできる方法を目撃しました。 +前節で、`IpAddr`enumがRustの型システムを使用して、プログラムにデータ以上の情報をコード化できる方法を目撃しました。 この節では、`Option`のケーススタディを掘り下げていきます。この型も標準ライブラリにより定義されているenumです。 この`Option`型はいろんな箇所で使用されます。なぜなら、値が何かかそうでないかという非常に一般的な筋書きをコード化するからです。 この概念を型システムの観点で表現することは、コンパイラが、プログラマが処理すべき場面全てを処理していることをチェックできることを意味し、 @@ -468,7 +468,7 @@ enum Option { `Option`は有益すぎて、初期化処理(prelude)にさえ含まれています。つまり、明示的にインポートする必要がないのです。 さらに、バリアントもそうなっています: `Some`と`None`を`Option::`と接頭辞を付けることなく直接使えるわけです。 -ただ、`Option`は普通のenumであり、`Some(T)`と`None`は`Option`型のバリアントです。 +ただ、`Option`はそうは言っても、普通のenumであり、`Some(T)`と`None`も`Option`型のただのバリアントです。 @@ -556,7 +556,7 @@ not satisfied -言い換えると、`T`型の処理を行うには、`Option`を`T`に変換する必要があるわけです。一般的に、 +言い換えると、`T`型の処理を行う前には、`Option`を`T`に変換する必要があるわけです。一般的に、 これにより、nullの最もありふれた問題の一つを捕捉できます: 実際にはnullなのに、 そうでないかのように想定することです。 diff --git a/second-edition/src/ch06-02-match.md b/second-edition/src/ch06-02-match.md index cc6ecb18b..20961d5e1 100644 --- a/second-edition/src/ch06-02-match.md +++ b/second-edition/src/ch06-02-match.md @@ -63,8 +63,8 @@ fn value_in_cents(coin: Coin) -> u32 { -`value_in_cents`関数内の`match`を分解しましょう。まず、`match`キーワードに続けて式を並べています。 -この式は今回の場合、値`coin`です。`if`で使用した式と非常に酷似していますね。しかし、大きな違いがあります: +`value_in_cents`関数内の`match`を噛み砕きましょう。まず、`match`キーワードに続けて式を並べています。 +この式は今回の場合、値`coin`です。`if`で使用した式と非常に酷似しているみたいですね。しかし、大きな違いがあります: `if`では、式は論理値を返す必要があります。ここでは、どんな型でも構いません。この例における`coin`の型は、 リスト6-3で定義した`Coin`enumです。 diff --git a/second-edition/src/ch08-03-hash-maps.md b/second-edition/src/ch08-03-hash-maps.md index 1e08b0fe2..b4a35a4ec 100644 --- a/second-edition/src/ch08-03-hash-maps.md +++ b/second-edition/src/ch08-03-hash-maps.md @@ -28,8 +28,8 @@ -この説でマッシュマップの基礎的なAPIを見ていきますが、より多くのグッズが標準ライブラリにより、 -`HashMap`状に定義された関数に隠されています。いつものように、 +この節でマッシュマップの基礎的なAPIを見ていきますが、より多くのグッズが標準ライブラリにより、 +`HashMap`上に定義された関数に隠されています。いつものように、 もっと情報が欲しければ、標準ライブラリのドキュメントをチェックしてください。 @@ -42,7 +42,7 @@ 空のハッシュマップを`new`で作り、要素を`insert`で追加することができます。リスト8-18では、 -名前がブルーとイエローの2チームのスコアを追いかけています。ブルーチーム10点から、イエローチームは50点から始まります: +名前がブルーとイエローの2チームのスコアを追いかけています。ブルーチームは10点から、イエローチームは50点から始まります: ```rust use std::collections::HashMap; @@ -87,7 +87,7 @@ scores.insert(String::from("Yellow"), 50); ハッシュマップを生成する別の方法は、タプルのベクタに対して`collect`メソッドを使用するものです。 ここで、各タプルは、キーと値から構成されています。`collect`メソッドはいろんなコレクション型にデータをまとめ上げ、 -そこには`HashMap`も含まれています。例として、チームメイト初期スコアが別々のベクタに含まれていたら、 +そこには`HashMap`も含まれています。例として、チーム名と初期スコアが別々のベクタに含まれていたら、 `zip`メソッドを使ってタプルのベクタを作り上げることができ、そこでは「ブルー」は10とペアになるなどします。 リスト8-19に示したように、それから`collect`メソッドを使って、そのタプルのベクタを`HashMap`に変換することができるわけです: @@ -112,7 +112,7 @@ let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect(); ここでは、`HashMap<_, _>`という型注釈が必要になります。なぜなら、いろんなデータ構造に`まとめ上げる`ことができ、 -コンパイラは指定しない限りどれがいるのかわからないからです。ところが、キーと値の型引数については、 +コンパイラは指定しない限り、どれがいるのかわからないからです。ところが、キーと値の型引数については、 アンダースコアを使用しており、コンパイラはベクタのデータ型に基づいてハッシュマップが含む型を推論することができるのです。 @@ -200,7 +200,7 @@ let score = scores.get(&team_name); -ベクタでしたように、`for`ループでハッシュマップのキーと値のペアを走査することができます: +ベクタのように、`for`ループでハッシュマップのキーと値のペアを走査することができます: ```rust use std::collections::HashMap; @@ -254,7 +254,7 @@ Blue: 10 キーと値をハッシュマップに挿入し、同じキーを異なる値で挿入したら、そのキーに紐づけられている値は置換されます。 -リスト8-22のコードは、`insert`を二度呼んでいるものの、ハッシュマップには一つのキーと値の組みしか含まれません。 +リスト8-22のコードは、`insert`を二度呼んでいるものの、ハッシュマップには一つのキーと値の組しか含まれません。 なぜなら、ブルーチームキーに対する値を2回とも挿入しているからです: ```rust @@ -332,7 +332,7 @@ println!("{:?}", scores); リスト8-23のコードを実行すると、`{"Yellow": 50, "Blue": 10}`と出力するでしょう。 最初の`entry`呼び出しは、まだイエローチームに対する値がないので、値`50`でイエローチームのキーを挿入します。 -`entry`の2回目の呼び出しはハッシュマップを変更しません。なぜなら、ブルーチームはすでに`10`という値があるからです。 +`entry`の2回目の呼び出しはハッシュマップを変更しません。なぜなら、ブルーチームにはすでに`10`という値があるからです。 @@ -346,7 +346,7 @@ println!("{:?}", scores); ハッシュマップの別の一般的なユースケースは、キーの値を探し、古い値に基づいてそれを更新することです。 -例えば、リスト8-24は、各単語があるテキストに何回出現するかをかぞえあげるコードを示しています。 +例えば、リスト8-24は、各単語があるテキストに何回出現するかを数え上げるコードを示しています。 キーに単語を入れたハッシュマップを使用し、その単語を何回見かけたか追いかけるために値を増やします。 ある単語を見かけたのが最初だったら、まず`0`という値を挿入します: @@ -368,7 +368,7 @@ println!("{:?}", map); -単語とカウントを保持するハッシュマップを使って単語の出現数をカウントする +リスト8-24: 単語とカウントを保持するハッシュマップを使って単語の出現数をカウントする @@ -435,7 +435,7 @@ println!("{:?}", map); mode(最も頻繁に出現する値; ハッシュマップがここでは有効活用できるでしょう)を返してください。 * 文字列をピッグ・ラテン(`脚注`: 英語の言葉遊びの一つ)に変換してください。各単語の最初の子音は、 単語の終端に移り、"ay"が足されます。従って、"first"は"irst-fay"になります。ただし、 -母音で始まる単語にはお尻に"hay"が付け足されます("apple"は"apple-hay"になります)。 +母音で始まる単語には、お尻に"hay"が付け足されます("apple"は"apple-hay"になります)。 UTF-8エンコードに関する詳細を心に留めておいてください! * ハッシュマップとベクタを使用して、ユーザに会社の部署に雇用者の名前を追加させられるテキストインターフェイスを作ってください。 例えば、"Add Sally to Engineering"(開発部門にサリーを追加)や"Add Amir to Sales"(販売部門にアミールを追加)などです。 From 28a3cf28a4946bb892657a039d01bd39616c4f91 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 22 Sep 2017 19:27:08 +0900 Subject: [PATCH 054/428] Make some small changes on the chapter 6-2 --- second-edition/src/ch06-02-match.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/second-edition/src/ch06-02-match.md b/second-edition/src/ch06-02-match.md index 20961d5e1..08ab73ec6 100644 --- a/second-edition/src/ch06-02-match.md +++ b/second-edition/src/ch06-02-match.md @@ -133,20 +133,20 @@ fn value_in_cents(coin: Coin) -> u32 { -マッチのアームの別の便利な機能は、パターンにマッチした値の一部に束縛できる点です。これにより、 +マッチのアームの別の有益な機能は、パターンにマッチした値の一部に束縛できる点です。こうして、 enumのバリアントから値を取り出すことができます。 - + 例として、enumのバリアントの一つを中にデータを保持するように変えましょう。1999年から2008年まで、 アメリカは、片側に50の州それぞれで異なるデザインをしたクォーターコインを鋳造していました。 他のコインは州のデザインがなされることはなかったので、クォーターだけがこのおまけの値を保持します。 -`Quarter`バリアントを変更して、`State`値が中に保持されるようにすることでenumにこの情報を追加でき、 +Quarterバリアントを変更して、UsState値が中に保持されるようにすることでenumにこの情報を追加でき、 それをしたのがリスト6-4のコードになります: @@ -351,7 +351,7 @@ None => None, `match`とenumの組み合わせは、多くの場面で有効です。Rustコードにおいて、このパターンはよく見かけるでしょう: -enumに対し`match`し、内部のデータに変数を束縛させ、それに基づいたコードを実行します。一目にはちょっと巧妙ですが、 +enumに対し`match`し、内部のデータに変数を束縛させ、それに基づいたコードを実行します。最初はちょっと巧妙ですが、 一旦慣れてしまえば、全ての言語にあってほしいと願うことになるでしょう。一貫してユーザのお気に入りなのです。 @@ -399,7 +399,7 @@ error[E0004]: non-exhaustive patterns: `None` not covered 全可能性を網羅していないことをコンパイラは検知しています。もっと言えば、どのパターンを忘れているかさえ知っているのです。 Rustにおけるマッチは、*包括的*です: 全てのあらゆる可能性を網羅し尽くさなければ、コードは有効にならないのです。 特に`Option`の場合には、コンパイラが明示的に`None`の場合を扱うのを忘れないようにする時、 -nullになるかもしれない値があることを想定しないように、つまり、前に議論した10億ドルの失敗を犯さないよう、 +nullになるかもしれない値があることを想定しないように、故に、前に議論した10億ドルの失敗を犯さないよう、 保護してくれるわけです。 From 4ff019aea628b383903abb92de820b4938b7b26b Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 22 Sep 2017 19:53:08 +0900 Subject: [PATCH 055/428] Make some small changes on the chapter 6-3 --- second-edition/src/ch06-03-if-let.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/second-edition/src/ch06-03-if-let.md b/second-edition/src/ch06-03-if-let.md index 9f032231b..50079b239 100644 --- a/second-edition/src/ch06-03-if-let.md +++ b/second-edition/src/ch06-03-if-let.md @@ -31,7 +31,7 @@ match some_u8_value { `Some(3)`にマッチした時だけ何かをし、他の`Some`値や`None`値の時には何もしたくありません。 `match`式を満たすためには、バリアントを一つだけ処理した後に`_ => ()`を追加しなければなりません。 -これでは、追加すべき典型コードが多すぎます。 +これでは、追加すべき定型コードが多すぎます。 @@ -59,7 +59,7 @@ if let Some(3) = some_u8_value { -`if let`を使うと、タイプ数が減り、インデントも少なくなり、典型コードも減ります。しかしながら、 +`if let`を使うと、タイプ数が減り、インデントも少なくなり、定型コードも減ります。しかしながら、 `match`では強制された包括性チェックがなくなってしまいます。`match`か`if let`かの選択は、 特定の場面でどんなことをしたいかと簡潔性を得ることが包括性チェックを失うのに適切な代償となるかによります。 @@ -81,7 +81,7 @@ if let Some(3) = some_u8_value { `if let`と`else`に等価な`match`式の`_`の場合に入るコードブロックと同じになります。 リスト6-4の`Coin`enum定義を思い出してください。ここでは、`Quarter`バリアントは、 `UsState`の値も保持していましたね。クォーターコインの状態を告げつつ、 -見かけたクォーター以外のコインの枚数を数えたいなら、以下のように`match`式で実現することができます: +見かけたクォーター以外のコインの枚数を数えたいなら、以下のように`match`式で実現することができるでしょう: ```rust # #[derive(Debug)] @@ -107,7 +107,7 @@ match coin { -または、以下のように`if let`と`else`を使うこともできます: +または、以下のように`if let`と`else`を使うこともできるでしょう: ```rust # #[derive(Debug)] From c66e9fde0600c88d1f19587774703bfcec342492 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 24 Sep 2017 18:42:32 +0900 Subject: [PATCH 056/428] Fix an error in the chapter 7-1 --- second-edition/src/ch07-01-mod-and-the-filesystem.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch07-01-mod-and-the-filesystem.md b/second-edition/src/ch07-01-mod-and-the-filesystem.md index bc04ebff5..0d9089bf2 100644 --- a/second-edition/src/ch07-01-mod-and-the-filesystem.md +++ b/second-edition/src/ch07-01-mod-and-the-filesystem.md @@ -609,7 +609,7 @@ communicator では、`network::server`モジュールを抽出したかったときに、 -`network::server`モジュールを*src/server.rs*に直接抽出できずに、 +なぜ、`network::server`モジュールを*src/server.rs*に直接抽出できずに、 *src/network.rs*ファイルを*src/network/mod.rs*ファイルに変更し、 `network::server`のコードを*network*ディレクトリ内の*src/network/server.rs*に置かなければならなかったのでしょうか? 理由は、*server.rs*ファイルが*src*ディレクトリにあると、コンパイラが、 From 017ba6dfdbe2bc88991b8c9dcd8434ce9774c12b Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 26 Sep 2017 19:08:47 +0900 Subject: [PATCH 057/428] Fix some errors in the chapter 8-1, 8-2 and 8-3 --- second-edition/src/ch08-01-vectors.md | 2 +- second-edition/src/ch08-02-strings.md | 6 +++--- second-edition/src/ch08-03-hash-maps.md | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/second-edition/src/ch08-01-vectors.md b/second-edition/src/ch08-01-vectors.md index c55d5e04c..669ad1267 100644 --- a/second-edition/src/ch08-01-vectors.md +++ b/second-edition/src/ch08-01-vectors.md @@ -231,7 +231,7 @@ let does_not_exist = v.get(100); `get`メソッドがベクタ外の番号を渡されると、パニックすることなく`None`を返します。 -普通の状態でも、ベクタの範囲外にアクセスする可能性がある場合に、このメソッドを使用することでしょう。 +普通の状態でも、ベクタの範囲外にアクセスする可能性がある場合に、このメソッドを使用することになるでしょう。 そうしたら、コードには`Some(&element)`か`None`を扱うロジックが存在することになります。そう、 第6章で議論したように。例えば、番号は人間に数値を入力してもらうことで得ることもできます。 もし大きすぎる値を誤って入力し、プログラムが`None`値を得てしまったら、現在`Vec`に幾つ要素があるかをユーザに教え、 diff --git a/second-edition/src/ch08-02-strings.md b/second-edition/src/ch08-02-strings.md index e7df6e41c..b64dd6bb0 100644 --- a/second-edition/src/ch08-02-strings.md +++ b/second-edition/src/ch08-02-strings.md @@ -600,7 +600,7 @@ character boundary', ../src/libcore/str/mod.rs:1694 -### 文字列を操作するメソッド群 +### 文字列を走査するメソッド群 @@ -684,9 +684,9 @@ for b in "नमस्ते".bytes() { まとめると、文字列は込み入っています。プログラミング言語ごとにこの複雑性をプログラマに提示する方法は違います。 Rustでは、`String`データを正しく扱うことが、全てのRustプログラムにとっての規定動作になっているわけであり、 -これは、プログラマがUTF-8データを素直に扱う際により思考しないといけないことを意味します。 +これは、プログラマがUTF-8データを素直に扱う際に、より思考しないといけないことを意味します。 このトレードオフにより、他のプログラミング言語よりも文字列の複雑性がより露出していますが、 -ASCII以外の文字に関するエラーを開発の後半で扱わなければならない可能性を排除してくれているのです。 +ASCII以外の文字に関するエラーを開発の後半で扱わなければならない可能性が排除されているのです。 diff --git a/second-edition/src/ch08-03-hash-maps.md b/second-edition/src/ch08-03-hash-maps.md index b4a35a4ec..998cb4d7e 100644 --- a/second-edition/src/ch08-03-hash-maps.md +++ b/second-edition/src/ch08-03-hash-maps.md @@ -11,7 +11,7 @@ 一般的なコレクションのトリを飾るのは、*ハッシュマップ*です。型`HashMap`は、 `K`型のキーと`V`型の値の対応関係を保持します。これを*ハッシュ関数*を介して行います。 -これは、キーと値のメモリ配置方法を決めるものです。色々なプログラミング言語でもこの種のデータ構造はサポートされていますが、 +ハッシュ関数は、キーと値のメモリ配置方法を決めるものです。色々なプログラミング言語でもこの種のデータ構造はサポートされていますが、 しばしば名前が違います。hash、map、object、ハッシュテーブル、連想配列など、枚挙に(いとま)はありません。 @@ -64,7 +64,7 @@ scores.insert(String::from("Yellow"), 50); -最初に標準ライブラリからコレクション部分の`HashMap`を`use`する必要があることに注意してください。 +最初に標準ライブラリのコレクション部分から`HashMap`を`use`する必要があることに注意してください。 今までの3つの一般的なコレクションの内、これが最も使用頻度が低いので、初期化処理で自動的にインポートされる機能には含まれていません。 また、標準ライブラリからのサポートもハッシュマップは少ないです; 例えば、生成するための組み込みマクロがありません。 @@ -450,5 +450,5 @@ UTF-8エンコードに関する詳細を心に留めておいてください! -処理が失敗する可能性のあるようなより複雑なプログラムに入り込んできています; ということは、 +処理が失敗する可能性のあるような、より複雑なプログラムに入り込んできています; ということは、 次にエラーの処理法について議論するのにぴったりということですね! From beb5266a292d9e2d4b4668325dbdf0e43ea9837f Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 27 Sep 2017 19:20:43 +0900 Subject: [PATCH 058/428] Fix an error in the chapter 3-0 --- second-edition/src/ch03-00-common-programming-concepts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch03-00-common-programming-concepts.md b/second-edition/src/ch03-00-common-programming-concepts.md index 4c4c07770..56dae441a 100644 --- a/second-edition/src/ch03-00-common-programming-concepts.md +++ b/second-edition/src/ch03-00-common-programming-concepts.md @@ -8,7 +8,7 @@ この章では、ほとんど全てのプログラミング言語で見られる概念を解説し、それらがRustにおいて、 -どう動作するかを見ていこう。多くのプログラミング言語は、その核心において、いろいろなものを共有しています。 +どう動作するかを見ていきましょう。多くのプログラミング言語は、その核心において、いろいろなものを共有しています。 この章で提示する概念は、全てRustに固有のものではありませんが、Rustの文脈で議論し、その規格を 解説していきます。 From 3cfe1996d674e7b2884b65be63a458f1582bc0a1 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 29 Sep 2017 20:21:02 +0900 Subject: [PATCH 059/428] Fix some errors in the chapter 2 --- .../src/ch02-00-guessing-game-tutorial.md | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/second-edition/src/ch02-00-guessing-game-tutorial.md b/second-edition/src/ch02-00-guessing-game-tutorial.md index 8fea43e7d..9094f9582 100644 --- a/second-edition/src/ch02-00-guessing-game-tutorial.md +++ b/second-edition/src/ch02-00-guessing-game-tutorial.md @@ -111,7 +111,7 @@ Hello, world! -*src/main.rs*ファイルを開き直しましょう。ここにすべてのコードを書いてきます。 +*src/main.rs*ファイルを開き直しましょう。ここにすべてのコードを書いていきます。 @@ -347,7 +347,7 @@ io::stdin().read_line(&mut guess) `&`という記号は、この引数が*参照*であることを表し、これのおかげで、データを複数回メモリにコピーせずとも、 コードの複数箇所で同じデータにアクセスできるようになるわけです。参照は複雑な機能であり、 とても安全かつ簡単に参照を使うことができることは、Rustの主要な利点の一つでもあります。 -そのような詳細は知らなくても、このプログラムを完成させることはできます: +そのような詳細を知らなくても、このプログラムを完成させることはできます: 第4章で参照について詳しく見ることにしましょう。現時点では、変数のように、参照も標準で不変であることを 知っておけばいいでしょう。故に、`&guess`と書くのではなく、`&mut guess`と書いて、可変にする必要があるのです。 @@ -536,7 +536,7 @@ You guessed(次のように予想したよ): 6 次に、ユーザが数当てに挑戦する秘密の数字を生成する必要があります。毎回この秘密の数字は、変わるべきです。 ゲームが何回も楽しめるようにですね。ゲームが難しくなりすぎないように、1から100までの乱数を使用しましょう。 -Rustの標準ライブラリには、乱数機能はまだ含まれていません。ですが、 +Rustの標準ライブラリには、乱数機能はまだ含まれていません。ですが、実は、 Rustチームが[`rand`クレート][randcrate]を用意してくれています。 [randcrate]: https://crates.io/crates/rand @@ -551,7 +551,7 @@ Rustチームが[`rand`クレート][randcrate]を用意してくれています *クレート*はRustコードのパッケージであることを思い出してください。私たちがここまで作ってきたプロジェクトは、 *バイナリークレート*であり、これは実行可能形式になります。`rand`クレートは*ライブラリクレート*であり、 -他のプログラムで使用する用のコードが含まれています。 +他のプログラムで使用するためのコードが含まれています。 @@ -615,7 +615,7 @@ $ cargo build -もしかしたら、バージョンナンバーは違うかもしれません(でも、互換性はあります、SemVerのおかげでね!) +もしかしたら、バージョンナンバーは違うかもしれません(でも、互換性はあります、SemVerのおかげでね!)。 そして、行の出力順序も違うかもしれません。 @@ -865,14 +865,14 @@ fn main() { クレートの使用方法は、各クレートのドキュメントにあります。Cargoの別の巧妙な機能は、 `cargo doc --open`コマンドを走らせてローカルに存在する依存ファィルすべてのドキュメントをビルドし、Webブラウザで閲覧できる機能です。 例えば、`rand`クレートの他の機能に興味があるなら、`cargo doc --open`コマンドを走らせて、 -左側のサイドバーから`rand`をクリックすればいいわけです。 +左側のサイドバーから`rand`をクリックしてください。 -コードに追加した2行目は、秘密の数字を出力してくれます。これは、プログラムをテストする構築中には役立ちますが、 +コードに追加した2行目は、秘密の数字を出力してくれます。これは、プログラムをテストする開発中には役立ちますが、 最終版からは削除する予定です。プログラムがスタートと同時に答えを出力しちゃったら、ゲームにならないからですね! @@ -950,7 +950,7 @@ fn main() { -リスト2-4: 2値比較の返り値を処理する +リスト2-4: 2値比較の可能性のある返り値を処理する @@ -1023,7 +1023,7 @@ match guess.cmp(&secret_number) { 値の`Ordering::Greater`と`Ordering::Less`はマッチしないため、このアームのコードは無視され、 次のアームに移ります。次のアームのパターン、`Ordering::Greater`は*見事に*`Ordering::Greater`とマッチします! このアームに紐づけられたコードが実行され、画面に`Too big!`が表示されます。 -これで`match`式の実行は終わりになります。この筋書きでは、最後のアームを吟味する必要はもうないからですね。 +これで`match`式の実行は終わりになります。この特定の筋書きでは、最後のアームを吟味する必要はもうないからですね。 @@ -1190,7 +1190,7 @@ Rustには、組み込みの数値型がいくつかあります; ここで見 `parse`メソッドの呼び出しは、エラーになりやすいです。例としては、文字列が`A👍%`を含んでいたら、 数値に変換できるわけがありません。失敗する可能性があるので、`parse`メソッドは、 -`Result`型を返すわけです。ちょうど、「Result型で失敗する可能性に対処する」節で先ほど議論した`read_line`メソッドがするようにというわけですね。 +`Result`型を返すわけです。ちょうど、「Result型で失敗する可能性に対処する」節で先ほど議論した`read_line`メソッドのようにというわけですね。 今回も、`expect`メソッドを使用して`Result`型を同じように扱います。 もし、文字列から数値を生成できなかったために、`parse`メソッドが`Result`型の`Err`値を返したら、 `expect`メソッドの呼び出しは、ゲームをクラッシュさせ、与えたメッセージを表示します。 @@ -1219,7 +1219,7 @@ Too big! いいですね!予想の前にスペースを追加したにもかかわらず、プログラムはちゃんとユーザが76と予想したことを導き出しました。 -プログラムを何回か走らせて、異なる入力の異なる振る舞いを確認してください: つまり、 +プログラムを何回か走らせて、異なる入力の色々な振る舞いを確認してください: つまり、 数字を正しく言い当てたり、大きすぎる値を予想したり、低すぎる数字を入力したりということです。 @@ -1294,9 +1294,9 @@ fn main() { -ユーザは、`Ctrl-C`というキーボードショートカットを使って、いつでもプログラムを強制終了させられます。 -しかし、「予想を秘密の数字と比較する」節の`parse`メソッドに関する議論で触れたこの貪欲なモンスターを -回避する別の方法があります: ユーザが数字以外の答えを入力すれば、プログラムはクラッシュするのです。 +ユーザは、Ctrl-Cというキーボードショートカットを使って、いつでもプログラムを強制終了させられます。 +しかし、「予想を秘密の数字と比較する」節の`parse`メソッドに関する議論で触れたこの貪欲なモンスターを回避する別の方法があります: +ユーザが数字以外の答えを入力すれば、プログラムはクラッシュするのです。 ユーザは、その利点を活かして、終了することができます。以下のようにね: ```text @@ -1340,7 +1340,7 @@ error: Process didn't exit successfully: `target/debug/guess` (exit code: 101) -`break`文を追加して、ユーザが勝った時にゲームが終了するようにしましょう: +`break`文を追加して、ユーザが勝った時にゲームが終了するようにプログラムしましょう: @@ -1422,7 +1422,7 @@ let guess: u32 = match guess.trim().parse() { `expect`メソッドの呼び出しから`match`式に切り替えることは、 エラーでクラッシュする動作から実際にエラー処理を行う処理へ変更する一般的な手段になります。`parse`メソッドは、 `Result`型を返し、`Result`は`Ok`か`Err`の値を取りうるenumであることを思い出してください。 -ここでは`match`式を使っています。`cmp`メソッドの`Ordering`という結果でしたのと同じですね。 +ここでは`match`式を使っています。`cmp`メソッドの`Ordering`という結果のような感じですね。 @@ -1447,9 +1447,9 @@ let guess: u32 = match guess.trim().parse() { `parse`メソッドは、文字列から数値への変換に*失敗*したら、エラーに関する情報を多く含む`Err`値を返します。 この`Err`値は、最初の`match`アームの`Ok(num)`というパターンにはマッチしないものの、 2番目のアームの`Err(_)`というパターンにはマッチするわけです。この`_`は、包括値です; この例では、 -保持している情報がどんなものでもいいから全ての`Err`値にマッチさせたいと宣言しています。 +保持している情報がどんなものでもいいから、全ての`Err`値にマッチさせたいと宣言しています。 従って、プログラムは2番目のアームのコードを実行し(`continue`ですね)、これは、 -`loop`の次の段階に移り、再度予想入力を求めることを意味します。故に実効的には、 +`loop`の次の繰り返しに移り、再度予想入力を求めることを意味します。故に実効的には、 プログラムは`parse`メソッドが遭遇しうる全てのエラーを無視するようになります! @@ -1485,7 +1485,7 @@ You win! 素晴らしい!最後にひとつまみ変更を加えて、数当てゲームを完了にしましょう: - プログラムが未だに秘密の数字を出力していることを思い出してください。テスト中はうまく動くけど、 +プログラムが未だに秘密の数字を出力していることを思い出してください。テスト中はうまく動くけど、 ゲームを台無しにしてしまいます。秘密の数字を出力する`println!`を削除しましょう。 リスト2-5が成果物のコードです: From 4df40a9740c8df0f972ecb6d2c9826d7022e4e38 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 5 Oct 2017 19:47:43 +0900 Subject: [PATCH 060/428] First drafts of the chapters 9-0 and 9-1 --- second-edition/src/SUMMARY.md | 13 +- second-edition/src/ch09-00-error-handling.md | 59 ++-- ...ch09-01-unrecoverable-errors-with-panic.md | 285 ++++++++++++------ 3 files changed, 238 insertions(+), 119 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index 75e35fbf2..29c6758e6 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -80,10 +80,15 @@ - [文字列型](ch08-02-strings.md) - [ハッシュマップ](ch08-03-hash-maps.md) -- [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) + + + + + +- [エラー処理](ch09-00-error-handling.md) + - [`panic!`で回復不能なエラー](ch09-01-unrecoverable-errors-with-panic.md) + - [`Result`で回復可能なエラー](ch09-02-recoverable-errors-with-result.md) + - [`panic!`すべきかするまいか](ch09-03-to-panic-or-not-to-panic.md) - [Generic Types, Traits, and Lifetimes](ch10-00-generics.md) - [Generic Data Types](ch10-01-syntax.md) diff --git a/second-edition/src/ch09-00-error-handling.md b/second-edition/src/ch09-00-error-handling.md index d8ead01c5..de0a602a3 100644 --- a/second-edition/src/ch09-00-error-handling.md +++ b/second-edition/src/ch09-00-error-handling.md @@ -1,24 +1,41 @@ -# Error Handling + -Rust’s commitment to reliability extends to error handling. Errors are a fact -of life in software, so Rust has a number of features for handling situations -in which something goes wrong. In many cases, Rust requires you to acknowledge -the possibility of an error occurring and take some action before your code -will compile. This requirement makes your program more robust by ensuring that -you’ll discover errors and handle them appropriately before you’ve deployed -your code to production! +# エラー処理 -Rust groups errors into two major categories: *recoverable* and *unrecoverable* -errors. Recoverable errors are situations in which it’s reasonable to report -the problem to the user and retry the operation, like a file not found error. -Unrecoverable errors are always symptoms of bugs, like trying to access a -location beyond the end of an array. + + + + + + + -Most languages don’t distinguish between these two kinds of errors and handle -both in the same way using mechanisms like exceptions. Rust doesn’t have -exceptions. Instead, it has the value `Result` for recoverable errors and -the `panic!` macro that stops execution when it encounters unrecoverable -errors. This chapter covers calling `panic!` first and then talks about -returning `Result` values. Additionally, we’ll explore considerations to -take into account when deciding whether to try to recover from an error or to -stop execution. +Rustの信頼性への傾倒は、エラー処理にも及びます。ソフトウェアにおいて、エラーは生きている証しです。 +従って、Rustには何かがおかしくなる場面を扱う機能がたくさんあります。多くの場面で、 +コンパイラは、エラー発生の可能性を知り、コードのコンパイルが通るまでに何かしら対応を行うことを要求してきます。 +この要求により、エラーを発見し、コードを実用に供する前に適切に対処していることを確認することでプログラムを頑健なものにしてくれるのです! + + + + + + + +Rustでは、エラーは大きく二つに分類されます: *回復可能*と*回復不能*なエラーです。回復可能なエラーとは、 +問題をユーザに報告し、処理を再試行することが合理的になる場面のことです。例えば、ファイルが見つからないような場面ですね。 +回復不能なエラーは、常にバグの兆候です。例えば、配列の境界を超えた箇所にアクセスしようとすることなどです。 + + + + + + + + + + +多くの言語では、この2種のエラーを区別することはなく、例外などの機構を使用して同様に扱います。 +Rustには例外が存在しません。代わりに、回復可能なエラーには`Result`値を、回復不能なエラーに遭遇したら、 +`panic!`マクロで実行を中止します。この章では、まず`panic!`の呼び出しを解説し、 +それから`Result`を戻り値にする話をします。加えて、エラーからの回復を試みるか、 +実行を中止するか決定する際に考慮すべき事項についても、掘り下げましょう。 diff --git a/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md b/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md index 678a590e2..4ae74b440 100644 --- a/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md +++ b/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md @@ -1,41 +1,69 @@ -## Unrecoverable Errors with `panic!` + -Sometimes, bad things happen in your code, and there’s nothing you can do about -it. In these cases, Rust has the `panic!` macro. When the `panic!` macro -executes, your program will print a failure message, unwind and clean up the -stack, and then quit. The most common situation this occurs in is when a bug of -some kind has been detected, and it’s not clear to the programmer how to handle -the error. +## `panic!`で回復不能なエラー -> ### Unwinding the Stack or Aborting in Response to a `panic!` + + + + + + + +時として、コードで悪いことが起きるものです。そして、それに対してできることは何もありません。 +このような場面で、Rustには`panic!`マクロが用意されています。`panic!`マクロが実行されると、 +プログラムは失敗のメッセージを表示し、スタックを巻き戻し掃除して、終了します。こうなる最もありふれた場面は、 +何らかのバグが検出された時であり、プログラマには、どうエラーを処理すればいいか明確ではありません。 + + + + + + + + + + + + + + + + + + + +> ### `panic!`に対してスタックを巻き戻すか異常終了するか > -> By default, when a `panic!` occurs, the program starts *unwinding*, which -> means Rust walks back up the stack and cleans up the data from each function -> it encounters. But this walking back and cleanup is a lot of work. The -> alternative is to immediately *abort*, which ends the program without -> cleaning up. Memory that the program was using will then need to be cleaned -> up by the operating system. If in your project you need to make the resulting -> binary as small as possible, you can switch from unwinding to aborting on -> panic by adding `panic = 'abort'` to the appropriate `[profile]` sections in -> your *Cargo.toml* file. For example, if you want to abort on panic in release -> mode, add this: +> 標準では、`panic!`が発生すると、プログラムは*巻き戻し*を始めます。つまり、言語がスタックを遡り、 +> 遭遇した各関数のデータを片付けるということです。しかし、この遡りと片付けはすべきことが多くなります。 +> 対立案は、即座に異常終了し、片付けをせずにプログラムを終了させることです。そうなると、プログラムが使用していたメモリは、 +> OSが片付ける必要があります。プロジェクトにおいて、実行可能ファイルを極力小さくする必要があれば、 +> *Cargo.toml*ファイルの適切な`[profile]`欄に`panic = 'abort'`を追記することで、 +> パニック時に巻き戻しから異常終了するように切り替えることができます。例として、 +> リリースモード時に異常するようにしたければ、以下を追記してください: > > ```toml > [profile.release] > panic = 'abort' > ``` -Let’s try calling `panic!` in a simple program: + + +単純なプログラムで`panic!`の呼び出しを試してみましょう: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust,should_panic fn main() { - panic!("crash and burn"); + panic!("crash and burn"); //クラッシュして炎上 } ``` -When you run the program, you’ll see something like this: + + +このプログラムを実行すると、以下のような出力を目の当たりにするでしょう: ```text $ cargo run @@ -43,32 +71,51 @@ $ cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.25 secs Running `target/debug/panic` thread 'main' panicked at 'crash and burn', src/main.rs:2 +('main'スレッドはsrc/main.rs:2の「クラッシュして炎上」でパニックしました) note: Run with `RUST_BACKTRACE=1` for a backtrace. error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) ``` -The call to `panic!` causes the error message contained in the last three -lines. The first line shows our panic message and the place in our source code -where the panic occurred: *src/main.rs:2* indicates that it’s the second line -of our *src/main.rs* file. + + + + + +`panic!`の呼び出しが、最後の3行に含まれるエラーメッセージを発生させているのです。 +1行目にパニックメッセージとソースコード中でパニックが発生した箇所を示唆しています: +*src/main.rs:2*は、*src/main.rs*ファイルの2行目であることを示しています。 -In this case, the line indicated is part of our code, and if we go to that -line, we see the `panic!` macro call. In other cases, the `panic!` call might -be in code that our code calls. The filename and line number reported by the -error message will be someone else’s code where the `panic!` macro is called, -not the line of our code that eventually led to the `panic!` call. We can use -the backtrace of the functions the `panic!` call came from to figure out the -part of our code that is causing the problem. We’ll discuss what a backtrace is -in more detail next. + + + + + + + + -### Using a `panic!` Backtrace +この場合、示唆される行は、自分のコードの一部で、その箇所を見に行けば、`panic!`マクロ呼び出しがあるわけです。 +`panic!`呼び出しが、自分のコードが呼び出しているコードの一部になっている可能性もあるわけです。 +エラーメッセージで報告されるファイル名と行番号が、結果的に`panic!`呼び出しに導いた自分のコードの行ではなく、 +`panic!`マクロが呼び出されている他人のコードになるでしょう。`panic!`呼び出しの発生元である関数のバックトレースを使用して、 +問題を起こしている自分のコードの箇所を割り出すことができます。バックトレースがどんなものか、次に議論しましょう。 -Let’s look at another example to see what it’s like when a `panic!` call comes -from a library because of a bug in our code instead of from our code calling -the macro directly. Listing 9-1 has some code that attempts to access an -element by index in a vector: + -Filename: src/main.rs +### `panic!`バックトレースを使用する + + + + + + +別の例を眺めて、自分のコードでマクロを直接呼び出す代わりに、コードに存在するバグにより、 +ライブラリで`panic!`呼び出しが発生するとどんな感じなのか確かめてみましょう。リスト9-1は、 +添え字でベクタの要素にアクセスを試みるあるコードです: + + + +ファイル名: src/main.rs ```rust,should_panic fn main() { @@ -78,25 +125,41 @@ fn main() { } ``` -Listing 9-1: Attempting to access an element beyond the -end of a vector, which will cause a `panic!` + + + +リスト9-1: ベクタの境界を超えて要素へのアクセスを試み、 + `panic!`を発生させる + + + + + -Here, we’re attempting to access the hundredth element of our vector, but it -has only three elements. In this situation, Rust will panic. Using `[]` is -supposed to return an element, but if you pass an invalid index, there’s no -element that Rust could return here that would be correct. +ここでは、ベクタの100番目の要素にアクセスを試みていますが、ベクタには3つしか要素がありません。 +この場面では、Rustはパニックします。`[]`の使用は、要素を返すと想定されるものの、 +無効な番号を渡せば、ここでRustが返せて正しいと思われる要素は何もないわけです。 -Other languages, like C, will attempt to give you exactly what you asked for in -this situation, even though it isn’t what you want: you’ll get whatever is at -the location in memory that would correspond to that element in the vector, -even though the memory doesn’t belong to the vector. This is called a *buffer -overread* and can lead to security vulnerabilities if an attacker is able to -manipulate the index in such a way as to read data they shouldn’t be allowed to -that is stored after the array. + + + + + + + -To protect your program from this sort of vulnerability, if you try to read an -element at an index that doesn’t exist, Rust will stop execution and refuse to -continue. Let’s try it and see: +他の言語(Cなど)では、この場面で欲しいものではないにもかかわらず、まさしく要求したものを返そうとしてきます: +メモリがベクタに属していないにもかかわらず、ベクタ内のその要素に対応するメモリ上の箇所にあるものを何か返してくるのです。 +これは、*バッファー外読み出し*(buffer overread; `脚注`: 初めて見かけた表現。Rust独自?)と呼ばれ、 +攻撃者が、配列の後に格納された読めるべきでないデータを読み出せるように添え字を操作できたら、 +セキュリティ脆弱性につながる可能性があります。 + + + + + +この種の脆弱性からプログラムを保護するために、存在しない番号の要素を読もうとしたら、 +Rustは実行を中止し、継続を拒みます。試して確認してみましょう: ```text $ cargo run @@ -105,25 +168,40 @@ $ cargo run Running `target/debug/panic` thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 100', /stable-dist-rustc/build/src/libcollections/vec.rs:1362 +('main'スレッドは、/stable-dist-rustc/build/src/libcollections/vec.rs:1362の +「境界外番号: 長さは3なのに、添え字は100です」でパニックしました) note: Run with `RUST_BACKTRACE=1` for a backtrace. error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) ``` -This error points at a file we didn’t write, *libcollections/vec.rs*. That’s -the implementation of `Vec` in the standard library. The code that gets run -when we use `[]` on our vector `v` is in *libcollections/vec.rs*, and that is -where the `panic!` is actually happening. - -The next note line tells us that we can set the `RUST_BACKTRACE` environment -variable to get a backtrace of exactly what happened to cause the error. A -*backtrace* is a list of all the functions that have been called to get to this -point. Backtraces in Rust work like they do in other languages: the key to -reading the backtrace is to start from the top and read until you see files you -wrote. That’s the spot where the problem originated. The lines above the lines -mentioning your files are code that your code called; the lines below are code -that called your code. These lines might include core Rust code, standard -library code, or crates that you’re using. Let’s try getting a backtrace: -Listing 9-2 shows output similar to what you’ll see: + + + + + +このエラーは、自分のファイルではない*libcollections/vec.rs*ファイルを指しています。 +標準ライブラリの`Vec`の実装です。ベクタ`v`に対して`[]`を使った時に走るコードは、 +*libcollections/vec.rs*に存在し、ここで実際に`panic!`が発生しているのです。 + + + + + + + + + + + + +その次の注釈行は、`RUST_BACKTRACE`環境変数をセットして、まさしく何が起き、 +エラーが発生したのかのバックトレースを得られることを教えてくれています。 +*バックトレース*とは、ここに至るまでに呼び出された全関数の一覧です。Rustのバックトレースも、 +他の言語同様に動作します: バックトレースを読むコツは、頭からスタートして自分のファイルを見つけるまで読むことです。 +そこが、問題の根源になるのです。自分のファイルを言及している箇所以前は、コードで呼び出したコードになります; +以後は、自分のコードを呼び出しているコードになります。これらの行には、Rustの核となるコード、標準ライブラリのコード、 +使用しているクレートなどが含まれるかもしれません。バックトレースを出力してみましょう: +リスト9-2のような出力が得られるでしょう: ```text $ RUST_BACKTRACE=1 cargo run @@ -165,26 +243,45 @@ stack backtrace: 17: 0x0 - ``` -Listing 9-2: The backtrace generated by a call to -`panic!` displayed when the environment variable `RUST_BACKTRACE` is set - -That’s a lot of output! The exact output you see might be different depending -on your operating system and Rust version. In order to get backtraces with this -information, debug symbols must be enabled. Debug symbols are enabled by -default when using cargo build or cargo run without the --release flag, as we -have here. - -In the output in Listing 9-2, line 11 of the backtrace points to the line in -our project that’s causing the problem: *src/main.rs* in line 4. If we don’t -want our program to panic, the location pointed to by the first line mentioning -a file we wrote is where we should start investigating to figure out how we got -to this location with values that caused the panic. In Listing 9-1 where we -deliberately wrote code that would panic in order to demonstrate how to use -backtraces, the way to fix the panic is to not request an element at index 100 -from a vector that only contains three items. When your code panics in the -future, you’ll need to figure out what action the code is taking with what -values that causes the panic and what the code should do instead. - -We’ll come back to `panic!` and when we should and should not use `panic!` to -handle error conditions later in the chapter. Next, we’ll look at how to -recover from an error using `Result`. + + + +リスト9-2: `RUST_BACKTRACE`環境変数をセットした時に表示される、 +`panic!`呼び出しが生成するバックトレース + + + + + + + +出力が多いですね!OSやRustのバージョンによって、出力の詳細は変わる可能性があります。この情報とともに、 +バックトレースを得るには、デバッグシンボルを有効にしなければなりません。デバッグシンボルは、 +--releaseオプションなしでcargo buildやcargo runを使用していれば、標準で有効になり、 +ここではそうなっています。 + + + + + + + + + + + + +リスト9-2の出力で、バックトレースの11行目が問題発生箇所を指し示しています: *src/main.rs*の4行目です。 +プログラムにパニックしてほしくなければ、自分のファイルについて言及している最初の行で示されている箇所が、 +どのようにパニックを引き起こす値でこの箇所にたどり着いたか割り出すために調査を開始すべき箇所になります。 +バックトレースの使用法を模擬するためにわざとパニックするコードを書いたリスト9-1において、 +パニックを解消する方法は、3つしか要素のないベクタの100番目の要素を要求しないことです。 +将来コードがパニックしたら、パニックを引き起こすどんな値でコードがどんな動作をしているのかと、 +代わりにコードは何をすべきなのかを算出する必要があるでしょう。 + + + + + +また、この章で`panic!`とエラー状態を扱うのに`panic!`を使うべき時と使わぬべき時について触れます。 +次は、`Result`を使用してエラーから回復する方法を見ましょう。 From 77ac721922febd9356ff320ff317406318a32813 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 6 Oct 2017 18:53:14 +0900 Subject: [PATCH 061/428] First drafts of the chapters 9-2 and 9-3 --- .../ch09-02-recoverable-errors-with-result.md | 746 ++++++++++++------ .../src/ch09-03-to-panic-or-not-to-panic.md | 538 ++++++++----- 2 files changed, 835 insertions(+), 449 deletions(-) diff --git a/second-edition/src/ch09-02-recoverable-errors-with-result.md b/second-edition/src/ch09-02-recoverable-errors-with-result.md index f3c4abb84..2d8ef7609 100644 --- a/second-edition/src/ch09-02-recoverable-errors-with-result.md +++ b/second-edition/src/ch09-02-recoverable-errors-with-result.md @@ -1,14 +1,23 @@ -## Recoverable Errors with `Result` + -Most errors aren’t serious enough to require the program to stop entirely. -Sometimes, when a function fails, it’s for a reason that we can easily -interpret and respond to. For example, if we try to open a file and that -operation fails because the file doesn’t exist, we might want to create the -file instead of terminating the process. +## `Result`で回復可能なエラー -Recall in Chapter 2 in the on “[Handling Potential Failure with the `Result` -Type][handle_failure]” section that the `Result` enum is 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#handling-potential-failure-with-the-result-type @@ -19,19 +28,29 @@ enum Result { } ``` -The `T` and `E` are generic type parameters: we’ll discuss generics in more -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. + + + + + + + + + +`T`と`E`は、ジェネリックな型引数です: ジェネリクスについて詳しくは、第10章で議論します。 +たった今知っておく必要があることは、`T`が成功した時に`Ok`バリアントに含まれて返される値の型を表すことと、 +`E`が失敗した時に`Err`バリアントに含まれて返されるエラーの型を表すことです。`Result`はこのようなジェネリックな型引数を含むので、 +標準ライブラリ上に定義されている`Result`型や関数などを、成功した時とエラーの値が異なるような様々な場面で使用できるのです。 + + + -Let’s call a function that returns a `Result` value because the function could -fail: in Listing 9-3 we try to open a file: +関数が失敗する可能性があるために`Result`値を返す関数を呼び出しましょう: リスト9-3では、 +ファイルを開こうとしています: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust use std::fs::File; @@ -41,24 +60,35 @@ fn main() { } ``` -Listing 9-3: Opening a file + + +リスト9-3: ファイルを開く + + + + + + + + -How do we know `File::open` returns a `Result`? We could look at the standard -library API documentation, or we could ask the compiler! If we give `f` a type -annotation of a type that we know the return type of the function is *not* and -then we try to compile the code, the compiler will tell us that the types don’t -match. The error message will then tell us what the type of `f` *is*. Let’s try -it: we know that the return type of `File::open` isn’t of type `u32`, so let’s -change the `let f` statement to this: +`File::open`が`Result`を返すとどう知るのでしょうか?標準ライブラリのAPIドキュメントを参照することもできますし、 +コンパイラに尋ねることもできます!`f`に関数の戻り値では*ない*と判明している型の型注釈を与えて、 +コードのコンパイルを試みれば、コンパイラは型が合わないと教えてくれるでしょう。そして、エラーメッセージは、 +`f`の*実際の*型を教えてくれるでしょう。試してみましょう: `File::open`の戻り値の型は`u32`ではないと判明しているので、 +`let f`文を以下のように変更しましょう: ```rust,ignore let f: u32 = File::open("hello.txt"); ``` -Attempting to compile now gives us the following output: + + +コンパイルしようとすると、以下のような出力が得られます: ```text error[E0308]: mismatched types +(エラー: 型が合いません) --> src/main.rs:4:18 | 4 | let f: u32 = File::open("hello.txt"); @@ -66,33 +96,51 @@ error[E0308]: mismatched types `std::result::Result` | = note: expected type `u32` + (注釈: 予期した型は`u32`です) = note: found type `std::result::Result` + (注釈: 実際の型は`std::result::Result`です) ``` -This tells us the return type of the `File::open` function is a `Result`. -The generic parameter `T` has been filled in here with the type of the success -value, `std::fs::File`, which is a file handle. The type of `E` used in the -error value is `std::io::Error`. + + + + + +これにより、`File::open`関数の戻り値の型は、`Result`であることがわかります。ジェネリック引数の`T`は、 +ここでは成功値の型`std::fs::File`で埋められていて、これはファイルハンドルです。 +エラー値で使用されている`E`の型は、`std::io::Error`です。 -This return type means the call to `File::open` might succeed and return to us -a file handle that we can read from or write to. The function call also might -fail: for example, the file might not exist or we might not have permission to -access the file. The `File::open` function needs to have a way to tell us -whether it succeeded or failed and at the same time give us either the file -handle or error information. This information is exactly what the `Result` enum -conveys. + + + + + + + -In the case where `File::open` succeeds, the value we will have in the variable -`f` will be an instance of `Ok` that contains a file handle. In the case where -it fails, the value in `f` will be an instance of `Err` that contains more -information about the kind of error that happened. +この戻り値型は、`File::open`の呼び出しが成功し、読み込みと書き込みを行えるファイルハンドルを返す可能性があることを意味します。 +また、関数呼び出しは失敗もする可能性があります: 例えば、ファイルが存在しない可能性、ファイルへのアクセス権限がない可能性です。 +`File::open`には成功したか失敗したかを知らせる方法とファイルハンドルまたは、エラー情報を与える方法が必要なのです。 -We need to add to the code in Listing 9-3 to take different actions depending -on the value `File::open` returned. Listing 9-4 shows one way to handle the -`Result` using a basic tool: the `match` expression that we discussed in -Chapter 6. + + + + -Filename: src/main.rs +`File::open`が成功した場合、変数`f`にはファイルハンドルを含む`Ok`インスタンスが格納されます。 +失敗した場合には、発生したエラーの種類に関する情報をより多く含む`Err`インスタンスが`f`には格納されます。 + + + + + + +リスト9-3のコードに追記をして`File::open`が返す値に応じて異なる動作をする必要があります。 +リスト9-4に基礎的な道具を使って`Result`を扱う方法を一つ示しています: 第6章で議論した`match`式です。 + + + +ファイル名: src/main.rs ```rust,should_panic use std::fs::File; @@ -103,47 +151,75 @@ fn main() { let f = match f { Ok(file) => file, Err(error) => { + // ファイルを開く際に問題がありました panic!("There was a problem opening the file: {:?}", error) }, }; } ``` -Listing 9-4: Using a `match` expression to handle the -`Result` variants we might have + + + +リスト9-4: `match`式を使用して存在する可能性のある`Result`バリアントを処理する -Note that, like the `Option` enum, the `Result` enum and its variants have been -imported in the prelude, so we don’t need to specify `Result::` before the `Ok` -and `Err` variants in the `match` arms. + + + -Here we tell Rust that when the result is `Ok`, return the inner `file` value -out of the `Ok` variant, and we then assign that file handle value to the -variable `f`. After the `match`, we can then use the file handle for reading or -writing. +`Option`enumのように、`Result`enumとそのバリアントは、初期化処理でインポートされているので、 +`match`アーム内で`Ok`と`Err`バリアントの前に`Result::`を指定する必要がないことに注目してください。 -The other arm of the `match` handles the case where we get an `Err` value from -`File::open`. In this example, we’ve chosen to call the `panic!` macro. If -there’s no file named *hello.txt* in our current directory and we run this -code, we’ll see the following output from the `panic!` macro: + + + + + +ここでは、結果が`Ok`の時に、`Ok`バリアントから中身の`file`値を返すように指示し、 +それからそのファイルハンドル値を変数`f`に代入しています。`match`の後には、 +ファイルハンドルを使用して読み込んだり書き込むことができるわけです。 + + + + + + +`match`のもう一つのアームは、`File::open`から`Err`値が得られたケースを処理しています。 +この例では、`panic!`マクロを呼び出すことを選択しています。カレントディレクトリに*hello.txt*というファイルがなく、 +このコードを走らせたら、`panic!`マクロからの以下のような出力を目の当たりにするでしょう: ```text thread 'main' panicked at 'There was a problem opening the file: Error { repr: Os { code: 2, message: "No such file or directory" } }', src/main.rs:8 +('main'スレッドは、src/main.rs:8の「ファイルを開く際に問題がありました: Error{ repr: +Os { code: 2, message: "そのような名前のファイルまたはディレクトリはありません"}}」でパニックしました) ``` -As usual, this output tells us exactly what has gone wrong. + + +通常通り、この出力は、一体何がおかしくなったのかを物語っています。 + + -### Matching on Different Errors +### 色々なエラーにマッチする -The code in Listing 9-4 will `panic!` no matter the reason that `File::open` -failed. What we want to do instead is take different actions for different -failure reasons: if `File::open` failed because the file doesn’t exist, we want -to create the file and return the handle to the new file. If `File::open` -failed for any other reason, for example because we didn’t have permission to -open the file, we still want the code to `panic!` in the same way as it did in -Listing 9-4. Look at Listing 9-5, which adds another arm to the `match`: + + + + + + + -Filename: src/main.rs +リスト9-4のコードは、`File::open`が失敗した理由にかかわらず`panic!`します。代わりにしたいことは、 +異なる失敗理由には異なる動作をすることです: ファイルが存在しないために`File::open`が失敗したら、 +ファイルを作成し、その新しいファイルへのハンドルを返したいです。他の理由(例えばファイルを開く権限がなかったなど)で、 +`File::open`が失敗したら、リスト9-4のようにコードには`panic!`してほしいのです。 +リスト9-5を眺めてください。ここでは`match`に別のアームを追加しています: + + + +ファイル名: src/main.rs @@ -161,6 +237,7 @@ fn main() { match File::create("hello.txt") { Ok(fc) => fc, Err(e) => { + //ファイルを作成しようとしましたが、問題がありました panic!( "Tried to create file but there was a problem: {:?}", e @@ -178,46 +255,77 @@ fn main() { } ``` -Listing 9-5: Handling different kinds of errors in -different ways - -The type of the value that `File::open` returns inside the `Err` variant is -`io::Error`, which is a struct provided by the standard library. This struct -has a method `kind` that we can call to get an `io::ErrorKind` value. -`io::ErrorKind` is an enum provided by the standard library that has variants -representing the different kinds of errors that might result from an `io` -operation. The variant we want to use is `ErrorKind::NotFound`, which indicates -the file we’re trying to open doesn’t exist yet. - -The condition `if error.kind() == ErrorKind::NotFound` is called a *match -guard*: it’s an extra condition on a `match` arm that further refines the arm’s -pattern. This condition must be true for that arm’s code to be run; otherwise, -the pattern matching will move on to consider the next arm in the `match`. The -`ref` in the pattern is needed so `error` is not moved into the guard condition -but is merely referenced by it. The reason `ref` is used to take a reference in -a pattern instead of `&` will be covered in detail in Chapter 18. In short, in -the context of a pattern, `&` matches a reference and gives us its value, but -`ref` matches a value and gives us a reference to it. - -The condition we want to check in the match guard is whether the value returned -by `error.kind()` is the `NotFound` variant of the `ErrorKind` enum. If it is, -we try to create the file with `File::create`. However, because `File::create` -could also fail, we need to add an inner `match` statement as well. When the -file can’t be opened, a different error message will be printed. The last arm -of the outer `match` stays the same so the program panics on any error besides -the missing file error. - -### Shortcuts for Panic on Error: `unwrap` and `expect` - -Using `match` works well enough, but it can be a bit verbose and doesn’t always -communicate intent well. The `Result` type has many helper methods -defined on it to do various tasks. One of those methods, called `unwrap`, is a -shortcut method that is implemented just like the `match` statement we wrote in -Listing 9-4. If the `Result` value is the `Ok` variant, `unwrap` will return -the value inside the `Ok`. If the `Result` is the `Err` variant, `unwrap` will -call the `panic!` macro for us. Here is an example of `unwrap` in action: - -Filename: src/main.rs + + + +リスト9-5: 色々な種類のエラーを異なる方法で扱う + + + + + + + + + +`File::open`が`Err`バリアントに含めて返す値の型は、`io::Error`であり、これは標準ライブラリで提供されている構造体です。 +この構造体には、呼び出すと`io::ErrorKind`値が得られる`kind`メソッドがあります。`io::ErrorKind`は、 +標準ライブラリで提供されているenumであり、`io`処理の結果発生する可能性のある色々な種類のエラーを表すバリアントを持ちます。 +使用したいバリアントは、`ErrorKind::NotFound`で、これは開こうとしているファイルがまだ存在しないことを示唆します。 + + + + + + + + + + + +`if error.kind() == ErrorKind::Notfound`という条件式は、*マッチガード*と呼ばれます: +アームのパターンをさらに洗練する`match`アーム上のおまけの条件式です。この条件式は、 +そのアームのコードが実行されるには真でなければいけないのです; そうでなければ、 +パターンマッチングは継続し、`match`の次のアームを考慮します。パターンの`ref`は、 +`error`がガード条件式にムーブされないように必要ですが、ただガード式に参照されます。 +`ref`を使用して`&`の代わりにパターン内で参照を取っている理由は、第18章で詳しく解説されるでしょう。 +手短に言えば、パターンの文脈において、`&`は参照にマッチし、その値を返すが、 +`ref`は値にマッチし、それへの参照を返すということなのです。 + + + + + + + + + +マッチガードで精査したい条件は、`error.kind()`により返る値が、`ErrorKind`enumの`NotFound`バリアントであるかということです。 +もしそうなら、`File::create`でファイル作成を試みます。ところが、`File::create`も失敗する可能性があるので、 +内部にも`match`文を追加する必要があるのです。ファイルが開けないなら、異なるエラーメッセージが出力されるでしょう。 +外側の`match`の最後のアームは同じままなので、ファイルが行方不明のエラー以外ならプログラムはパニックします。 + + + +### エラー時にパニックするショートカット: `unwrap`と`expect` + + + + + + + + + +`match`の使用は、十分に仕事をしてくれますが、いささか冗長になり得る上、必ずしも意図をよく伝えるとは限りません。 +`Result`型には、色々な作業をするヘルパーメソッドが多く定義されています。それらの関数の一つは、 +`unwrap`と呼ばれますが、リスト9-4で書いた`match`文と同じように実装された短絡メソッドです。 +`Result`値が`Ok`バリアントなら、`unwrap`は`Ok`の中身を返します。`Result`が`Err`バリアントなら、 +`unwrap`は`panic!`マクロを呼んでくれます。こちらが実際に動作している`unwrap`の例です: + + + +ファイル名: src/main.rs ```rust,should_panic use std::fs::File; @@ -227,34 +335,50 @@ fn main() { } ``` -If we run this code without a *hello.txt* file, we’ll see an error message from -the `panic!` call that the `unwrap` method makes: + + + +このコードを*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" } }', /stable-dist-rustc/build/src/libcore/result.rs:868 +('main'スレッドは、/stable-dist-rustc/build/src/libcore/result.rs:868の +「`Err`値に対して`Result::unwrap()`が呼び出されました: Error{ +repr: Os { code: 2, message: "そのようなファイルまたはディレクトリはありません" } }」でパニックしました) ``` -Another method, `expect`, which is similar to `unwrap`, lets us also choose the -`panic!` error message. Using `expect` instead of `unwrap` and providing good -error messages can convey your intent and make tracking down the source of a -panic easier. The syntax of `expect` looks like this: + + + + + +別のメソッド`expect`は、`unwrap`に似ていますが、`panic!`のエラーメッセージも選択させてくれます。 +`unwrap`の代わりに`expect`を使用していいエラーメッセージを提供することは、意図を伝え、 +パニックの原因をたどりやすくしてくれます。`expect`の表記はこんな感じです: + + -Filename: src/main.rs +ファイル名: 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"); } ``` -We use `expect` in the same way as `unwrap`: to return the file handle or call -the `panic!` macro. The error message used by `expect` in its call to `panic!` -will be the parameter that we pass to `expect`, rather than the default -`panic!` message that `unwrap` uses. Here’s what it looks like: + + + + + +`expect`を`unwrap`と同じように使用してファイルハンドルを返したり、`panic!`マクロを呼び出しています。 +`expect`が`panic!`呼び出しで使用するエラーメッセージは、`unwrap`が使用するデフォルトの`panic!`メッセージではなく、 +`expect`に渡した引数になります。以下のようになります: ```text thread 'main' panicked at 'Failed to open hello.txt: Error { repr: Os { code: @@ -262,26 +386,43 @@ thread 'main' panicked at 'Failed to open hello.txt: Error { repr: Os { code: /stable-dist-rustc/build/src/libcore/result.rs:868 ``` -Because this error message starts with the text we specified, `Failed to open -hello.txt`, it will be easier to find where in the code this error message is -coming from. If we use `unwrap` in multiple places, it can take more time to -figure out exactly which `unwrap` is causing the panic because all `unwrap` -calls that panic print the same message. + + + + + + +このエラーメッセージは、指定したテキストの`hello.txtを開くのに失敗しました`で始まっているので、 +コード内のどこでエラーメッセージが出力されたのかより見つけやすくなるでしょう。複数箇所で`unwrap`を使用していたら、 +ズバリどの`unwrap`がパニックを引き起こしているのか算出するのは、より時間がかかる可能性があります。 +パニックする`unwrap`呼び出しは全て、同じメッセージを出力するからです。 + + + +### エラーを委譲する + + + + + + + -### Propagating Errors +失敗する可能性のある何かを呼び出す実装をした関数を書く際、関数内でエラーを処理する代わりに、 +呼び出し元がどうするかを決められるようにエラーを返すことができます。これはエラーの*委譲*として認知され、 +呼び出し元に自分のコードの文脈で利用可能なものよりも、 +エラーの処理法を規定する情報やロジックがより多くある箇所を制御してもらいます。 -When you’re writing a function whose implementation calls something that might -fail, instead of handling the error within this function, you can return the -error to the calling code so that it can decide what to do. This is known as -*propagating* the error and gives more control to the calling code where there -might be more information or logic that dictates how the error should be -handled than what you have available in the context of your code. + + + -For example, Listing 9-6 shows a function that reads a username from a file. If -the file doesn’t exist or can’t be read, this function will return those errors -to the code that called this function: +例えば、リスト9-6の関数は、ファイルからユーザ名を読み取ります。ファイルが存在しなかったり、読み込みできなければ、 +この関数はそのようなエラーを呼び出し元のコードに返します: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust use std::io; @@ -305,60 +446,98 @@ fn read_username_from_file() -> Result { } ``` -Listing 9-6: A function that returns errors to the -calling code using `match` - -Let’s look at the return type of the function first: `Result`. This means the function is returning a value of the type -`Result` where the generic parameter `T` has been filled in with the -concrete type `String`, and the generic type `E` has been filled in with the -concrete type `io::Error`. If this function succeeds without any problems, the -code that calls this function will receive an `Ok` value that holds a -`String`—the username that this function read from the file. If this function -encounters any problems, the code that calls this function will receive an -`Err` value that holds an instance of `io::Error` that contains more -information about what the problems were. We chose `io::Error` as the return -type of this function because that happens to be the type of the error value -returned from both of the operations we’re calling in this function’s body that -might fail: the `File::open` function and the `read_to_string` method. - -The body of the function starts by calling the `File::open` function. Then we -handle the `Result` value returned with a `match` similar to the `match` in -Listing 9-4, only instead of calling `panic!` in the `Err` case, we return -early from this function and pass the error value from `File::open` back to the -calling code as this function’s error value. If `File::open` succeeds, we store -the file handle in the variable `f` and continue. - -Then we create a new `String` in variable `s` and call the `read_to_string` -method on the file handle in `f` to read the contents of the file into `s`. The -`read_to_string` method also returns a `Result` because it might fail, even -though `File::open` succeeded. So we need another `match` to handle that -`Result`: if `read_to_string` succeeds, then our function has succeeded, and we -return the username from the file that’s now in `s` wrapped in an `Ok`. If -`read_to_string` fails, we return the error value in the same way that we -returned the error value in the `match` that handled the return value of -`File::open`. However, we don’t need to explicitly say `return`, because this -is the last expression in the function. - -The code that calls this code will then handle getting either an `Ok` value -that contains a username or an `Err` value that contains an `io::Error`. We -don’t know what the calling code will do with those values. If the calling code -gets an `Err` value, it could call `panic!` and crash the program, use a -default username, or look up the username from somewhere other than a file, for -example. We don’t have enough information on what the calling code is actually -trying to do, so we propagate all the success or error information upwards for -it to handle appropriately. - -This pattern of propagating errors is so common in Rust that Rust provides the -question mark operator `?` to make this easier. - -#### A Shortcut for Propagating Errors: `?` - -Listing 9-7 shows an implementation of `read_username_from_file` that has the -same functionality as it had in Listing 9-6, but this implementation uses the -question mark operator: - -Filename: src/main.rs + + + +リスト9-6: `match`でエラーを呼び出し元のコードに返す関数 + + + + + + + + + + + + + + + +まずは、関数の戻り値型に注目しましょう: `Result`です。つまり、この関数は、 +`Result`型の値を返しているということです。ここでジェネリック引数の`T`は、具体型`String`で埋められ、 +ジェネリック引数の`E`は具体型`io::Error`で埋められています。この関数が何の問題もなく成功すれば、 +この関数を呼び出したコードは、`String`(関数がファイルから読み取ったユーザ名)を保持する`Ok`値を受け取ります。 +この関数が何かエラーに行き当たったら、呼び出し元のコードは`io::Error`のインスタンスを保持する`Err`値を受け取り、 +この`io::Error`は問題の内容に関する情報をより多く含んでいます。関数の戻り値の型に`io::Error`を選んだのは、 +この関数本体で呼び出している失敗する可能性のある処理が両方ともたまたまこの型をエラー値として返すからです: +`File::open`関数と`read_to_string`メソッドです。 + + + + + + + + +関数の本体は、`File::open`関数を呼び出すとこから始まります。そして、リスト9-4の`match`に似た`match`で返ってくる`Result`値を扱い、 +`Err`ケースに`panic!`を呼び出す代わりだけですが、この関数から早期リターンしてこの関数のエラー値として、 +`File::open`から得たエラー値を呼び出し元に渡し返します。`File::open`が成功すれば、 +ファイルハンドルを変数`f`に保管して継続します。 + + + + + + + + + + + + +さらに、変数`s`に新規`String`を生成し、`f`のファイルハンドルに対して`read_to_string`を呼び出して、 +ファイルの中身を`s`に読み出します。`File::open`が成功しても、失敗する可能性があるので、`read_to_string`メソッドも、 +`Result`を返却します。その`Result`を処理するために別の`match`が必要になります: `read_to_string`が成功したら、 +関数は成功し、今は`Ok`に包まれた`s`に入っているファイルのユーザ名を返却します。`read_to_string`が失敗したら、 +`File::open`の戻り値を扱った`match`でエラー値を返したように、エラー値を返します。 +しかし、明示的に`return`を述べる必要はありません。これが関数の最後の式だからです。 + + + + + + + + + + +そうしたら、呼び出し元のコードは、ユーザ名を含む`Ok`値か、`io::Error`を含む`Err`値を得て扱います。 +呼び出し元のコードがそれらの値をどうするかはわかりません。呼び出しコードが`Err`値を得たら、 +例えば、`panic!`を呼び出してプログラムをクラッシュさせたり、デフォルトのユーザ名を使ったり、 +ファイル以外の場所からユーザ名を検索したりできるでしょう。呼び出し元のコードが実際に何をしようとするかについて、 +十分な情報がないので、成功や失敗情報を全て委譲して適切に扱えるようにするのです。 + + + + +Rustにおいて、この種のエラー委譲は非常に一般的なので、Rustにはこれをしやすくする`?`演算子が用意されています。 + + + +#### エラー委譲のショートカット: `?` + + + + + +リスト9-7もリスト9-6と同じ機能を有する`read_username_from_file`の実装ですが、 +こちらははてなマーク演算子を使用しています: + + + +ファイル名: src/main.rs ```rust use std::io; @@ -373,42 +552,67 @@ fn read_username_from_file() -> Result { } ``` -Listing 9-7: A function that returns errors to the -calling code using `?` - -The `?` placed after a `Result` value is defined to work in almost the same way -as the `match` expressions we defined to handle the `Result` values in Listing -9-6. If the value of the `Result` is an `Ok`, the value inside the `Ok` will -get returned from this expression and the program will continue. If the value -is an `Err`, the value inside the `Err` will be returned from the whole -function as if we had used the `return` keyword so the error value gets -propagated to the calling code. - -The one difference between the `match` expression from Listing 9-6 and what the -question mark operator does is that when using the question mark operator, -error values go through the `from` function defined in the `From` trait in the -standard library. Many error types implement the `from` function to convert an -error of one type into an error of another type. When used by the question mark -operator, the call to the `from` function converts the error type that the -question mark operator gets into the error type defined in the return type of -the current function that we’re using `?` in. This is useful when parts of a -function might fail for many different reasons, but the function returns one -error type that represents all the ways the function might fail. As long as -each error type implements the `from` function to define how to convert itself -to the returned error type, the question mark operator takes care of the -conversion automatically. - -In the context of Listing 9-7, the `?` at the end of the `File::open` call will -return the value inside an `Ok` to the variable `f`. If an error occurs, `?` -will return early out of the whole function and give any `Err` value to the -calling code. The same thing applies to the `?` at the end of the -`read_to_string` call. - -The `?` eliminates a lot of boilerplate and makes this function’s -implementation simpler. We could even shorten this code further by chaining -method calls immediately after the `?` as shown in Listing 9-8: - -Filename: src/main.rs + + + +リスト9-7: `?`でエラーを呼び出し元に返す関数 + + + + + + + + + +`Result`値の直後に置かれた`?`は、リスト9-6で`Result`値を処理するために定義した`match`式とほぼ同じように動作します。 +`Result`の値が`Ok`なら、`Ok`の中身がこの式から返ってきて、プログラムは継続します。値が`Err`なら、 +`return`キーワードを使ったかのように関数全体から`Err`の中身が返ってくるので、 +エラー値は呼び出し元のコードに委譲されます。 + + + + + + + + + + + + + + + +リスト9-6の`match`式とはてなマーク演算子の唯一の違いは、はてなマークを使った時、 +エラー値は標準ライブラリの`From`トレイトで定義されている`from`関数を通ることです。 +多くのエラー型が、ある種から別種のエラー型に変換できる`from`関数を実装しています。 +はてなマークで使用されると、`from`関数の呼び出しは、 +はてな演算子が得たエラー型を演算子が使用されている関数の返り値型に変換してくれます。 +この挙動は、関数のいろんな場所でいろいろな理由により失敗する可能性がある時に有用ですが、 +関数は失敗する全ての方法を表す一つのエラー型を返します。各エラー型が`from`関数を実装して返り値のエラー型への変換を定義している限り、 +はてなマークが変換の面倒を自動的に見てくれます。 + + + + + + + +リスト9-7の文脈では、`File::open`呼び出し末尾の`?`は`Ok`の中身を変数`f`に返します。 +エラーが発生したら、`?`により関数全体から早期リターンし、あらゆる`Err`値を呼び出し元に与えます。 +同じ法則が`read_to_string`呼び出し末尾の`?`にも適用されます。 + + + + + +`?`により定型コードの多くが排除され、この関数の実装を単純にしてくれます。 +リスト9-8で示したように、`?`の直後のメソッド呼び出しを連結することでさらにこのコードを短くすることさえもできます: + + + +ファイル名: src/main.rs ```rust use std::io; @@ -424,28 +628,44 @@ fn read_username_from_file() -> Result { } ``` -Listing 9-8: Chaining method calls after the question -mark operator + + + +リスト9-8: はてなマークの後のメソッド呼び出しを連結する + + + + + + + + + + +`s`の新規`String`の生成を関数の冒頭に移動しました; その部分は変化していません。変数`f`を生成する代わりに、 +`read_to_string`の呼び出しを直接`File::open("hello.txt")?`の結果に連結させました。 +それでも、`read_to_string`呼び出しの末尾には`?`があり、`File::open`と`read_to_string`両方が成功したら、 +エラーを返すというよりもまだ`s`にユーザ名を含む`Ok`値を返します。機能もまたリスト9-6及び、9-7と同じです; +ただ単に異バージョンのよりプログラマフレンドリーな書き方なのです。 + + -We’ve moved the creation of the new `String` in `s` to the beginning of the -function; that part hasn’t changed. Instead of creating a variable `f`, we’ve -chained the call to `read_to_string` directly onto the result of -`File::open("hello.txt")?`. We still have a `?` at the end of the -`read_to_string` call, and we still return an `Ok` value containing the -username in `s` when both `File::open` and `read_to_string` succeed rather than -returning errors. The functionality is again the same as in Listing 9-6 and -Listing 9-7; this is just a different, more ergonomic way to write it. +#### `?`は、結果を返す関数でしか使用できない -#### `?` Can Only Be Used in Functions That Return Result + + + + + -The `?` can only be used in functions that have a return type of `Result`, -because it is defined to work in the same way as the `match` expression we -defined in Listing 9-6. The part of the `match` that requires a return type of -`Result` is `return Err(e)`, so the return type of the function must be a -`Result` to be compatible with this `return`. +`?`は戻り値に`Result`を持つ関数でしか使用できません。というのも、リスト9-6で定義した`match`式と同様に動作するよう、 +定義されているからです。`Result`の戻り値型を要求する`match`の部品は、`return Err(e)`なので、 +関数の戻り値はこの`return`と互換性を保つために`Result`でなければならないのです。 -Let’s look at what happens if we use `?` in the `main` function, which you’ll -recall has a return type of `()`: + + + +`main`関数で`?`を使用したらどうなるか見てみましょう。`main`関数は、戻り値が`()`でしたね: ```rust,ignore use std::fs::File; @@ -455,11 +675,15 @@ fn main() { } ``` -When we compile this code, we get the following error message: + + +このコードをコンパイルすると、以下のようなエラーメッセージが得られます: ```text error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`) +(エラー: `?`演算子は`Result`(または`std::ops::Try`を実装する別の型)を返す関数でしか +使用できません) --> src/main.rs:4:13 | 4 | let f = File::open("hello.txt")?; @@ -467,17 +691,27 @@ error[E0277]: the `?` operator can only be used in a function that returns | | | cannot use the `?` operator in a function that returns `()` | in this macro invocation + | (このマクロ呼び出しの`()`を返す関数では、`?`演算子を使用できません) | = 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`で要求されています) ``` -This error points out that we’re only allowed to use the question mark operator -in a function that returns `Result`. In functions that don’t return `Result`, -when you call other functions that return `Result`, you’ll need to use a -`match` or one of the `Result` methods to handle it instead of using `?` to -potentially propagate the error to the calling code. + + + + + + +このエラーは、はてなマーク演算子は`Result`を返す関数でしか使用が許可されないと指摘しています。 +`Result`を返さない関数では、`Result`を返す別の関数を呼び出した時、 +`?`を使用してエラーを呼び出し元に委譲する可能性を生み出す代わりに、`match`か`Result`のメソッドのどれかを使う必要があるでしょう。 + + + + -Now that we’ve discussed the details of calling `panic!` or returning `Result`, -let’s return to the topic of how to decide which is appropriate to use in which -cases. +さて、`panic!`呼び出しや`Result`を返す詳細について議論し終えたので、 +どんな場合にどちらを使うのが適切か決める方法についての話に戻りましょう。 diff --git a/second-edition/src/ch09-03-to-panic-or-not-to-panic.md b/second-edition/src/ch09-03-to-panic-or-not-to-panic.md index ef2df322f..494648819 100644 --- a/second-edition/src/ch09-03-to-panic-or-not-to-panic.md +++ b/second-edition/src/ch09-03-to-panic-or-not-to-panic.md @@ -1,51 +1,88 @@ -## To `panic!` or Not to `panic!` - -So how do you decide when you should `panic!` and when you should return -`Result`? When code panics, there’s no way to recover. You could call `panic!` -for any error situation, whether there’s a possible way to recover or not, but -then you’re making the decision on behalf of the code calling your code that a -situation is unrecoverable. When you choose to return a `Result` value, you -give the calling code options rather than making the decision for it. The -calling code could choose to attempt to recover in a way that’s appropriate for -its situation, or it could decide that an `Err` value in this case is -unrecoverable, so it can call `panic!` and turn your recoverable error into an -unrecoverable one. Therefore, returning `Result` is a good default choice when -you’re defining a function that might fail. - -In a few situations it’s more appropriate to write code that panics instead of -returning a `Result`, but they are less common. Let’s explore why it’s -appropriate to panic in examples, prototype code, and tests; then in situations -where you as a human can know a method won’t fail that the compiler can’t -reason about; and conclude with some general guidelines on how to decide -whether to panic in library code. - -### Examples, Prototype Code, and Tests Are All Places it’s Perfectly Fine to Panic - -When you’re writing an example to illustrate some concept, having robust error -handling code in the example as well can make the example less clear. In -examples, it’s understood that a call to a method like `unwrap` that could -`panic!` is meant as a placeholder for the way that you’d want your application -to handle errors, which can differ based on what the rest of your code is doing. - -Similarly, the `unwrap` and `expect` methods are very handy when prototyping, -before you’re ready to decide how to handle errors. They leave clear markers in -your code for when you’re ready to make your program more robust. - -If a method call fails in a test, we’d want the whole test to fail, even if -that method isn’t the functionality under test. Because `panic!` is how a test -is marked as a failure, calling `unwrap` or `expect` is exactly what should -happen. - -### Cases When You Have More Information Than the Compiler - -It would also be appropriate to call `unwrap` when you have some other logic -that ensures the `Result` will have an `Ok` value, but the logic isn’t -something the compiler understands. You’ll still have a `Result` value that you -need to handle: whatever operation you’re calling still has the possibility of -failing in general, even though it’s logically impossible in your particular -situation. If you can ensure by manually inspecting the code that you’ll never -have an `Err` variant, it’s perfectly acceptable to call `unwrap`. Here’s an -example: + + +## `panic!`すべきかするまいか + + + + + + + + + + + + + +では、`panic!`すべき時と`Result`を返すべき時はどう決定すればいいのでしょうか?コードがパニックしたら、 +回復する手段はありません。回復する可能性のある手段の有る無しに関わらず、どんなエラー場面でも`panic!`を呼ぶことはできますが、 +そうすると、呼び出す側のコードの立場に立ってこの場面は回復不能だという決定を下すことになります。 +`Result`値を返す決定をすると、決断を下すのではなく、呼び出し側に選択肢を与えることになります。 +呼び出し側は、場面に合わせて回復を試みることを決定したり、この場合の`Err`値は回復不能と断定して、 +`panic!`を呼び出し、回復可能だったエラーを回復不能に変換することもできます。故に、`Result`を返却することは、 +失敗する可能性のある関数を定義する際には、いい第1選択肢になります。 + + + + + + + + +いくつかの事例では、`Result`を返すよりもパニックするコードを書く方が適切になることもありますが、 +あまり一般的ではありません。例やプロトタイプコード、テストでパニックするのが適切な理由を探求しましょう; +それから人間として、コンパイラは推定不能だけど、メソッドが失敗すると把握できる場面に移りましょう; +そして、ライブラリコードでパニックするか決定する方法についての一般的なガイドラインで結論づけましょう。 + + + +### 例、プロトタイプコード、テストは全てパニックするのが完全に合理的な箇所である + + + + + + + +例を記述して何らかの概念を具体化している時、頑健なエラー処理コードも例に含むことは、例の明瞭さを欠くことになりかねません。 +例では、`unwrap`などの`panic!`する可能性のあるメソッド呼び出しは、 +アプリケーションにエラーを処理してほしい方法へのプレースホルダーを意味していると理解され、 +これは残りのコードがしていることによって異なる可能性があります。 + + + + + +同様に、`unwrap`や`expect`メソッドは、エラーの処理法を決定する準備ができる前、プロトタイプの段階では、 +非常に便利です。それらにより、コードにプログラムをより頑健にする時の明らかなマーカが残されるわけです。 + + + + + + +メソッド呼び出しがテスト内で失敗したら、そのメソッドがテスト下に置かれた機能ではなかったとしても、 +テスト全体が失敗してほしいでしょう。`panic!`が、テストが失敗と印づけられる手段なので、 +`unwrap`や`expect`はスバリ起こるべきことです。 + + + +### コンパイラよりもプログラマがより情報を持っている場合 + + + + + + + + + + +`Result`が`Ok`値であると確認する何らかの別のロジックがある場合、`unwrap`を呼び出すことは適切でしょうが、 +コンパイラは、そのロジックを理解はしません。それでも、処理する必要のある`Result`は存在するでしょう: +呼び出している処理が何であれ、自分の特定の場面では論理的に起こり得なくても、一般的にまだ失敗する可能性はあるわけです。 +手動でコードを調査して`Err`バリアントは存在しないと確認できたら、`unwrap`を呼び出すことは完全に受容できることです。 +こちらが例です: ```rust use std::net::IpAddr; @@ -53,88 +90,152 @@ use std::net::IpAddr; let home = "127.0.0.1".parse::().unwrap(); ``` -We’re creating an `IpAddr` instance by parsing a hardcoded string. We can see -that `127.0.0.1` is a valid IP address, so it’s acceptable to use `unwrap` -here. However, having a hardcoded, valid string doesn’t change the return type -of the `parse` method: we still get a `Result` value, and the compiler will -still make us handle the `Result` as if the `Err` variant is still a -possibility because the compiler isn’t smart enough to see that this string is -always a valid IP address. If the IP address string came from a user rather -than being hardcoded into the program, and therefore *did* have a possibility -of failure, we’d definitely want to handle the `Result` in a more robust way -instead. - -### Guidelines for Error Handling - -It’s advisable to have your code `panic!` when it’s possible that your code -could end up in a bad state. In this context, bad state is when some -assumption, guarantee, contract, or invariant has been broken, such as when -invalid values, contradictory values, or missing values are passed to your -code—plus one or more of the following: - -* The bad state is not something that’s *expected* to happen occasionally. -* Your code after this point needs to rely on not being in this bad state. -* There’s not a good way to encode this information in the types you use. - -If someone calls your code and passes in values that don’t make sense, the best -choice might be to `panic!` and alert the person using your library to the bug -in their code so they can fix it during development. Similarly, `panic!` is -often appropriate if you’re calling external code that is out of your control, -and it returns an invalid state that you have no way of fixing. - -When a bad state is reached, but it’s expected to happen no matter how well you -write your code, it’s still more appropriate to return a `Result` rather than -making a `panic!` call. Examples of this 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, you should indicate that failure is an expected -possibility by returning a `Result` to propagate these bad states upwards so -the calling code can decide how to handle the problem. To `panic!` wouldn’t be -the best way to handle these cases. - -When your code performs operations on values, your code should verify the -values are valid first, and `panic!` if the values aren’t valid. This is mostly -for safety reasons: attempting to operate on invalid data can expose your code -to vulnerabilities. This is the main reason the standard library will `panic!` -if you attempt an out-of-bounds memory access: trying to access memory that -doesn’t belong to the current data structure is a common security problem. -Functions often have *contracts*: their behavior is only guaranteed if the -inputs meet particular requirements. Panicking when the contract is violated -makes sense because a contract violation always indicates a caller-side bug, -and it’s not a kind of error you want the calling code to have to explicitly -handle. In fact, there’s no reasonable way for calling code to recover: the -calling *programmers* need to fix the code. Contracts for a function, -especially when a violation will cause a panic, should be explained in the API -documentation for the function. - -However, having lots of error checks in all of your functions would be verbose -and annoying. Fortunately, you can use Rust’s type system (and thus the type -checking the compiler does) to do many of the checks for you. If your function -has a particular type as a parameter, you can proceed with your code’s logic -knowing that the compiler has already ensured you have a valid value. For -example, if you have a type rather than an `Option`, your program expects to -have *something* rather than *nothing*. Your code then doesn’t have to handle -two cases for the `Some` and `None` variants: it will only have one case for -definitely having a value. Code trying to pass nothing to your function won’t -even compile, so your function doesn’t have to check for that case at runtime. -Another example is using an unsigned integer type like `u32`, which ensures the -parameter is never negative. - -### Creating Custom Types for Validation - -Let’s take the idea of using Rust’s type system to ensure we have a valid value -one step further and look at creating a custom type for validation. Recall the -guessing game in Chapter 2 where 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 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. - -One way to do this would be to parse the guess as an `i32` instead of only a -`u32` to allow potentially negative numbers, and then add a check for the -number being in range, like so: + + + + + + + + + + + +ハードコードされた文字列を構文解析することで`IpAddr`インスタンスを生成しています。 +プログラマには`127.0.0.1`が有効なIPアドレスであることがわかるので、ここで`unwrap`を使用することは、 +受容可能です。しかしながら、ハードコードされた有効な文字列が存在することは、 +`parse`メソッドの戻り値型を変えることにはなりません: それでも得られるのは、`Result`値であり、 +コンパイラはまだ`Err`バリアントになる可能性があるかのように`Result`を処理することを強制してきます。 +コンパイラは、この文字列が常に有効なIPアドレスであると把握できるほど利口ではないからです。 +プログラムにハードコードされるのではなく、IPアドレス文字列がユーザ起源でそれ故に*確かに*失敗する可能性がある場合、 +絶対に`Result`をもっと頑健な方法で代わりに処理する必要があるでしょう。 + + + +### エラー処理のガイドライン + + + + + + + +コードが悪い状態に陥る可能性があるときに`panic!`させるのは、アドバイスされることです。この文脈において、 +悪い状態とは、何らかの前提、保証、契約、不変性が破られたことを言い、例を挙げれば、無効な値、 +矛盾する値、行方不明な値がコードに渡されることと、さらに以下のいずれか一つ以上の状態であります: + + + + + +* 悪い状態がときに起こるとは*想定*されないとき +* この時点以降、この悪い状態にないことを頼りにコードが書かれている場合 +* 使用している型にこの情報をコード化するいい手段がないとき + + + + + + + +誰かが自分のコードを呼び出して筋の通らない値を渡してきたら、最善の選択肢は`panic!`し、 +開発段階で修正できるように自分たちのコードにバグがあることをライブラリ使用者に通知することかもしれません。 +同様に自分の制御下にない外部コードを呼び出し、修正しようのない無効な状態を返すときに`panic!`はしばしば適切です。 + + + + + + + + + + +悪い状態に達すると、どんなにコードをうまく書いても起こると予想されるが、`panic!`呼び出しをするよりもまだ、 +`Result`を返すほうがより適切です。これの例には、不正なデータを渡されたパーサとか、 +訪問制限に引っかかったことを示唆するステータスを返すHTTPリクエストなどが挙げられます。 +このような場合には、呼び出し側が問題の処理方法を決定できるように`Result`を返してこの悪い状態を委譲して、 +失敗が予想される可能性であることを示唆するべきです。`panic!`は、 +これらのケースでは最善策ではないでしょう。 + + + + + + + + + + + + + + + + +コードが値に対して処理を行う場合、コードはまず値が有効であることを確認し、 +値が有効でなければ`panic!`するべきです。これはほぼ安全性上の理由によるものです: 不正なデータの処理を試みると、 +コードを脆弱性に晒す可能性があります。これが、境界外へのメモリアクセスを試みたときに標準ライブラリが`panic!`する主な理由です: +現在のデータ構造に属しないメモリにアクセスを試みることは、ありふれたセキュリティ問題なのです。 +関数にはしばしば*契約*が伴います: 入力が特定の条件を満たすときのみ、振る舞いが保証されるのです。 +契約が侵されたときにパニックすることは、道理が通っています。なぜなら、契約侵害は常に呼び出し側のバグを示唆し、 +呼び出し側に明示的に処理してもらう必要のある種のエラーではないからです。実際に、 +呼び出し側が回復する合理的な手段はありません: 呼び出し側の*プログラマ*がコードを修正する必要があるのです。 +関数の契約は、特に侵害がパニックを引き起こす際には、関数のAPIドキュメント内で説明されているべきです。 + + + + + + + + + + + + + + +ですが、全ての関数でたくさんのエラーチェックを行うことは冗長で煩わしいことでしょう。幸運にも、 +Rustの型システム(故にコンパイラが行う型精査)を使用して多くの精査を行ってもらうことができます。 +関数の引数に特定の型があるなら、有効な値があるとコンパイラがすでに確認していることを把握して、 +コードのロジックに進むことができます。例えば、`Option`以外の型がある場合、プログラムは、 +*何もない*ではなく*何かある*と想定します。そうしたらコードは、 +`Some`と`None`バリアントの2つの場合を処理する必要がなくなるわけです: +確実に値があるという可能性しかありません。関数に何もないことを渡そうとしてくるコードは、 +コンパイルが通りもしませんので、その場合を実行時に精査する必要はないわけです。 +別の例は、`u32`のような符号なし整数を使うことであり、この場合、引数は負には絶対にならないことが確認されます。 + + + +### 有効化のために独自の型を作る + + + + + + + + + + + + +Rustの型システムを使用して有効な値があると確認するというアイディアを一歩先に進め、 +有効化のために独自の型を作ることに目を向けましょう。第2章の数当てゲームで、 +コードがユーザに1から100までの数字を推測するよう求めたことを思い出してください。 +秘密の数字と照合する前にユーザの推測がそれらの値の範囲にあることを全く確認しませんでした; +推測が正であることしか確認しませんでした。この場合、結果はそれほど悲惨なものではありませんでした: +「大きすぎ」、「小さすぎ」という出力は、それでも正しかったでしょう。ユーザを有効な推測に導き、 +ユーザが範囲外の数字を推測したり、例えばユーザが文字を代わりに入力したりしたときに別の挙動をするようにしたら、 +有益な改善になるでしょう。 + + + + + +これをする一つの方法は、ただの`u32`の代わりに`i32`として推測をパースし、負の数になる可能性を許可し、 +それから数字が範囲に収まっているというチェックを追加することでしょう。そう、以下のように: ```rust,ignore loop { @@ -155,23 +256,35 @@ loop { } ``` -The `if` expression checks whether our value is out of range, tells the user -about the problem, and calls `continue` to start the next iteration of the loop -and ask for another guess. After the `if` expression, we can proceed with the -comparisons between `guess` and the secret number knowing that `guess` is -between 1 and 100. + + + + + -However, this is not an ideal solution: if it was absolutely critical that the -program only operated on values between 1 and 100, and it had many functions -with this requirement, it would be tedious (and potentially impact performance) -to have a check like this in every function. +この`if`式が、値が範囲外かどうかをチェックし、ユーザに問題を告知し、`continue`を呼び出してループの次の繰り返しを始め、 +別の推測を求めます。`if`式の後、`guess`は1から100の範囲にあると把握して、`guess`と秘密の数字の比較に進むことができます。 -Instead, we can make a new type and put the validations in a function to create -an instance of the type rather than repeating the validations everywhere. That -way, it’s safe for functions to use the new type in their signatures and -confidently use the values they receive. Listing 9-9 shows one way to define a -`Guess` type that will only create an instance of `Guess` if the `new` function -receives a value between 1 and 100: + + + + + +ところが、これは理想的な解決策ではありません: プログラムが1から100の範囲の値しか処理しないことが間違いなく、 +肝要であり、この要求がある関数の数が多ければ、このようなチェックを全関数で行うことは、 +面倒でパフォーマンスにも影響を及ぼす可能性があるでしょう。 + + + + + + + + +代わりに、新しい型を作ってバリデーションを関数内に閉じ込め、バリデーションを全箇所で繰り返すのではなく、 +その型のインスタンスを生成することができます。そうすれば、関数がその新しい型をシグニチャに用い、 +受け取った値を自信を持って使用することは安全になります。リスト9-9に、`new`関数が1から100までの値を受け取った時のみ、 +`Guess`のインスタンスを生成する`Guess`型を定義する一つの方法を示しました: ```rust pub struct Guess { @@ -195,52 +308,91 @@ impl Guess { } ``` -Listing 9-9: A `Guess` type that will only continue with -values between 1 and 100 - -First, we define a struct named `Guess` that has a field named `value` that -holds a `u32`. This is where the number will be stored. - -Then we implement an associated function named `new` on `Guess` that creates -instances of `Guess` values. The `new` function is defined to have one -parameter named `value` of type `u32` and to return a `Guess`. The code in the -body of the `new` function tests `value` to make sure it’s between 1 and 100. -If `value` doesn’t pass this test, we make a `panic!` call, which will alert -the programmer who is writing the calling code that they have a bug they need -to fix, because creating a `Guess` with a `value` outside this range would -violate the contract that `Guess::new` is relying on. The conditions in which -`Guess::new` might panic should be discussed in its public-facing API -documentation; we’ll cover documentation conventions indicating the possibility -of a `panic!` in the API documentation that you create in Chapter 14. If -`value` does pass the test, we create a new `Guess` with its `value` field set -to the `value` parameter and return the `Guess`. - -Next, we implement a method named `value` that borrows `self`, doesn’t have any -other parameters, and returns a `u32`. This is a kind of method sometimes -called a *getter*, because its purpose is to get some data from its fields and -return it. This public method is necessary because the `value` field of the -`Guess` struct is private. It’s important that the `value` field is private so -code using the `Guess` struct is not allowed to set `value` directly: code -outside the module *must* use the `Guess::new` function to create an instance -of `Guess`, which ensures there’s no way for a `Guess` to have a `value` that -hasn’t been checked by the conditions in the `Guess::new` function. - -A function that has a parameter or returns only numbers between 1 and 100 could -then declare in its signature that it takes or returns a `Guess` rather than a -`u32` and wouldn’t need to do any additional checks in its body. - -## Summary - -Rust’s error handling features are designed to help you write more robust code. -The `panic!` macro signals that your program is in a state it can’t handle and -lets you tell the process to stop instead of trying to proceed with invalid or -incorrect values. The `Result` enum uses Rust’s type system to indicate that -operations might fail in a way that your code could recover from. You can use -`Result` to tell code that calls your code that it needs to handle potential -success or failure as well. Using `panic!` and `Result` in the appropriate -situations will make your code more reliable in the face of inevitable problems. - -Now that you’ve seen useful ways that the standard library uses generics with -the `Option` and `Result` enums, we’ll talk about how generics work and how you -can use them in your code in the next chapter. + + + +リスト9-9: 値が1から100の場合のみ処理を継続する`Guess`型 + + + + +まず、`u32`型の`value`をフィールドに持つ`Guess`という名前の構造体を定義しています。 +ここに数値が保管されます。 + + + + + + + + + + + + + + + +それから`Guess`に`Guess`値のインスタンスを生成する`new`という名前の関連関数を実装しています。 +`new`関数は、`u32`型の`value`という引数を取理、`Guess`を返すように定義されています。 +`new`関数の本体のコードは、`value`をふるいにかけ、1から100の範囲であることを確かめます。 +`value`がふるいに引っかかったら、`panic!`呼び出しを行います。これにより、呼び出しコードを書いているプログラマに、 +修正すべきバグがあると警告します。というのも、この範囲外の`value`で`Guess`を生成することは、 +`Guess::new`が頼りにしている契約を侵害するからです。`Guess::new`がパニックするかもしれない条件は、 +公開されているAPIドキュメントで議論されるべきでしょう; あなたが作成するAPIドキュメントで`panic!`可能性を示唆する、 +ドキュメントの規約は、第14章で解説します。`value`が確かにふるいを通ったら、 +`value`フィールドが`value`引数にセットされた新しい`Guess`を作成して返します。 + + + + + + + + + + + +次に、`self`を借用し、他に引数はなく、`u32`を返す`value`というメソッドを実装します。 +これはときに*ゲッター*と呼ばれる種のメソッドです。目的がフィールドから何らかのデータを得て返すことだからです。 +この公開メソッドは、`Guess`構造体の`value`フィールドが非公開なので、必要になります。 +`value`フィールドが非公開なことは重要であり、そのために`Guess`構造体を使用するコードは、 +直接`value`をセットすることが叶わないのです: モジュール外のコードは、 +`Guess::new`関数を使用して`Guess`のインスタンスを生成し*なければならず*、 +これにより`Guess::new`関数の条件式でチェックされていない`value`が`Guess`に存在する手段はなくなるわけです。 + + + + + +そうしたら、引数を一つ持つか、1から100の範囲の数値のみを返す関数は、シグニチャで`u32`ではなく、 +`Guess`を取るか返し、本体内で追加の確認を行う必要はなくなると宣言できるでしょう。 + + + +## まとめ + + + + + + + + + + +Rustのエラー処理機能は、プログラマがより頑健なコードを書く手助けをするように設計されています。 +`panic!`マクロは、プログラムが処理できない状態にあり、無効だったり不正な値で処理を継続するのではなく、 +プロセスに処理を中止するよう教えることを通知します。`Result`enumは、Rustの型システムを使用して、 +コードが回復可能な方法で処理が失敗するかもしれないことを示唆します。`Result`を使用して、 +呼び出し側のコードに成功や失敗する可能性を処理する必要があることも教えてくれます。 +適切な場面で`panic!`や`Result`を使用することで、必然的な問題の眼前でコードの信頼性を上げてくれます。 + + + + + + +今や、標準ライブラリが`Option`や`Result`enumなどでジェネリクスを有効活用するところを目の当たりにしたので、 +次章では、ジェネリクスの動作法と自分のコードでの使用方法について語りましょう。 From 9c9b746d6c9a38f0ef93d957ed85adce906d93a5 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 6 Oct 2017 19:59:23 +0900 Subject: [PATCH 062/428] Remove an unnecessary git merge header --- second-edition/src/ch05-01-defining-structs.md | 1 - 1 file changed, 1 deletion(-) diff --git a/second-edition/src/ch05-01-defining-structs.md b/second-edition/src/ch05-01-defining-structs.md index 34137a242..7b9938aab 100644 --- a/second-edition/src/ch05-01-defining-structs.md +++ b/second-edition/src/ch05-01-defining-structs.md @@ -287,7 +287,6 @@ let user2 = User { リスト5-7: 構造体更新記法を使用して、新しい`User`インスタンス用の値に新しい`email`と`username`をセットしつつ、 残りの値は、`user1`変数のフィールド値を使う -<<<<<<< HEAD From a37a50534683316e345af0af065052c55d37646b Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 16 Oct 2017 20:27:19 +0900 Subject: [PATCH 063/428] Fix some errors in the chapter 9 --- .../ch09-01-unrecoverable-errors-with-panic.md | 4 ++-- .../ch09-02-recoverable-errors-with-result.md | 9 +++++---- .../src/ch09-03-to-panic-or-not-to-panic.md | 18 +++++++++--------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md b/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md index 4ae74b440..f971b8de6 100644 --- a/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md +++ b/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md @@ -40,7 +40,7 @@ > OSが片付ける必要があります。プロジェクトにおいて、実行可能ファイルを極力小さくする必要があれば、 > *Cargo.toml*ファイルの適切な`[profile]`欄に`panic = 'abort'`を追記することで、 > パニック時に巻き戻しから異常終了するように切り替えることができます。例として、 -> リリースモード時に異常するようにしたければ、以下を追記してください: +> リリースモード時に異常終了するようにしたければ、以下を追記してください: > > ```toml > [profile.release] @@ -198,7 +198,7 @@ error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) エラーが発生したのかのバックトレースを得られることを教えてくれています。 *バックトレース*とは、ここに至るまでに呼び出された全関数の一覧です。Rustのバックトレースも、 他の言語同様に動作します: バックトレースを読むコツは、頭からスタートして自分のファイルを見つけるまで読むことです。 -そこが、問題の根源になるのです。自分のファイルを言及している箇所以前は、コードで呼び出したコードになります; +そこが、問題の根源になるのです。自分のファイルを言及している箇所以前は、自分のコードで呼び出したコードになります; 以後は、自分のコードを呼び出しているコードになります。これらの行には、Rustの核となるコード、標準ライブラリのコード、 使用しているクレートなどが含まれるかもしれません。バックトレースを出力してみましょう: リスト9-2のような出力が得られるでしょう: diff --git a/second-edition/src/ch09-02-recoverable-errors-with-result.md b/second-edition/src/ch09-02-recoverable-errors-with-result.md index 2d8ef7609..c31892c89 100644 --- a/second-edition/src/ch09-02-recoverable-errors-with-result.md +++ b/second-edition/src/ch09-02-recoverable-errors-with-result.md @@ -121,6 +121,7 @@ error[E0308]: mismatched types この戻り値型は、`File::open`の呼び出しが成功し、読み込みと書き込みを行えるファイルハンドルを返す可能性があることを意味します。 また、関数呼び出しは失敗もする可能性があります: 例えば、ファイルが存在しない可能性、ファイルへのアクセス権限がない可能性です。 `File::open`には成功したか失敗したかを知らせる方法とファイルハンドルまたは、エラー情報を与える方法が必要なのです。 +この情報こそが`Result`enumが意図するものなのです。 @@ -376,7 +377,7 @@ fn main() { -`expect`を`unwrap`と同じように使用してファイルハンドルを返したり、`panic!`マクロを呼び出しています。 +`expect`を`unwrap`と同じように使用してます: ファイルハンドルを返したり、`panic!`マクロを呼び出しています。 `expect`が`panic!`呼び出しで使用するエラーメッセージは、`unwrap`が使用するデフォルトの`panic!`メッセージではなく、 `expect`に渡した引数になります。以下のようになります: @@ -469,7 +470,7 @@ fn read_username_from_file() -> Result { `Result`型の値を返しているということです。ここでジェネリック引数の`T`は、具体型`String`で埋められ、 ジェネリック引数の`E`は具体型`io::Error`で埋められています。この関数が何の問題もなく成功すれば、 この関数を呼び出したコードは、`String`(関数がファイルから読み取ったユーザ名)を保持する`Ok`値を受け取ります。 -この関数が何かエラーに行き当たったら、呼び出し元のコードは`io::Error`のインスタンスを保持する`Err`値を受け取り、 +この関数が何か問題に行き当たったら、呼び出し元のコードは`io::Error`のインスタンスを保持する`Err`値を受け取り、 この`io::Error`は問題の内容に関する情報をより多く含んでいます。関数の戻り値の型に`io::Error`を選んだのは、 この関数本体で呼び出している失敗する可能性のある処理が両方ともたまたまこの型をエラー値として返すからです: `File::open`関数と`read_to_string`メソッドです。 @@ -481,7 +482,7 @@ fn read_username_from_file() -> Result { -関数の本体は、`File::open`関数を呼び出すとこから始まります。そして、リスト9-4の`match`に似た`match`で返ってくる`Result`値を扱い、 +関数の本体は、`File::open`関数を呼び出すところから始まります。そして、リスト9-4の`match`に似た`match`で返ってくる`Result`値を扱い、 `Err`ケースに`panic!`を呼び出す代わりだけですが、この関数から早期リターンしてこの関数のエラー値として、 `File::open`から得たエラー値を呼び出し元に渡し返します。`File::open`が成功すれば、 ファイルハンドルを変数`f`に保管して継続します。 @@ -646,7 +647,7 @@ fn read_username_from_file() -> Result { `read_to_string`の呼び出しを直接`File::open("hello.txt")?`の結果に連結させました。 それでも、`read_to_string`呼び出しの末尾には`?`があり、`File::open`と`read_to_string`両方が成功したら、 エラーを返すというよりもまだ`s`にユーザ名を含む`Ok`値を返します。機能もまたリスト9-6及び、9-7と同じです; -ただ単に異バージョンのよりプログラマフレンドリーな書き方なのです。 +ただ単に異なるバージョンのよりプログラマフレンドリーな書き方なのです。 diff --git a/second-edition/src/ch09-03-to-panic-or-not-to-panic.md b/second-edition/src/ch09-03-to-panic-or-not-to-panic.md index 494648819..9138e2ab3 100644 --- a/second-edition/src/ch09-03-to-panic-or-not-to-panic.md +++ b/second-edition/src/ch09-03-to-panic-or-not-to-panic.md @@ -45,7 +45,7 @@ 例を記述して何らかの概念を具体化している時、頑健なエラー処理コードも例に含むことは、例の明瞭さを欠くことになりかねません。 -例では、`unwrap`などの`panic!`する可能性のあるメソッド呼び出しは、 +例において、`unwrap`などの`panic!`する可能性のあるメソッド呼び出しは、 アプリケーションにエラーを処理してほしい方法へのプレースホルダーを意味していると理解され、 これは残りのコードがしていることによって異なる可能性があります。 @@ -54,7 +54,7 @@ 同様に、`unwrap`や`expect`メソッドは、エラーの処理法を決定する準備ができる前、プロトタイプの段階では、 -非常に便利です。それらにより、コードにプログラムをより頑健にする時の明らかなマーカが残されるわけです。 +非常に便利です。それらにより、コードにプログラムをより頑健にする時の明らかなマーカーが残されるわけです。 @@ -63,7 +63,7 @@ メソッド呼び出しがテスト内で失敗したら、そのメソッドがテスト下に置かれた機能ではなかったとしても、 テスト全体が失敗してほしいでしょう。`panic!`が、テストが失敗と印づけられる手段なので、 -`unwrap`や`expect`はスバリ起こるべきことです。 +`unwrap`や`expect`の呼び出しはスバリ起こるべきことです。 @@ -152,7 +152,7 @@ let home = "127.0.0.1".parse::().unwrap(); 悪い状態に達すると、どんなにコードをうまく書いても起こると予想されるが、`panic!`呼び出しをするよりもまだ、 -`Result`を返すほうがより適切です。これの例には、不正なデータを渡されたパーサとか、 +`Result`を返すほうがより適切です。これの例には、不正なデータを渡されたパーサーとか、 訪問制限に引っかかったことを示唆するステータスを返すHTTPリクエストなどが挙げられます。 このような場合には、呼び出し側が問題の処理方法を決定できるように`Result`を返してこの悪い状態を委譲して、 失敗が予想される可能性であることを示唆するべきです。`panic!`は、 @@ -179,7 +179,7 @@ let home = "127.0.0.1".parse::().unwrap(); 現在のデータ構造に属しないメモリにアクセスを試みることは、ありふれたセキュリティ問題なのです。 関数にはしばしば*契約*が伴います: 入力が特定の条件を満たすときのみ、振る舞いが保証されるのです。 契約が侵されたときにパニックすることは、道理が通っています。なぜなら、契約侵害は常に呼び出し側のバグを示唆し、 -呼び出し側に明示的に処理してもらう必要のある種のエラーではないからです。実際に、 +呼び出し側に明示的に処理してもらう必要のある種類のエラーではないからです。実際に、 呼び出し側が回復する合理的な手段はありません: 呼び出し側の*プログラマ*がコードを修正する必要があるのです。 関数の契約は、特に侵害がパニックを引き起こす際には、関数のAPIドキュメント内で説明されているべきです。 @@ -334,12 +334,12 @@ impl Guess { それから`Guess`に`Guess`値のインスタンスを生成する`new`という名前の関連関数を実装しています。 -`new`関数は、`u32`型の`value`という引数を取理、`Guess`を返すように定義されています。 +`new`関数は、`u32`型の`value`という引数を取り、`Guess`を返すように定義されています。 `new`関数の本体のコードは、`value`をふるいにかけ、1から100の範囲であることを確かめます。 `value`がふるいに引っかかったら、`panic!`呼び出しを行います。これにより、呼び出しコードを書いているプログラマに、 修正すべきバグがあると警告します。というのも、この範囲外の`value`で`Guess`を生成することは、 `Guess::new`が頼りにしている契約を侵害するからです。`Guess::new`がパニックするかもしれない条件は、 -公開されているAPIドキュメントで議論されるべきでしょう; あなたが作成するAPIドキュメントで`panic!`可能性を示唆する、 +公開されているAPIドキュメントで議論されるべきでしょう; あなたが作成するAPIドキュメントで`panic!`の可能性を示唆する、 ドキュメントの規約は、第14章で解説します。`value`が確かにふるいを通ったら、 `value`フィールドが`value`引数にセットされた新しい`Guess`を作成して返します。 @@ -383,9 +383,9 @@ impl Guess { Rustのエラー処理機能は、プログラマがより頑健なコードを書く手助けをするように設計されています。 `panic!`マクロは、プログラムが処理できない状態にあり、無効だったり不正な値で処理を継続するのではなく、 -プロセスに処理を中止するよう教えることを通知します。`Result`enumは、Rustの型システムを使用して、 +プロセスに処理を中止するよう指示することを通知します。`Result`enumは、Rustの型システムを使用して、 コードが回復可能な方法で処理が失敗するかもしれないことを示唆します。`Result`を使用して、 -呼び出し側のコードに成功や失敗する可能性を処理する必要があることも教えてくれます。 +呼び出し側のコードに成功や失敗する可能性を処理する必要があることも教えます。 適切な場面で`panic!`や`Result`を使用することで、必然的な問題の眼前でコードの信頼性を上げてくれます。 From 90b0a4f22f3e4c5c6f5d8576a221696a7882f681 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 5 Dec 2017 22:20:32 +0900 Subject: [PATCH 064/428] First draft of the chapter 11-0 --- second-edition/src/ch11-00-testing.md | 92 +++++++++++++++++---------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/second-edition/src/ch11-00-testing.md b/second-edition/src/ch11-00-testing.md index 4b1c61ad1..ffb2d8192 100644 --- a/second-edition/src/ch11-00-testing.md +++ b/second-edition/src/ch11-00-testing.md @@ -1,33 +1,59 @@ -# Writing Automated Tests - -In his 1972 essay “The Humble Programmer,” Edsger W. Dijkstra said that -“Program testing can be a very effective way to show the presence of bugs, but -it is hopelessly inadequate for showing their absence.” That doesn’t mean we -shouldn’t try to test as much as we can! Correctness in our programs is the -extent to which our code does what we intend it to do. Rust is a programming -language 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. - -As an example, say we write a function called `add_two` that adds two to -whatever number is passed to it. This function’s signature accepts an integer -as a parameter and returns an integer as a result. When we implement and -compile that function, Rust does all the type checking and borrow checking that -you’ve learned so far to ensure that, for instance, we aren’t passing a -`String` value or an invalid reference to this function. But Rust *can’t* check -that this function will do precisely what we intend, which is return the -parameter plus two rather than, say, the parameter plus 10 or the parameter -minus 50! That’s where tests come in. - -We can write tests that assert, for example, that when we pass `3` to the -`add_two` function, the returned value is `5`. We can run these tests whenever -we make changes to our code to make sure any existing correct behavior has not -changed. - -Testing is a complex skill: although we can’t cover every detail about how to -write good tests in one chapter, we’ll discuss the mechanics of Rust’s testing -facilities. We’ll talk about the annotations and macros available to you when -writing your tests, the default behavior and options provided for running your -tests, and how to organize tests into unit tests and integration tests. + + +# 自動テストを書く + + + + + + + + + + + + +1972年のエッセイ「謙虚なプログラマ」でエドガー・W・ダイクストラは以下のように述べている。 +「プログラムのテストは、バグの存在を示すには非常に効率的な手法であるが、 +バグの不在を示すには望み薄く不適切である」と。これは、できるだけテストを試みるべきではないということではありません。 +プログラムの正当性は、どこまで自分のコードが意図していることをしているかなのです。 +Rustは、プログラムの正当性に重きを置いて設計されたプログラミング言語ですが、 +正当性は複雑で、単純に証明することはありません。Rustの型システムは、 +この重荷の多くの部分を肩代わりしてくれますが、型システムはあらゆる種類の不当性を捕捉してはくれません。 +ゆえに、Rustでは、言語内で自動化されたソフトウェアテストを書くことをサポートしているのです。 + + + + + + + + + + + +例として、渡された何かの数値に2を足す`add_two`という関数を書くとしましょう。 +この関数のシグニチャは、引数に整数を取り、結果として整数を返します。 +この関数を実装してコンパイルすると、コンパイラはこれまでに学んできた型チェックと借用チェックを全て行い、 +例えば、`String`の値や無効な参照をこの関数に渡していないかなどを確かめるのです。 +ところが、コンパイラはプログラマがまさしく意図したことを関数が実行しているかどうかは確かめ*られません*。 +つまり、そうですね、引数に10を足したり、50を引いたりするのではなく、引数に2を足していることです。 +そんな時にテストは、必要になるのです。 + + + + + + +例えば、`add_two`関数に`3`を渡した時に、戻り値は5であることをアサーションするようなテストを書くことができます。 +コードに変更を加えた際にこれらのテストを走らせ、既存の正当な振る舞いが変わっていないことを確認できます。 + + + + + + + +テストは、煩雑なスキルです: いいテストの書き方をあらゆる方面から解説することは1章だけではきないのですが、 +Rustのテスト機構のメカニズムについて議論します。テストを書く際に利用可能になるアノテーションとマクロについて、 +テストを実行するのに提供されているオプションと標準の動作、さらにテストをユニットテストや統合テストに体系化する方法について語ります。 From 1cc7a89ef3885d2c0ee588ae0cf4c78cd31ac4b3 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 6 Dec 2017 19:17:50 +0900 Subject: [PATCH 065/428] First drafts of the chapter 11 and missing merges from the previous commit --- second-edition/src/SUMMARY.md | 13 +- second-edition/src/ch03-05-control-flow.md | 9 +- .../src/ch04-01-what-is-ownership.md | 9 +- .../src/ch07-03-importing-names-with-use.md | 10 +- second-edition/src/ch11-00-testing.md | 2 +- second-edition/src/ch11-01-writing-tests.md | 881 ++++++++++++------ second-edition/src/ch11-02-running-tests.md | 341 ++++--- .../src/ch11-03-test-organization.md | 511 ++++++---- 8 files changed, 1176 insertions(+), 600 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index bf2bbcd55..bf2ac51fb 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -95,10 +95,15 @@ - [Traits: Defining Shared Behavior](ch10-02-traits.md) - [Validating References with Lifetimes](ch10-03-lifetime-syntax.md) -- [Testing](ch11-00-testing.md) - - [Writing tests](ch11-01-writing-tests.md) - - [Running tests](ch11-02-running-tests.md) - - [Test Organization](ch11-03-test-organization.md) + + + + + +- [テスト](ch11-00-testing.md) + - [テストを書く](ch11-01-writing-tests.md) + - [テストを走らせる](ch11-02-running-tests.md) + - [テストの体系化](ch11-03-test-organization.md) - [An I/O Project: Building a Command Line Program](ch12-00-an-io-project.md) - [Accepting Command Line Arguments](ch12-01-accepting-command-line-arguments.md) diff --git a/second-edition/src/ch03-05-control-flow.md b/second-edition/src/ch03-05-control-flow.md index 1ae9ffcb4..0ec685ec6 100644 --- a/second-edition/src/ch03-05-control-flow.md +++ b/second-edition/src/ch03-05-control-flow.md @@ -559,15 +559,10 @@ the value is: 50 コンパイラが実行時にループの各回ごとに境界値チェックを行うようなコードを追加するからです。 - + -<<<<<<< HEAD より効率的な対立案として、`for`ループを使ってコレクションの各アイテムに対してコードを実行することができます。 -`for`ループはこんな見た目です: -======= -As a more concise alternative, you can use a `for` loop and execute some code -for each item in a collection. A `for` loop looks like this code in Listing 3-4: ->>>>>>> fork_master_master +`for`ループはリスト3-4のこんな見た目です: diff --git a/second-edition/src/ch04-01-what-is-ownership.md b/second-edition/src/ch04-01-what-is-ownership.md index 63e065dcc..2170b5a4e 100644 --- a/second-edition/src/ch04-01-what-is-ownership.md +++ b/second-edition/src/ch04-01-what-is-ownership.md @@ -782,6 +782,7 @@ Rustには`Copy`トレイトと呼ばれる特別な注釈があり、 + @@ -805,16 +806,10 @@ Rustには`Copy`トレイトと呼ばれる特別な注釈があり、 fn main() { let s = String::from("hello"); // sがスコープに入る。 -<<<<<<< HEAD takes_ownership(s); // sの値が関数にムーブされ... // ... ここではもう有効ではない。 - let x = 5; // xがスコープに入る。 -======= - takes_ownership(s); // s's value moves into the function... - // ... and so is no longer valid here. - let x = 5; // x comes into scope. ->>>>>>> fork_master_master + let x = 5; // xがスコープに入る。 makes_copy(x); // xも関数にムーブされるが、 // i32はCopyなので、この後にxを使っても diff --git a/second-edition/src/ch07-03-importing-names-with-use.md b/second-edition/src/ch07-03-importing-names-with-use.md index 9cf981c39..5584f46f1 100644 --- a/second-edition/src/ch07-03-importing-names-with-use.md +++ b/second-edition/src/ch07-03-importing-names-with-use.md @@ -218,18 +218,12 @@ communicator └── tests ``` -<<<<<<< HEAD - + テストは、ライブラリ内でコードの準備運動を行うためのものなので、この`it_works`関数から`client::connect`関数を呼び出してみましょう。 -まあ、最も今のところ、機能の検査は何もしないんですけどね: -======= -Tests are for exercising the code within our library, so let’s try to call our -`client::connect` function from this `it_works` function, even though we won’t -be checking any functionality right now. This won't work yet: ->>>>>>> fork_master_master +まあ、尤も今のところ、機能の検査は何もしないんですけどね。これはまだ動きません: diff --git a/second-edition/src/ch11-00-testing.md b/second-edition/src/ch11-00-testing.md index ffb2d8192..3518a089d 100644 --- a/second-edition/src/ch11-00-testing.md +++ b/second-edition/src/ch11-00-testing.md @@ -54,6 +54,6 @@ Rustは、プログラムの正当性に重きを置いて設計されたプロ -テストは、煩雑なスキルです: いいテストの書き方をあらゆる方面から解説することは1章だけではきないのですが、 +テストは、煩雑なスキルです: いいテストの書き方をあらゆる方面から解説することは1章だけではできないのですが、 Rustのテスト機構のメカニズムについて議論します。テストを書く際に利用可能になるアノテーションとマクロについて、 テストを実行するのに提供されているオプションと標準の動作、さらにテストをユニットテストや統合テストに体系化する方法について語ります。 diff --git a/second-edition/src/ch11-01-writing-tests.md b/second-edition/src/ch11-01-writing-tests.md index 2aba37f88..20de66ead 100644 --- a/second-edition/src/ch11-01-writing-tests.md +++ b/second-edition/src/ch11-01-writing-tests.md @@ -1,39 +1,68 @@ -## How to Write Tests + -Tests are Rust functions that verify that the non-test code is functioning in -the expected manner. The bodies of test functions typically perform these three -actions: +## テストの記述法 -1. Set up any needed data or state -2. Run the code we want to test -3. Assert the results are what we expect + + + -Let’s look at the features Rust provides specifically for writing tests that -take these actions, which include the `test` attribute, a few macros, and the -`should_panic` attribute. +テストは、非テストコードが想定された手段で機能していることを実証するRustの関数です。 +テスト関数の本体は、典型的には以下の3つの動作を行います: -### The Anatomy of a Test Function + + + -At its simplest, a test in Rust is a function that’s annotated with the `test` -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, we add `#[test]` on the line before `fn`. When we run our -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 -test function passes or fails. +1. 必要なデータや状態をセットアップする +2. テスト対象のコードを走らせる +3. 結果が想定通りかアサーションする -In Chapter 7, we saw that when we make a new library project with Cargo, a test -module with a test function in it is automatically generated for us. This -module helps us start writing our tests so we don’t have to look up the exact -structure and syntax of test functions every time we start a new project. We -can add as many additional test functions and as many test modules as we want! + + + -We’ll explore some aspects of how tests work by experimenting with the template -test generated for us without actually testing any code. Then we’ll write some -real-world tests that call some code that we’ve written and assert that its -behavior is correct. +Rustが、特にこれらの動作を行うテストを書くために用意している機能を見ていきましょう。 +これには、`test`アトリビュート、いくつかのマクロ、`should_panic`アトリビュートが含まれます。 -Let’s create a new library project called `adder`: + + +## テスト関数の解剖 + + + + + + + + + +最も単純には、Rustにおけるテストは`test`アトリビュートで注釈された関数のことです。アトリビュートとは、 +Rustコードの欠片に関するメタデータです; 一例を挙げれば、構造体とともに第5章で使用した`derive`アトリビュートです。 +関数をテスト関数に変えるには、`fn`の前に`#[test]`を付け加えるのです。 +`cargo test`コマンドでテストを実行したら、コンパイラは`test`アトリビュートで注釈された関数を走らせるテスト用バイナリをビルドし、 +各テスト関数が通過したか失敗したかを報告します。 + + + + + + + +第7章で、Cargoで新規ライブラリプロジェクトを作成した時に、テスト関数が含まれるテストモジュールが自動で生成されたことを確かめました。 +このモジュールのおかげでテストを書き始めることができるので、新しいプロジェクトを立ち上げる度に、 +テスト関数の正確な構造と記法を調べる必要がなくなるわけです。必要なだけテスト関数とテストモジュールは追加することができます。 + + + + + + +実際にテストすることなしにテンプレートのテストが生成されるのを実験することでテストの動作法の一部を探求しましょう。 +それから、自分で書いたコードを呼び出し、振る舞いが正しいかアサーションする現実世界のテストを書きましょう。 + + + +`adder`という新しいライブラリプロジェクトを生成しましょう: ```text $ cargo new adder @@ -41,10 +70,14 @@ $ cargo new adder $ cd adder ``` -The contents of the *src/lib.rs* file in your adder library should look like -Listing 11-1: + + + +adderライブラリの*src/lib.rs*ファイルの中身はリスト11-1のような見た目のはずです: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -56,22 +89,35 @@ mod tests { } ``` -Listing 11-1: The test module and function generated -automatically by `cargo new` + + + +リスト11-1: `cargo new`で自動生成されたテストモジュールと関数 + + + + + + + + +とりあえず、最初の2行は無視し、関数に集中してその動作法を見ましょう。 +`fn`行の`#[test]`アノテーションに注目してください:このアトリビュートは、これがテスト関数であることを示唆しますので、 +テスト実行機はこの関数をテストとして扱うとわかるのです。さらに、`tests`モジュール内には非テスト関数を入れ込み、 +一般的なシナリオをセットアップする手助けをしたり、共通の処理を行ったりもできるので、 +`#[test]`アトリビュートでどの関数がテストかを示唆する必要があるのです。 + + + + -For now, let’s ignore the top two lines and focus on the function to see how it -works. Note the `#[test]` annotation before the `fn` line: this attribute -indicates this is a test function, so the test runner knows to treat this -function as a test. We could also have non-test functions in the `tests` module -to help set up common scenarios or perform common operations, so we need to -indicate which functions are tests by using the `#[test]` attribute. +関数本体は、`assert_eq!`マクロを使用して、2 + 2が4に等しいことをアサーションしています。 +このアサーションは、典型的なテストのフォーマット例をなしているわけです。走らせてこのテストが通ることを確かめましょう。 -The function body uses the `assert_eq!` macro to assert that 2 + 2 equals 4. -This assertion serves as an example of the format for a typical test. Let’s run -it to see that this test passes. + + -The `cargo test` command runs all tests in our project, as shown in Listing -11-2: +`cargo test`コマンドでプロジェクトにあるテストが全て実行されます。リスト11-2に示したようにね: ```text $ cargo test @@ -91,36 +137,60 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Listing 11-2: The output from running the automatically -generated test + + + +リスト11-2: 自動生成されたテストを走らせた出力 + + + + + + + + +Cargoがテストをコンパイルし、走らせました。`Compiling`, `Finished`, `Running`の行の後に`running 1 test`の行があります。 +次行が、生成されたテスト関数の`it_works`とこのテストの実行結果、`ok`を示しています。 +テスト実行の総合的なまとめが次に出現します。`test result:ok.`というテキストは、 +全テストが通ったことを意味し、`1 passed; 0 failed`と読める部分は、通過または失敗したテストの数を総評しているのです。 + + + + + +無視すると指定したテストは何もなかったため、まとめは`0 ignored`と示しています。テストを無視することに関しては次の節、 +「テストの実行され方を制御する」で語ります。 -Cargo compiled and ran the test. After the `Compiling`, `Finished`, and -`Running` lines is the line `running 1 test`. The next line shows the name -of the generated test function, called `it_works`, and the result of running -that test, `ok`. The overall summary of running the tests appears next. The -text `test result: ok.` means that all the tests passed, and the portion that -reads `1 passed; 0 failed` totals the number of tests that passed or failed. + + + -Because we don’t have any tests we’ve marked as ignored, the summary shows `0 -ignored`. We’ll talk about ignoring tests in the next section, “Controlling How -Tests Are Run.” +`0 measured`という統計は、パフォーマンスを測定するベンチマークテスト用です。 +ベンチマークテストは、本書記述の時点では、ナイトリー版のRustでのみ利用可能です。 +ナイトリー版のRustについて詳しくは、第1章を参照されたし。 -The `0 measured` statistic is for benchmark tests that measure performance. -Benchmark tests are, as of this writing, only available in nightly Rust. See -Chapter 1 for more information about nightly Rust. + + + + + + -The next part of the test output, which starts with `Doc-tests adder`, is for -the results of any documentation tests. We don’t have any documentation tests -yet, but Rust can compile any code examples that appear in our API -documentation. This feature helps us keep our docs and our code in sync! We’ll -discuss how to write documentation tests in the “Documentation Comments” -section of Chapter 14. For now, we’ll ignore the `Doc-tests` output. +テスト出力の次の部分、つまり`Doc-tests adder`で始まる部分は、ドキュメンテーションテストの結果用のものです。 +まだドキュメンテーションテストは何もないものの、コンパイラは、APIドキュメントに現れたどんなコード例もコンパイルできます。 +この機能により、ドキュメントとコードを同期することができるわけです。ドキュメンテーションテストの書き方については、 +第14章の「ドキュメンテーションコメント」節で議論しましょう。今は、`Doc-tests`出力は無視します。 -Let’s change the name of our test to see how that changes the test output. -Change the `it_works` function to a different name, such as `exploration`, like -so: + + + -Filename: src/lib.rs +テストの名前を変更してどうテスト出力が変わるか確かめましょう。`it_works`関数を違う名前、`exploration`などに変えてください。 +そう、以下のように: + + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -132,8 +202,10 @@ mod tests { } ``` -Then run `cargo test` again. The output now shows `exploration` instead of -`it_works`: + + + +そして、`cargo test`を再度走らせます。出力が`it_works`の代わりに`exploration`と表示するようになりました: ```text running 1 test @@ -142,14 +214,22 @@ test tests::exploration ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Let’s add another test, but this time we’ll make a test that fails! Tests fail -when something in the test function panics. Each test is run in a new thread, -and when the main thread sees that a test thread has died, the test is marked -as failed. We talked about the simplest way to cause a panic in Chapter 9, -which is to call the `panic!` macro. Enter the new test, `another`, so your -*src/lib.rs* file looks like Listing 11-3: + + + + + + + +別のテストを追加しますが、今回は失敗するテストにしましょう!テスト関数内の何かがパニックすると、 +テストは失敗します。各テストは、新規スレッドで実行され、メインスレッドが、テストスレッドが死んだと確認した時、 +テストは失敗と印づけられます。第9章でパニックを引き起こす最も単純な方法について語りました。 +要するに、`panic!`マクロを呼び出すことです。*src/lib.rs*ファイルがリスト11-3のような見た目になるよう、 +新しいテスト`another`を入力してください: + + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -161,16 +241,22 @@ mod tests { #[test] fn another() { + //このテストを失敗させる panic!("Make this test fail"); } } ``` -Listing 11-3: Adding a second test that will fail because -we call the `panic!` macro + + -Run the tests again using `cargo test`. The output should look like Listing -11-4, which shows that our `exploration` test passed and `another` failed: +リスト11-3: `panic!`マクロを呼び出したために失敗する2番目のテストを追加する + + + + +`cargo test`で再度テストを走らせてください。出力はリスト11-4のようになるはずであり、 +`exploration`テストは通り、`another`は失敗したと表示されます: ```text running 2 tests @@ -191,40 +277,67 @@ test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out error: test failed ``` -Listing 11-4: Test results when one test passes and one -test fails + + + +リスト11-4: 1つのテストが通り、失敗するときのテスト結果 + + + + + + + + + + + +`ok`の代わりに`test test::another`の行は、`FAILED`を表示しています。個々の結果とまとめの間に、 +2つ新たな区域ができました: 最初の区域は、失敗したテスト各々の具体的な理由を表示しています。 +今回の場合、`another`は`'Make this test fail'でパニックした`ために失敗し、 +これは、*src/lib.rs*ファイルの10行で起きました。次の区域は失敗したテストの名前だけを列挙し、 +テストがたくさんあり、失敗したテストの詳細がたくさん表示されるときに有用になります。 +失敗したテストの名前を使用してそのテストだけを実行し、より簡単にデバッグすることができます。 +ただし、テストの実行方法については、「テストの走らせ方を制御する」節でもっと語りましょう。 -Instead of `ok`, the line `test tests::another` shows `FAILED`. Two new -sections appear between the individual results and the summary: the first -section displays the detailed reason for each test failure. In this case, -`another` failed because it `panicked at 'Make this test fail'`, which happened -on line 10 in the *src/lib.rs* file. The next section lists just the names of -all the failing tests, which is useful when there are lots of tests and lots of -detailed failing test output. We can use the name of a failing test to run just -that test to more easily debug it; we’ll talk more about ways to run tests in -the “Controlling How Tests Are Run” section. + + -The summary line displays at the end: overall, our test result is `FAILED`. -We had one test pass and one test fail. +総括の行が最後に出力されています: 総合的に言うと、テスト結果は`失敗`でした。 +一つのテストが通り、一つが失敗したわけです。 -Now that you’ve seen what the test results look like in different scenarios, -let’s look at some macros other than `panic!` that are useful in tests. + + -### Checking Results with the `assert!` Macro +異なるシナリオでのテスト結果がどんな風になるか見てきたので、テストを行う際に有用になる`panic!`以外のマクロに目を向けましょう。 -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. + -In Chapter 5, Listing 5-9, we used a `Rectangle` struct and a `can_hold` -method, which are repeated here in Listing 11-5. Let’s put this code in the -*src/lib.rs* file and write some tests for it using the `assert!` macro. +### `assert!`マクロで結果を確認する -Filename: src/lib.rs + + + + + + + + +`assert!`マクロは、標準ライブラリで提供されていますが、テスト内の何らかの条件が`true`と評価されることを確かめたいときに有効です。 +`assert!`マクロには、論理値に評価される引数を与えます。その値が`true`なら、 +`assert!`は何もせず、テストは通ります。その値が`false`なら、`assert!`マクロは`panic!`マクロを呼び出し、 +テストは失敗します。`assert!`マクロを使用することで、コードが意図した通りに機能していることを確認できるわけです。 + + + + + +第5章のリスト5-9で、`Rectangle`構造体と`can_hold`メソッドを使用しました。リスト11-5でもそれを繰り返しています。 +このコードを*src/lib.rs*ファイルに放り込み、`assert!`マクロでそれ用のテストを何か書いてみましょう。 + + + +ファイル名: src/lib.rs ```rust #[derive(Debug)] @@ -240,16 +353,24 @@ impl Rectangle { } ``` -Listing 11-5: Using the `Rectangle` struct and its -`can_hold` method from Chapter 5 + + -The `can_hold` method returns a Boolean, which means it’s a perfect use case -for the `assert!` macro. In Listing 11-6, we write a test that exercises the -`can_hold` method by creating a `Rectangle` instance that has a length of 8 and -a width of 7, and asserting that it can hold another `Rectangle` instance that -has a length of 5 and a width of 1: +リスト11-5: 第5章から`Rectangle`構造体とその`can_hold`メソッドを使用する -Filename: src/lib.rs + + + + + + +`can_hold`メソッドは論理値を返すので、`assert!`マクロの完璧な実行例になるわけです。 +リスト11-6で、長さが8、幅が7の`Rectangle`インスタンスを生成し、これが長さ5、 +幅1の別の`Rectangle`インスタンスを保持できるとアサーションすることで`can_hold`を用いるテストを書きます: + + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -266,20 +387,31 @@ mod tests { } ``` -Listing 11-6: A test for `can_hold` that checks that a -larger rectangle can indeed hold a smaller rectangle + + + +リスト11-6: より大きな四角形がより小さな四角形を確かに保持できると確認する`can_hold`用のテスト + + + + + + + -Note that we’ve added a new line inside the `tests` module: the `use super::*;` -line. The `tests` module is a regular module that follows the usual visibility -rules we covered in Chapter 7 in the “Privacy Rules” section. Because the -`tests` module is an inner module, we need to bring the code under test in the -outer module into the scope of the inner module. We use a glob here so anything -we define in the outer module is available to this `tests` module. +`tests`モジュール内に新しい行を加えたことに注目してください: `use super::*`という1行です。 +`tests`モジュールは、第7章の「プライバシー規則」節で解説した通常の公開ルールに従う普通のモジュールです。 +`tests`モジュールは、内部モジュールなので、外部モジュール内のテスト配下にあるコードを内部モジュールのスコープに持っていく必要があります。 +ここではglobを使用して、外部モジュールで定義したもの全てがこの`tests`モジュールでも使用可能になるようにしています。 -We’ve named our test `larger_can_hold_smaller`, and we’ve created the two -`Rectangle` instances that we need. Then we called the `assert!` macro and -passed it the result of calling `larger.can_hold(&smaller)`. This expression -is supposed to return `true`, so our test should pass. Let’s find out! + + + + + +テストは`larger_can_hold_smaller`と名付け、必要な`Rectangle`インスタンスを2つ生成しています。 +そして、`assert!`マクロを呼び出し、`larger.can_hold(&smaller)`の呼び出し結果を渡しました。 +この式は、`true`を返すと考えられるので、テストは通るはずです。確かめましょう! ```text running 1 test @@ -288,10 +420,14 @@ test tests::larger_can_hold_smaller ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -It does pass! Let’s add another test, this time asserting that a smaller -rectangle cannot hold a larger rectangle: + + + +確かに!別のテストを追加しましょう。今回は、小さい四角形は、より大きな四角形を保持できないことをアサーションします。 + + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -313,9 +449,12 @@ mod tests { } ``` -Because the correct result of the `can_hold` function in this case is `false`, -we need to negate that result before we pass it to the `assert!` macro. As a -result, our test will pass if `can_hold` returns `false`: + + + + +今回の場合、`can_hold`関数の正しい結果は`false`なので、その結果を`assert!`マクロに渡す前に反転させる必要があります。 +結果として、`can_hold`が`false`を返せば、テストは通ります。 ```text running 2 tests @@ -325,10 +464,13 @@ test tests::larger_can_hold_smaller ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Two tests that pass! Now let’s see what happens to our test results when we -introduce a bug in our code. Let’s change the implementation of the `can_hold` -method by replacing the greater-than sign with a less-than sign when it -compares the lengths: + + + + + +通るテストが2つ!さて、コードにバグを導入したらテスト結果がどうなるか確認してみましょう。 +長さを比較する大なり記号を小なり記号で置き換えて`can_hold`メソッドの実装を変更しましょう: ```rust # #[derive(Debug)] @@ -345,7 +487,9 @@ impl Rectangle { } ``` -Running the tests now produces the following: + + +テストを実行すると、以下のような出力をします: ```text running 2 tests @@ -365,28 +509,45 @@ failures: test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out ``` -Our tests caught the bug! Because `larger.length` is 8 and `smaller.length` is -5, the comparison of the lengths in `can_hold` now returns `false`: 8 is not -less than 5. + + + + +テストによりバグが捕捉されました!`larger.length`が8、`smaller.length`が5なので、 +`can_hold`内の長さの比較が今は`false`を返すようになったのです: 8は5より小さくないですからね。 + + + +### `assert_eq!`と`assert_ne!`マクロで等値性をテストする + + + + + + + + + + + -### Testing Equality with the `assert_eq!` and `assert_ne!` Macros +機能をテストする一般的な方法は、テスト下にあるコードの結果をコードが返すと期待される値と比較して、 +等しいと確かめることです。これを`assert`マクロを使用して`==`演算子を使用した式を渡すことで行うこともできます。 +しかしながら、これはありふれたテストなので、標準ライブラリには1組のマクロ(`assert_eq!`と`assert_ne!`)が提供され、 +このテストをより便利に行うことができます。これらのマクロはそれぞれ、二つの引数を等値性と非等値性のために比較します。 +また、アサーションが失敗したら二つの値の出力もし、テストが失敗した*原因*を確認しやすくなります。 +一方で`assert!`マクロは、`==`式の値が`false`値になったことしか示唆せず、`false`値に導いた値は出力しません。 -A common way to test functionality is to compare the result of the code under -test to the value we expect the code to return to make sure they’re equal. We -could do this using the `assert!` macro and passing it an expression using the -`==` operator. However, this is such a common test that the standard library -provides a pair of macros—`assert_eq!` and `assert_ne!`—to perform this test -more conveniently. These macros compare two arguments for equality or -inequality, respectively. They’ll also print the two values if the assertion -fails, which makes it easier to see *why* the test failed; conversely, the -`assert!` macro only indicates that it got a `false` value for the `==` -expression, not the values that lead to the `false` value. + + + -In Listing 11-7, we write a function named `add_two` that adds `2` to its -parameter and returns the result. Then we test this function using the -`assert_eq!` macro. +リスト11-7において、引数に`2`を加えて結果を返す`add_two`という名前の関数を書いています。 +そして、`assert_eq!`マクロでこの関数をテストしています。 -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust pub fn add_two(a: i32) -> i32 { @@ -404,10 +565,14 @@ mod tests { } ``` -Listing 11-7: Testing the function `add_two` using the -`assert_eq!` macro + + + +リスト11-7: `assert_eq!`マクロで`add_two`関数をテストする + + -Let’s check that it passes! +テストが通ることを確認しましょう! ```text running 1 test @@ -416,13 +581,19 @@ test tests::it_adds_two ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -The first argument we gave to the `assert_eq!` macro, `4`, is equal to the -result of calling `add_two(2)`. The line for this test is `test -tests::it_adds_two ... ok`, and the `ok` text indicates that our test passed! + + + + +`assert_eq!`マクロに与えた第1引数の`4`は、`add_two(2)`の呼び出し結果と等しいです。 +このテストの行は`test tests::it_adds_two ... ok`であり、`ok`というテキストはテストが通ったことを示しています! + + + + -Let’s introduce a bug into our code to see what it looks like when a test that -uses `assert_eq!` fails. Change the implementation of the `add_two` function to -instead add `3`: +コードにバグを仕込んで、`assert_eq!`を使ったテストが失敗した時にどんな見た目になるのか確認してみましょう。 +`add_two`関数の実装を代わりに`3`を足すように変えてください: ```rust pub fn add_two(a: i32) -> i32 { @@ -430,7 +601,9 @@ pub fn add_two(a: i32) -> i32 { } ``` -Run the tests again: + + +テストを再度実行します: ```text running 1 test @@ -449,58 +622,99 @@ failures: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out ``` -Our test caught the bug! The `it_adds_two` test failed, displaying the message -`` assertion failed: `(left == right)` `` and showing that `left` was `4` and -`right` was `5`. This message is useful and helps us start debugging: it means -the `left` argument to `assert_eq!` was `4`, but the `right` argument, where we -had `add_two(2)`, was `5`. - -Note that in some languages and test frameworks, the parameters to the -functions that assert two values are equal are called `expected` and `actual`, -and the order in which we specify the arguments matters. However, in Rust, -they’re called `left` and `right`, and the order in which we specify the value -we expect and the value that the code under test produces doesn’t matter. We -could write the assertion in this test as `assert_eq!(add_two(2), 4)`, which -would result in a failure message that displays `` assertion failed: `(left == -right)` `` and that `left` was `5` and `right` was `4`. - -The `assert_ne!` macro will pass if the two values we give it are not equal and -fail if they’re equal. This macro is most useful for cases when we’re not sure -what a value *will* be, but we know what the value definitely *won’t* be if our -code is functioning as we intend. For example, if we’re testing a function that -is guaranteed to change its input in some way, but the way in which the input -is changed depends on the day of the week that we run our tests, the best thing -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 -out 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 for more details about these and -other derivable traits. - -### Adding Custom Failure Messages - -We can also add a custom message to be printed with the failure message as -optional arguments to the `assert!`, `assert_eq!`, and `assert_ne!` macros. Any -arguments specified after the one required argument to `assert!` or the two -required arguments to `assert_eq!` and `assert_ne!` are passed along to the -`format!` macro (discussed in Chapter 8 in the “Concatenation with the `+` -Operator or the `format!` Macro” section), so you can pass a format string that -contains `{}` placeholders and values to go in those placeholders. Custom -messages are useful to document what an assertion means; when a test fails, -we’ll have a better idea of what the problem is with the code. - -For example, let’s say we have a function that greets people by name, and we -want to test that the name we pass into the function appears in the output: - -Filename: src/lib.rs + + + + + + +テストがバグを捕捉しました!`it_adds_two`のテストは失敗し、`` assertion failed: `(left == right)` ``というメッセージを表示し、 +`left`は`4`で、`right`は`5`だったと示しています。このメッセージは有用で、デバッグを開始する助けになります: +`assert_eq!`の`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`と表示されるわけです。 + + + + + + + + + +`assert_ne!`マクロは、与えた2つの値が等しくなければ通り、等しければ失敗します。 +このマクロは、値が何になる*だろう*か確信が持てないけれども、コードが意図した通りに動いていれば、 +確実にこの値にはならない*だろう*とわかっているような場合に最も有用になります。例えば、 +入力を何らかの手段で変えることが保障されているけれども、入力が変更される方法がテストを実行する曜日に依存する関数をテストしているなら、 +アサーションすべき最善の事柄は、関数の出力が入力と等しくないことかもしれません。 + + + + + + + + + + + + + + +表面下では、`assert_eq!`と`assert_ne!`マクロはそれぞれ、`==`と`!=`演算子を使用しています。 +アサーションが失敗すると、これらのマクロは引数をデバッグフォーマットを使用して出力するので、 +比較対象の値は`PartialEq`と`Debug`トレイトを実装していなければなりません。 +自分で定義した構造体とenumについては、`PartialEq`を実装して、 +その型の値が等しいか等しくないかアサーションする必要があるでしょう。`Debug`を実装して、 +アサーションが失敗した時に値を出力できるようにする必要もあるでしょう。 +第5章のリスト5-12で触れたように、どちらのトレイトも継承可能トレイトなので、 +これは通常、構造体やenum定義に`#[derive(PartialEq, Debug)]`というアノテーションを追加するくらい率直になります。 +これらや他の継承可能トレイトに関する詳細については、おまけCをご覧ください。 + + + +### カスタムの失敗メッセージを追加する + + + + + + + + + + + +さらに、`assert!`、`assert_eq!`、`assert_ne!`の追加引数として、失敗メッセージと共にカスタムのメッセージが表示されるよう、 +追加することもできます。`assert!`の1つの必須引数、 +あるいは`assert_eq!`と`assert_ne!`の2つの必須引数の後に指定された引数はどれも`format!`マクロに明け渡されるので、 +(format!マクロについては第8章の「`+`演算子または、`format!`マクロで連結する」節で議論しました)、 +`{}`プレースホルダーを含むフォーマット文字列とこのプレースホルダーに置き換えられる値を渡すことができます。 +カスタムメッセージは、アサーションがどんな意味を持つかドキュメント化するのに役に立ちます; +テストが失敗した時、問題が何なのかコードと共により良い考えを持てるでしょう。 + + + + +例として、人々に名前で挨拶をする関数があり、関数に渡した名前が出力に出現することをテストしたいとしましょう: + + + +ファイル名: src/lib.rs ```rust pub fn greeting(name: &str) -> String { @@ -519,15 +733,21 @@ mod tests { } ``` -The requirements for this program haven’t been agreed upon yet, and we’re -pretty sure the `Hello` text at the beginning of the greeting will change. We -decided we don’t want to have to update the test for the name when that -happens, so instead of checking for exact equality to the value returned from -the `greeting` function, we’ll just assert that the output contains the text of -the input parameter. + + + + + + + +このプログラムの必要事項はまだ合意が得られておらず、挨拶の先頭の`Hello`というテキストは変わるだろうということは確かです。 +そうなった時に名前のためにテストを更新する必要はないと決定したので、 +`greeting`関数から返る値と正確な等値性を確認するのではなく、出力が入力引数のテキストを含むことをアサーションするだけにします。 + + + -Let’s introduce a bug into this code by changing `greeting` to not include -`name` to see what this test failure looks like: +`greeting`が`name`を含まないように変更してこのコードにバグを仕込み、このテストの失敗がどんな見た目になるのか確かめましょう: ```rust pub fn greeting(name: &str) -> String { @@ -535,7 +755,9 @@ pub fn greeting(name: &str) -> String { } ``` -Running this test produces the following: + + +このテストを実行すると、以下のように出力されます: ```text running 1 test @@ -552,16 +774,22 @@ failures: tests::greeting_contains_name ``` -This result just indicates that the assertion failed and which line the -assertion is on. A more useful failure message in this case would print the -value we got from the `greeting` function. Let’s change the test function, -giving it a custom failure message made from a format string with a placeholder -filled in with the actual value we got from the `greeting` function: + + + + + + +この結果は、アサーションが失敗し、どの行にアサーションがあるかを示しているだけです。 +より役に立つ失敗メッセージは今回の場合、`greeting`関数から得た値を出力することでしょう。 +`greeting`関数から得た実際の値で埋められたプレースホルダーを含むフォーマット文字列からなるカスタムの失敗メッセージを与え、 +テスト関数を変更しましょう: ```rust,ignore #[test] fn greeting_contains_name() { let result = greeting("Carol"); + //挨拶は名前を含んでいません。値は`{}`でした assert!( result.contains("Carol"), "Greeting did not contain name, value was `{}`", result @@ -569,7 +797,9 @@ fn greeting_contains_name() { } ``` -Now when we run the test, we’ll get a more informative error message: + + +これでテストを実行したら、より有益なエラーメッセージが得られるでしょう: ```text ---- tests::greeting_contains_name stdout ---- @@ -578,27 +808,45 @@ Now when we run the test, we’ll get a more informative error message: note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` -We can see the value we actually got in the test output, which would help us -debug what happened instead of what we were expecting to happen. + + + +実際に得られた値がテスト出力に見られ、起こると想定していたものではなく、 +起こったものをデバッグするのに役に立ちます。 + + + +### `should_panic`でパニックが発生することを確認する + + + + + + + + -### Checking for Panics with `should_panic` +期待する正しい値をコードが返すことを確認することに加えて、想定通りにコードがエラー状態を扱っていることを確認するのも重要です。 +例えば、第9章のリスト9-9で生成した`Guess`型を考えてください。`Guess`を使用する他のコードは、 +`Guess`のインスタンスは1から100の範囲の値しか含まないという保証に依存しています。 +その範囲外の値で`Guess`インスタンスを生成しようとするとパニックすることを確認するテストを書くことができます。 -In addition to checking that our code returns the correct values we expect, -it’s also important to check that our code handles error conditions as we -expect. For example, consider the `Guess` type that we created in Chapter 9, -Listing 9-9. Other code that uses `Guess` depends on the guarantee that `Guess` -instances will only contain values between 1 and 100. We can write a test that -ensures that attempting to create a `Guess` instance with a value outside that -range panics. + + + -We do this by adding another attribute, `should_panic`, to our test function. -This attribute makes a test pass if the code inside the function panics; the -test will fail if the code inside the function doesn’t panic. +これは、テスト関数に`should_panic`という別のアトリビュートを追加することで達成できます。 +このアトリビュートは、関数内のコードがパニックしたら、テストを通過させます。つまり、 +関数内のコードがパニックしなかったら、テストは失敗するわけです。 -Listing 11-8 shows a test that checks that the error conditions of `Guess::new` -happen when we expect: + + -Filename: src/lib.rs +リスト11-8は、想定した時に`Guess::new`のエラー状態が発生していることを確認するテストを示しています: + + + +ファイル名: src/lib.rs ```rust pub struct Guess { @@ -608,6 +856,7 @@ pub struct Guess { 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); } @@ -629,12 +878,17 @@ mod tests { } ``` -Listing 11-8: Testing that a condition will cause a -`panic!` + + + +リスト11-8: 状況が`panic!`を引き起こすとテストする -We place the `#[should_panic]` attribute after the `#[test]` attribute and -before the test function it applies to. Let’s look at the result when this test -passes: + + + + +`#[test]`アトリビュートの後、適用するテスト関数の前に`#[should_panic]`アトリビュートを配置しました。 +このテストが通るときの結果を見ましょう: ```text running 1 test @@ -643,8 +897,10 @@ test tests::greater_than_100 ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Looks good! Now let’s introduce a bug in our code by removing the condition -that the `new` function will panic if the value is greater than 100: + + + +よさそうですね!では、値が100より大きいときに`new`関数がパニックするという状態を除去することでコードにバグを導入しましょう: ```rust # pub struct Guess { @@ -664,7 +920,9 @@ impl Guess { } ``` -When we run the test in Listing 11-8, it will fail: + + +リスト11-8のテストを実行すると、失敗するでしょう: ```text running 1 test @@ -678,20 +936,33 @@ failures: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out ``` -We don’t get a very helpful message in this case, but when we look at the test -function, we see that it’s annotated with `#[should_panic]`. The failure we got -means that the code in the test function did not cause a panic. + + + + +この場合、それほど役に立つメッセージは得られませんが、テスト関数に目を向ければ、 +`#[should_panic]`で注釈されていることがわかります。得られた失敗は、 +テスト関数のコードがパニックを引き起こさなかったことを意味するのです。 + + + + + + + + + -Tests that use `should_panic` can be imprecise because they only indicate that -the code has caused some panic. A `should_panic` test would pass even if the -test panics for a different reason than the one we were expecting to happen. To -make `should_panic` tests more precise, we can add an optional `expected` -parameter to the `should_panic` attribute. The test harness will make sure that -the failure message contains the provided text. For example, consider the -modified code for `Guess` in Listing 11-9 where the `new` function panics with -different messages depending on whether the value was too small or too large: +`should_panic`を使用するテストは不正確なこともあります。なぜなら、コードが何らかのパニックを起こしたことしか示さないからです。 +`should_panic`のテストは、起きると想定していたもの以外の理由でテストがパニックしても通ってしまうのです。 +`should_panic`のテストの正確を期すために、`should_panic`アトリビュートのオプションの`expected`引数を追加できます。 +このテストの拘束具が、失敗メッセージに与えられたテキストが含まれていることを確かめてくれるでしょう。 +例えば、リスト11-9の`Guess`の変更されたコードを考えてください。ここでは、 +`new`関数は、値の大小によって異なるメッセージでパニックします。 -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust # pub struct Guess { @@ -703,9 +974,11 @@ different messages depending on whether the value was too small or too large: impl Guess { pub fn new(value: u32) -> Guess { if value < 1 { + //予想値は、1以上でなければなりません panic!("Guess value must be greater than or equal to 1, got {}.", value); } else if value > 100 { + //予想値は100以下でなければなりません panic!("Guess value must be less than or equal to 100, got {}.", value); } @@ -728,22 +1001,34 @@ mod tests { } ``` -Listing 11-9: Testing that a condition will cause a -`panic!` with a particular panic message + + + +リスト11-9: 状況が特定のパニックメッセージで`panic!`を引き起こすことをテストする -This test will pass because the value we put in the `should_panic` attribute’s -`expected` parameter is a substring of the message that the `Guess::new` -function panics with. We could have specified the entire panic message that we -expect, which in this case would be `Guess value must be less than or equal to -100, got 200.` What you choose to specify in the expected parameter for -`should_panic` depends on how much of the panic message is unique or dynamic -and how precise you want your test to be. In this case, a substring of the -panic message is enough to ensure that the code in the test function executes -the `else if value > 100` case. + + + + + + + + + -To see what happens when a `should_panic` test with an `expected` message -fails, let’s again introduce a bug into our code by swapping the bodies of the -`if value < 1` and the `else if value > 100` blocks: +`should_panic`アトリビュートの`expected`引数においた値が`Guess::new`関数がパニックしたメッセージの一部になっているので、 +このテストは通ります。予想されるパニックメッセージ全体を指定することもでき、そうすれば今回の場合、 +`Guess value must be less than or equal to 100, got 200.`となります。 +`should_panic`の予想される引数に指定すると決めたものは、パニックメッセージの固有性や活動性、 +テストの正確性によります。今回の場合、パニックメッセージの一部でテスト関数内のコードが、 +`else if value > 100`ケースを実行していると確認するのに事足りるのです。 + + + + + +`expected`メッセージありの`should_panic`テストが失敗すると何が起きるのが確かめるために、 +`if value < 1`と`else if value > 100`ブロックの本体を入れ替えることで再度コードにバグを仕込みましょう: ```rust,ignore if value < 1 { @@ -753,7 +1038,9 @@ if value < 1 { } ``` -This time when we run the `should_panic` test, it will fail: + + +`should_panic`テストを実行すると、今回は失敗するでしょう: ```text running 1 test @@ -773,12 +1060,20 @@ failures: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out ``` -The failure message indicates that this test did indeed panic as we expected, -but the panic message did not include the expected string `'Guess value must be -less than or equal to 100'`. The panic message that we did get in this case was -`Guess value must be greater than or equal to 1, got 200.` Now we can start -figuring out where our bug is! + + + + + + +この失敗メッセージは、このテストが確かにまさしく予想通りパニックしたことを示唆していますが、 +パニックメッセージは、予想される文字列の`'Guess value must be less than or equal to 100'`を含んでいませんでした。 +実際に得られたパニックメッセージは今回の場合、`Guess value must be greater than or equal to 1, got 200`でした。 +それでバグの所在地を割り出し始めることができるわけです! + + + + -Now that you know several ways to write tests, let’s look at what is happening -when we run our tests and explore the different options we can use with `cargo -test`. +今やテスト記法を複数知ったので、テストを走らせる際に起きていることに目を向け、 +`cargo test`で使用できる色んなオプションを探求しましょう。 diff --git a/second-edition/src/ch11-02-running-tests.md b/second-edition/src/ch11-02-running-tests.md index 11fe2acc2..e2b7e8ca2 100644 --- a/second-edition/src/ch11-02-running-tests.md +++ b/second-edition/src/ch11-02-running-tests.md @@ -1,68 +1,118 @@ -## Controlling How Tests Are Run - -Just as `cargo run` compiles your code and then runs the resulting binary, -`cargo test` compiles your code in test mode and runs the resulting test -binary. You can specify command line options to change the default behavior of -`cargo test`. For example, the default behavior of the binary produced by -`cargo test` is to run all the tests in parallel and capture output generated -during test runs, preventing the output from being displayed and making it -easier to read the output related to the test results. - -Some command line options go to `cargo test` and some go to the resulting test -binary. To separate these two types of arguments, you list the arguments that -go to `cargo test` followed by the separator `--` and then the arguments that -go to the test binary. Running `cargo test --help` displays the options you can -use with `cargo test`, and running `cargo test -- --help` displays the options -you can use after the separator `--`. - -### Running Tests in Parallel or Consecutively - -When you run multiple tests, by default they run in parallel using threads. -This means the tests will finish running faster so you can get feedback quicker -on whether or not your code is working. Because the tests are running at the -same time, make sure your tests don’t depend on each other or on any shared -state, including a shared environment, such as the current working directory or -environment variables. - -For example, say each of your tests runs some code that creates a file on disk -named *test-output.txt* and writes some data to that file. Then each test reads -the data in that file and asserts that the file contains a particular value, -which is different in each test. Because the tests run at the same time, one -test might overwrite the file between when another test writes and reads the -file. The second test will then fail, not because the code is incorrect, but -because the tests have interfered with each other while running in parallel. -One solution is to make sure each test writes to a different file; another -solution is to run the tests one at a time. - -If you don’t want to run the tests in parallel or if you want more fine-grained -control over the number of threads used, you can send the `--test-threads` flag -and the number of threads you want to use to the test binary. Take a look at -the following example: + + +## テストの実行法を制御する + + + + + + + + + +`cargo run`がコードをコンパイルし、出来上がったバイナリを走らせるのと全く同様に、 +`cargo test`はコードをテストモードでコンパイルし、出来上がったテストバイナリを実行します。 +コマンドラインオプションを指定して`cargo test`の規定動作を変更することができます。 +例えば、`cargo test`で生成されるバイナリの規定動作は、テストを全て並行に実行し、 +テスト実行中に生成された出力をキャプチャし、出力が表示されるのを防ぎ、 +テスト結果に関係する出力を読みやすくします。 + + + + + + + + +コマンドラインオプションの中には`cargo test`にかかるものや、出来上がったテストバイナリにかかるものがあります。 +この2種の引数を区別するために、`cargo test`にかかる引数を`--`という区分記号の後に列挙し、 +それからテストバイナリにかかる引数を列挙します。`cargo test --help`を走らせると、`cargo test`で使用できるオプションが表示され、 +`cargo test -- --help`を走らせると、`--`という区分記号の後に使えるオプションが表示されます。 + + + +### テストを並行または連続して実行する + + + + + + + + +複数のテストを実行するとき、標準では、スレッドを使用して並行に走ります。これはつまり、 +テストが早く実行し終わり、コードが機能しているいかんにかかわらず、反応をより早く得られることを意味します。 +テストは同時に実行されているので、テストが相互や共有された環境を含む他の共通の状態に依存してないことを確かめてください。 +現在の作業対象ディレクトリや環境変数などですね。 + + + + + + + + + + + +例えば、各テストがディスクに*test_output.txt*というファイルを作成し、何らかのデータを書き込むコードを走らせるとしてください。 +そして、各テストはそのファイルのデータを読み取り、ファイルが特定の値を含んでいるとアサーションし、 +その値は各テストで異なります。テストが同時に走るので、あるテストが、 +他のテストが書き込んだり読み込んだりする間隙にファイルを上書きするかもしれません。 +それから2番目のテストが失敗します。コードが不正だからではなく、 +並行に実行されている間にテストがお互いに邪魔をしてしまったせいです。 +各テストが異なるファイルに書き込むことを確かめるのが一つの解決策です; 別の解決策では、 +一度に一つのテストを実行します。 + + + + + + +並行にテストを実行したくなかったり、使用されるスレッド数をよりきめ細かく制御したい場合、 +`--test-threads`フラグと使用したいスレッド数をテストバイナリに送ることができます。 +以下の例に目を向けてください: ```text $ cargo test -- --test-threads=1 ``` -We set the number of test threads to `1`, telling the program not to use any -parallelism. Running the tests using one thread will take longer than running -them in parallel, but the tests won’t interfere with each other if they share -state. + + + + -### Showing Function Output +テストスレッドの数を`1`にセットし、並行性を使用しないようにプログラムに指示しています。 +1スレッドのみを使用してテストを実行すると、並行に実行するより時間がかかりますが、 +状態を共有していても、お互いに邪魔をすることはありません。 -By default, if a test passes, Rust’s test library captures anything printed to -standard output. For example, if we call `println!` in a test and the test -passes, we won’t see the `println!` output in the terminal: we’ll only see the -line that indicates the test passed. If a test fails, we’ll see whatever was -printed to standard output with the rest of the failure message. + -As an example, Listing 11-10 has a silly function that prints the value of its -parameter and returns 10, as well as a test that passes and a test that fails. +### 関数の出力を表示する -Filename: src/lib.rs + + + + + + +標準では、テストが通ると、Rustのテストライブラリは標準出力に表示されたものをキャプチャします。例えば、 +テストで`println!`を呼び出してテストが通ると、`println!`の出力は、ターミナルに表示されません: +テストが通ったことを示す行しか見れないでしょう。テストが失敗すれば、 +残りの失敗メッセージと共に、標準出力に出力されたものが全て見えるでしょう。 + + + + +例として、リスト11-10は引数の値を出力し、10を返す馬鹿げた関数と通過するテスト1つ、失敗するテスト1つです。 + + + +ファイル名: src/lib.rs ```rust fn prints_and_returns_10(a: i32) -> i32 { + //{}という値を得た println!("I got the value {}", a); 10 } @@ -85,10 +135,14 @@ mod tests { } ``` -Listing 11-10: Tests for a function that calls -`println!` + + + +リスト11-10: `println!`を呼び出す関数用のテスト -When we run these tests with `cargo test`, we’ll see the following output: + + +これらのテストを`cargo test`で実行すると、以下のような出力を目の当たりにするでしょう: ```text running 2 tests @@ -110,20 +164,29 @@ failures: test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out ``` -Note that nowhere in this output do we see `I got the value 4`, which is what -is printed when the test that passes runs. That output has been captured. The -output from the test that failed, `I got the value 8`, appears in the section -of the test summary output, which also shows the cause of the test failure. + + + + + +この出力のどこにも`I got the value 4`という出力が見られないことに注意してください。 +この出力は、通るテストが走る際に出力されるものです。この出力はキャプチャされてしまったのです。 +失敗したテストからの出力である`I got the value 8`はテスト総括出力の区域に出現し、 +ここには、テスト失敗の原因も表示されています。 -If we want to see printed values for passing tests as well, we can disable the -output capture behavior by using the `--nocapture` flag: + + + +通過するテストについても出力される値が見たかったら、出力キャプチャ機能を`--nocapture`フラグで無効化することができます: ```text $ cargo test -- --nocapture ``` -When we run the tests in Listing 11-10 again with the `--nocapture` flag, we -see the following output: + + + +リスト11-10のテストを`--nocapture`フラグと共に再度実行したら、以下のような出力を目の当たりにします: ```text running 2 tests @@ -144,22 +207,38 @@ failures: test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out ``` -Note that the output for the tests and the test results are interleaved; the -reason is that the tests are running in parallel, as we talked about in the -previous section. Try using the `--test-threads=1` option and the `--nocapture` -flag, and see what the output looks like then! + + + + + +テスト用の出力とテスト結果の出力がまぜこぜになっていることに注意してください; +その理由は、前節で語ったようにテストが並行に実行されているからです。 +`-test-threads=1`オプションと`--nocapture`フラグを使ってみて、 +出力がどうなるか確かめてください! + + + +### 名前でテストの一部を実行する + + + + + + +時々、全テストを実行すると時間がかかってしまうことがあります。特定の部分のコードしか対象にしていない場合、 +そのコードに関わるテストのみを走らせたいかもしれません。`cargo test`に走らせたいテストの名前を引数として渡すことで、 +実行するテストを選ぶことができます。 -### Running a Subset of Tests by Name + + -Sometimes, running a full test suite can take a long time. If you’re working on -code in a particular area, you might want to run only the tests pertaining to -that code. You can choose which tests to run by passing `cargo test` the name -or names of the test(s) you want to run as an argument. +テストの一部を走らせる方法を模擬するために、リスト11-11に示したように、 +`add_two`関数用に3つテストを作成し、走らせるテストを選択します: -To demonstrate how to run a subset of tests, we’ll create three tests for our -`add_two` function, as shown in Listing 11-11, and choose which ones to run: + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust pub fn add_two(a: i32) -> i32 { @@ -187,11 +266,15 @@ mod tests { } ``` -Listing 11-11: Three tests with three different -names + + -If we run the tests without passing any arguments, as we saw earlier, all the -tests will run in parallel: +リスト11-11: 3つの異なる名前の3つのテスト + + + + +以前見かけたように、引数なしでテストを走らせたら、全テストが並行に走ります: ```text running 3 tests @@ -202,9 +285,13 @@ test tests::one_hundred ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -#### Running Single Tests + + +#### 単独のテストを走らせる + + -We can pass the name of any test function to `cargo test` to run only that test: +あらゆるテスト関数の名前を`cargo test`に渡して、そのテストのみを実行することができます: ```text $ cargo test one_hundred @@ -217,18 +304,29 @@ test tests::one_hundred ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out ``` -Only the test with the name `one_hundred` ran; the other two tests didn't match -that name. The test output lets us know we had more tests than what this -command ran by displaying `2 filtered out` at the end of the summary line. + + + + +`one_hundred`という名前のテストだけが走りました; 他の2つのテストはその名前に合致しなかったのです。 +まとめ行の最後に`2 filtered out`と表示することでテスト出力は、このコマンドが走らせた以上のテストがあることを知らせてくれています。 + + + + +この方法では、複数のテストの名前を指定することはできません; `cargo test`に与えられた最初の値のみが使われるのです。 +ですが、複数のテストを走らせる方法もあります。 + + -We can’t specify the names of multiple tests in this way; only the first value -given to `cargo test` will be used. But there is a way to run multiple tests. +#### 複数のテストを実行するようフィルターをかける -#### Filtering to Run Multiple Tests + + + -We can specify part of a test name, and any test whose name matches that value -will be run. For example, because two of our tests’ names contain `add`, we can -run those two by running `cargo test add`: +テスト名の一部を指定して、その値に合致するあらゆるテストを走らせることができます。例えば、 +我々のテストの2つが`add`という名前を含むので、`cargo test add`を実行することで、その二つを走らせることができます: ```text $ cargo test add @@ -242,20 +340,32 @@ test tests::add_three_and_two ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out ``` -This command ran all tests with `add` in the name name and filtered out the -test named `one_hundred`. Also note that the module in which tests appear -becomes part of the test’s name, so we can run all the tests in a module by -filtering on the module’s name. + + + + -### Ignoring Some Tests Unless Specifically Requested +このコマンドは名前に`add`を含むテストを全て実行し、`one_hundred`という名前のテストを除外しました。 +また、テストが出現するモジュールがテスト名の一部になっていて、 +モジュール名でフィルターをかけることで、あるモジュール内のテスト全てを実行できることに注目してください。 -Sometimes a few specific tests can be very time-consuming to execute, so you -might want to exclude them during most runs of `cargo test`. Rather than -listing as arguments all tests you do want to run, you can instead annotate the -time-consuming tests using the `ignore` attribute to exclude them, as shown -here: + -Filename: src/lib.rs +### 特に希望のない限りテストを無視する + + + + + + + +時として、いくつかの特定のテストが実行するのに非常に時間がかかることがあり、 +`cargo test`の実行のほとんどで除外したくなるかもしれません。引数として確かに実行したいテストを全て列挙するのではなく、 +ここに示したように代わりに時間のかかるテストを`ignore`アトリビュートで除外すると注釈することができます。 + + + +ファイル名: src/lib.rs ```rust #[test] @@ -266,12 +376,16 @@ fn it_works() { #[test] #[ignore] fn expensive_test() { + // 実行に1時間かかるコード // code that takes an hour to run } ``` -After `#[test]` we add the `#[ignore]` line to the test we want to exclude. Now -when we run our tests, `it_works` runs, but `expensive_test` doesn’t: + + + +`#[test]`の後の除外したいテストに`#[ignore]`行を追加しています。これで、 +テストを実行したら、`it_works`は実行されるものの、`expensive_test`は実行されません: ```text $ cargo test @@ -286,8 +400,11 @@ test it_works ... ok test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out ``` -The `expensive_test` function is listed as `ignored`. If we want to run only -the ignored tests, we can use `cargo test -- --ignored`: + + + +`expensive_test`関数は、`ignored`と列挙されています。無視されるテストのみを実行したかったら、 +`cargo test -- --ignored`を使うことができます: ```text $ cargo test -- --ignored @@ -300,7 +417,11 @@ test expensive_test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out ``` -By controlling which tests run, you can make sure your `cargo test` results -will be fast. When you’re at a point where it makes sense to check the results -of the `ignored` tests and you have time to wait for the results, you can run -`cargo test -- --ignored` instead. + + + + + +どのテストを走らせるか制御することで、結果が早く出ることを確かめることができるのです。 +`ignored`テストの結果を確認することが道理に合い、結果を待つだけの時間ができたときに、 +代わりに`cargo test -- --ignored`を走らせることができます。 diff --git a/second-edition/src/ch11-03-test-organization.md b/second-edition/src/ch11-03-test-organization.md index f0617aaed..9ac427876 100644 --- a/second-edition/src/ch11-03-test-organization.md +++ b/second-edition/src/ch11-03-test-organization.md @@ -1,41 +1,71 @@ -## Test Organization + -As mentioned at the start of the chapter, testing is a complex discipline, and -different people use different terminology and organization. The Rust community -thinks about tests in terms of two main categories: *unit tests* and -*integration tests*. Unit tests are small and more focused, testing one module -in isolation at a time, and can test private interfaces. Integration tests are -entirely external to your library and use your code in the same way any other -external code would, using only the public interface and potentially exercising -multiple modules per test. +## テストの体系化 -Writing both kinds of tests is important to ensure that the pieces of your -library are doing what you expect them to separately and together. + + + + + + + + -### Unit Tests +章の初めで触れたように、テストは複雑な鍛錬であり、人によって専門用語や体系化が異なります。 +Rustのコミュニティでは、テストを2つの大きなカテゴリで捉えています: *単体テスト*と*結合テスト*です。 +単体テストは小規模でより集中していて、個別に1回に1モジュールをテストし、非公開のインターフェイスもテストする可能性があります。 +結合テストは、完全にライブラリ外になり、他の外部コード同様に自分のコードを使用し、公開インターフェイスのみ使用し、 +1テストにつき複数のモジュールを用いることもあります。 -The purpose of unit tests is to test each unit of code in isolation from the -rest of the code to quickly pinpoint where code is and isn’t working as -expected. We put unit tests in the *src* directory in each file with the code -that they’re testing. The convention is that we create a module named `tests` -in each file to contain the test functions, and we annotate the module with -`cfg(test)`. + + -#### The Tests Module and `#[cfg(test)]` +どちらのテストを書くのも、ライブラリの一部が個別かつ共同でしてほしいことをしていることを確認するのに重要なのです。 -The `#[cfg(test)]` annotation on the tests module tells Rust to compile and run -the test code only when we run `cargo test`, but not when we run `cargo build`. -This saves compile time when we only want to build the library and saves space -in the resulting compiled artifact because the tests are not included. You’ll -see that because integration tests go in a different directory, they don’t need -the `#[cfg(test)]` annotation. However, because unit tests go in the same files -as the code, we use `#[cfg(test)]` to specify that they shouldn’t be included -in the compiled result. + -Recall that when we generated the new `adder` project in the first section of -this chapter, Cargo generated this code for us: +### 単体テスト -Filename: src/lib.rs + + + + + + + +単体テストの目的は、残りのコードから切り離して各単位のコードをテストし、 +コードが想定通り、動いたり動いていなかったりする箇所を急速に特定することです。 +単体テストは、テスト対象となるコードと共に、*src*ディレクトリの各ファイルに置きます。 +慣習は、各ファイルに`tests`という名前のモジュールを作り、テスト関数を含ませ、 +そのモジュールを`cfg(test)`で注釈することです。 + + + +#### テストモジュールと`#[cfg(test)]` + + + + + + + + + + +testsモジュールの`#[cfg(test)]`という注釈は、コンパイラに`cargo build`を走らせた時ではなく、`cargo test`を走らせた時にだけ、 +テストコードをコンパイルし走らせるよう指示します。これにより、ライブラリをビルドしたいだけの時にコンパイルタイムを節約し、 +テストが含まれないので、コンパイル後の成果物のサイズも節約します。結合テストは別のディレクトリに存在することになるので、 +`#[cfg(test)]`注釈は必要ないとわかるでしょう。しかしながら、単体テストはコードと同じファイルに存在するので、 +`#[cfg(test)]`を使用してコンパイル結果に含まれないよう指定するのです。 + + + + +この章の最初の節で新しい`adder`プロジェクトを生成した時に、Cargoがこのコードも生成したことを思い出してください: + + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -47,24 +77,40 @@ mod tests { } ``` -This code is the automatically generated test module. The attribute `cfg` -stands for *configuration* and tells Rust that the following item should only -be included given a certain configuration option. In this case, the -configuration option is `test`, which is provided by Rust for compiling and -running tests. By using the `cfg` attribute, Cargo compiles our test code only -if we actively run the tests with `cargo test`. This includes any helper -functions that might be within this module, in addition to the functions -annotated with `#[test]`. + + + + + + + + + +このコードが自動生成されたテストモジュールです。`cfg`というアトリビュートは、*configuration*を表していて、 +コンパイラに続く要素が、ある特定の設定オプションを与えて含まれるように指示します。 +今回の場合、設定オプションは、`test`であり、言語によって提供されているテストをコンパイルし、 +走らせるためのものです。`cfg`アトリビュートを使用することで、`cargo test`で積極的にテストを実行した場合のみ、 +Cargoがテストコードをコンパイルします。これには、このモジュールに含まれるかもしれないヘルパー関数全ても含まれ、 +`#[test]`で注釈された関数だけにはなりません。 + + + +#### 非公開関数をテストする -#### Testing Private Functions + + + + + -There’s debate within the testing community about whether or not private -functions should be tested directly, and other languages make it difficult or -impossible to test private functions. Regardless of which testing ideology you -adhere to, Rust’s privacy rules do allow you to test private functions. -Consider the code in Listing 11-12 with the private function `internal_adder`: +テストコミュニティ内で非公開関数を直接テストできるべきかについては議論があり、 +他の言語では非公開関数をテストするのは困難だったり、不可能だったりします。 +あなたがどちらのテストイデオロギーを支持しているかに関わらず、Rustの公開性規則により、 +非公開関数をテストすることが可能です。リスト11-12の非公開関数`internal_adder`を含むコードを考えてください: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust pub fn add_two(a: i32) -> i32 { @@ -86,36 +132,64 @@ mod tests { } ``` -Listing 11-12: Testing a private function + + +リスト11-12: 非公開関数をテストする + + + + + + + +`internal_adder`関数は`pub`とマークされていないものの、テストも単なるRustのコードであり、 +`tests`モジュールもただのモジュールでしかないので、テスト内で`internal_adder`を普通にインポートし呼び出すことができます。 +非公開関数はテストできるべきではないとお考えなら、Rustにはそれを強制するものは何もありません。 + + + +### 結合テスト -Note that the `internal_adder` function is not marked as `pub`, but because -tests are just Rust code and the `tests` module is just another module, we can -import and call `internal_adder` in a test just fine. If you don’t think -private functions should be tested, there’s nothing in Rust that will compel -you to do so. + + + + + + + -### Integration Tests +Rustにおいて、結合テストは完全にライブラリ外のものです。他のコードがするのと全く同様にあなたのライブラリを使用するので、 +ライブラリの公開APIの一部である関数しか呼び出すことはできません。その目的は、 +ライブラリのいろんな部分が共同で正常に動作していることをテストすることです。 +単体では正常に動くコードも、結合した状態だと問題を孕む可能性もあるので、 +結合したコードのテストの範囲も同様に重要になるのです。結合テストを作成するには、 +まず*tests*ディレクトリが必要になります。 -In Rust, integration tests are entirely external to your library. They use your -library in the same way any other code would, which means they can only call -functions that are part of your library’s public API. Their purpose is to test -that many parts of your library work together correctly. Units of code that -work correctly on their own could have problems when integrated, so test -coverage of the integrated code is important as well. To create integration -tests, you first need a *tests* directory. + -#### The *tests* Directory +#### *tests*ディレクトリ -We create a *tests* directory at the top level of our project directory, next -to *src*. Cargo knows to look for integration test files in this directory. We -can then make as many test files as we want to in this directory, and Cargo -will compile each of the files as an individual crate. + + + + -Let’s create an integration test. With the code in Listing 11-12 still in the -*src/lib.rs* file, make a *tests* directory, create a new file named -*tests/integration_test.rs*, and enter the code in Listing 11-13: +プロジェクトディレクトリのトップ階層、*src*の隣に*tests*ディレクトリを作成します。 +Cargoは、このディレクトリに結合テストのファイルを探せることを把握しています。 +そして、このディレクトリ内にいくらでもテストファイルを作成することができ、 +Cargoはそれぞれのファイルを個別のクレートとしてコンパイルします。 -Filename: tests/integration_test.rs + + + + +結合テストを作成しましょう。リスト11-12のコードが*src/lib.rs*ファイルにあるまま、 +*tests*ディレクトリを作成し、*tests/integration_test.rs*という名前の新しいファイルを生成し、 +リスト11-13のコードを入力してください: + + + +ファイル名: tests/integration_test.rs ```rust,ignore extern crate adder; @@ -126,16 +200,26 @@ fn it_adds_two() { } ``` -Listing 11-13: An integration test of a function in the -`adder` crate + + + +リスト11-13: `adder`クレートの関数の結合テスト + + + + -We’ve added `extern crate adder` at the top of the code, which we didn’t need -in the unit tests. The reason is that each test in the `tests` directory is a -separate crate, so we need to import our library into each of them. +コードの頂点に`extern crate adder`を追記しましたが、これは単体テストでは必要なかったものです。 +理由は、`tests`ディレクトリのテストはそれぞれ個別のクレートであるため、 +各々ライブラリをインポートする必要があるためです。 -We don’t need to annotate any code in *tests/integration_test.rs* with -`#[cfg(test)]`. Cargo treats the `tests` directory specially and compiles files -in this directory only when we run `cargo test`. Run `cargo test` now: + + + + +*tests/integration_test.rs*のどんなコードも`#[cfg(test)]`で注釈する必要はありません。 +Cargoは`tests`ディレクトリを特別に扱い、`cargo test`を走らせた時にのみこのディレクトリのファイルをコンパイルするのです。 +さあ、`cargo test`を実行してください: ```text $ cargo test @@ -162,27 +246,45 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -The three sections of output include the unit tests, the integration test, and -the doc tests. The first section for the unit tests is the same as we’ve been -seeing: one line for each unit test (one named `internal` that we added in -Listing 11-12) and then a summary line for the unit tests. - -The integration tests section starts with the line `Running -target/debug/deps/integration-test-ce99bcc2479f4607` (the hash at the end of -your output will be different). Next, there is a line for each test function in -that integration test and a summary line for the results of the integration -test just before the `Doc-tests adder` section starts. - -Recall that adding more unit test functions in any *src* file adds more test -result lines to the unit tests section. Adding more test functions to the -integration test file we created adds more lines to that file’s section. Each -integration test file has its own section, so if we add more files in the -*tests* directory, there will be more integration test sections. - -We can still run a particular integration test function by specifying the test -function’s name as an argument to `cargo test`. To run all the tests in a -particular integration test file, use the `--test` argument of `cargo test` -followed by the name of the file: + + + + + +3つの区域の出力が単体テスト、結合テスト、ドックテストを含んでいます。単体テスト用の最初の区域は、 +今まで見てきたものと同じです: 各単体テストに1行(リスト11-12で追加した`internal`という名前のもの)と、 +単体テストの総括行です。 + + + + + + + +結合テストの区域は、 +`Running target/debug/deps/integration-test-ce99bcc2479f4607`という行で始まっています(最後のハッシュは違うでしょう)。 +次に、この結合テストの各テスト関数用の行があり、`Doc-tests adder`区域が始まる直前に、 +結合テストの結果用の総括行があります。 + + + + + + + +どの*src*ファイルに単体テスト関数を追加しても、単体テスト区域のテスト結果の行が増えることを思い出してください。 +作成した結合テストファイルにもっとテスト関数を追加すると、そのファイルの区域に行が増えることになります。 +結合テストファイルはそれぞれ独自の区域があるため、*tests*ディレクトリにさらにファイルを追加すれば、 +結合テストの区域が増えることになるでしょう。 + + + + + + +それでも、テスト関数の名前を引数として`cargo test`に指定することで、特定の結合テスト関数を走らせることができます。 +特定の結合テストファイルにあるテストを全て走らせるには、`cargo test`に`--test`引数、 +その後にファイル名を続けて使用してください: ```text $ cargo test --test integration_test @@ -195,40 +297,64 @@ test it_adds_two ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -This command runs only the tests in the *tests/integration_test.rs* file. + + +このコマンドは、*tests/integration_test.rs*ファイルにあるテストのみを実行します。 + + -#### Submodules in Integration Tests +#### 結合テスト内のサブモジュール -As you add more integration tests, you might want to make more than one file in -the *tests* directory to help organize them; for example, you can group the -test functions by the functionality they’re testing. As mentioned earlier, each -file in the *tests* directory is compiled as its own separate crate. + + + + -Treating each integration test file as its own crate is useful to create -separate scopes that are more like the way end users will be using your crate. -However, this means files in the *tests* directory don’t share the same -behavior as files in *src* do, which you learned in Chapter 7 regarding how to -separate code into modules and files. +結合テストを追加するにつれて、*tests*ディレクトリに2つ以上のファイルを作成して体系化したくなるかもしれません; +例えば、テスト対象となる機能でテスト関数をグループ化することができます。前記したように、 +*tests*ディレクトリの各ファイルは、個別のクレートとしてコンパイルされます。 -The different behavior of files in the *tests* directory is most noticeable -when you have a set of helper functions that would be useful in multiple -integration test files and you try to follow the steps in the “Moving Modules -to Other Files” section of Chapter 7 to extract them into a common module. For -example, if we create *tests/common.rs* and place a function named `setup` in -it, we can add some code to `setup` that we want to call from multiple test -functions in multiple test files: + + + + + -Filename: tests/common.rs +各結合テストファイルをそれ自身のクレートとして扱うと、 +エンドユーザが自分のクレートを使用するかのような個別のスコープを生成するのに役立ちます。 +ですが、これは*tests*ディレクトリのファイルは、*src*のファイルとは同じ振る舞いを共有しないことを意味し、 +これについてはコードをモジュールとファイルに分ける方法について第7章で学びました。 + + + + + + + + + +*tests*ディレクトリのファイルの異なる振る舞いは、複数の結合テストファイルで役に立ちそうなヘルパー関数ができ、 +第7章の「モジュールを別のファイルに移動する」節の手順に従って共通モジュールに抽出しようとした時に最も気付きやすくなります。 +例えば、*tests/common.rs*を作成し、そこに`setup`という名前の関数を配置したら、 +複数のテストファイルの複数のテスト関数から呼び出したい何らかのコードを`setup`に追加することができます: + + + +ファイル名: tests/common.rs ```rust pub fn setup() { + // ここにライブラリテスト固有のコードが来る // setup code specific to your library's tests would go here } ``` -When we run the tests again, we’ll see a new section in the test output for the -*common.rs* file, even though this file doesn’t contain any test functions, nor -did we call the `setup` function from anywhere: + + + + +再度テストを実行すると、*common.rs*ファイルは何もテスト関数を含んだり、`setup`関数をどこかから呼んだりしてないのに、 +テスト出力に*common.rs*用の区域が見えるでしょう。 ```text running 1 test @@ -256,26 +382,45 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Having `common` appear in the test results with `running 0 tests` displayed for -it is not what we wanted. We just wanted to share some code with the other -integration test files. + + + + +`common`が`running 0 tests`とテスト結果に表示されるのは、望んだ結果ではありません。 +ただ単に他の結合テストファイルと何らかのコードを共有したかっただけです。 -To avoid having `common` appear in the test output, instead of creating -*tests/common.rs*, we’ll create *tests/common/mod.rs*. In the “Rules of Module -Filesystems” section of Chapter 7, we used the naming convention -*module_name/mod.rs* for files of modules that have submodules, and we don’t -have submodules for `common` here, but naming the file this way tells Rust not -to treat the `common` module as an integration test file. When we move the -`setup` function code into *tests/common/mod.rs* and delete the -*tests/common.rs* file, the section in the test output will no longer appear. -Files in subdirectories of the *tests* directory don’t get compiled as separate -crates or have sections in the test output. + -After we’ve created *tests/common/mod.rs*, we can use it from any of the -integration test files as a module. Here’s an example of calling the `setup` -function from the `it_adds_two` test in *tests/integration_test.rs*: + + + + + + + + + + -Filename: tests/integration_test.rs +`common`がテスト出力に出現するのを防ぐには、*tests/common.rs*を作成する代わりに、 +*tests/common/mod.rs*を作成すればいいのです。第7章の「モジュールファイルシステムの規則」節において、 +*module_name/mod.rs*という命名規則をサブモジュールのあるモジュールのファイルに使用したので、 +ここでは`common`にサブモジュールはありませんが、 +このように命名することでコンパイラに`common`モジュールを結合テストファイルとして扱わないように指示します。 +`setup`関数のコードを*tests/common/mod.rs*に移動し、*tests/common.rs*ファイルを削除すると、 +テスト出力に区域はもう表示されなくなります。*tests*ディレクトリのサブディレクトリ内のファイルは個別クレートとしてコンパイルされたり、 +テスト出力に区域が表示されることがないのです。 + + + + + +*tests/common.mod.rs*を作成した後、それをどの結合テストファイルからもモジュールとして使用することができます。 +こちらは、*tests/integration_test.rs*内の`it_adds_two`テストから`setup`関数を呼び出す例です: + + + +ファイル名: tests/integration_test.rs ```rust,ignore extern crate adder; @@ -289,37 +434,63 @@ fn it_adds_two() { } ``` -Note that the `mod common;` declaration is the same as the module declarations -we demonstrated in Listing 7-4. Then in the test function, we can call the -`common::setup()` function. - -#### Integration Tests for Binary Crates - -If our project is a binary crate that only contains a *src/main.rs* file and -doesn’t have a *src/lib.rs* file, we can’t create integration tests in the -*tests* directory and use `extern crate` to import functions defined in the -*src/main.rs* file. Only library crates expose functions that other crates can -call and use; binary crates are meant to be run on their own. - -This is one of the reasons Rust projects that provide a binary have a -straightforward *src/main.rs* file that calls logic that lives in the -*src/lib.rs* file. Using that structure, integration tests *can* test the -library crate by using `extern crate` to exercise the important functionality. -If the important functionality works, the small amount of code in the -*src/main.rs* file will work as well, and that small amount of code doesn’t -need to be tested. - -## Summary - -Rust’s testing features provide a way to specify how code should function to -ensure it continues to work as we expect even as we make changes. Unit tests -exercise different parts of a library separately and can test private -implementation details. Integration tests check that many parts of the library -work together correctly, and they use the library’s public API to test the code -in the same way external code will use it. Even though Rust’s type system and -ownership rules help prevent some kinds of bugs, tests are still important to -help reduce logic bugs having to do with how your code is expected to behave. - -Let’s combine the knowledge you learned in this chapter and in previous -chapters and work on a project in the next chapter! - + + + + +`mod common;`という宣言は、リスト7-4で模擬したモジュール宣言と同じであることに注意してください。 +それから、テスト関数内で`common::setup()`関数を呼び出すことができます。 + + + +#### バイナリクレート用の結合テスト + + + + + + + +もしもプロジェクトが*src/main.rs*ファイルのみを含み、*src/lib.rs*ファイルを持たないバイナリクレートだったら、 +*tests*ディレクトリに結合テストを作成し、 +`extern crate`を使用して*src/main.rs*ファイルに定義された関数をインポートすることはできません。 +ライブラリクレートのみが、他のクレートが呼び出して使用できる関数を晒け出せるのです; +バイナリクレートはそれ単体で実行するという意味を持っています。 + + + + + + + + + +これは、バイナリを提供するRustのプロジェクトに、 +*src/lib.rs*ファイルに存在するロジックを呼び出す素直な*src/main.rs*ファイルがある一因になっています。 +この構造を使用して結合テストは、`extern crate`を使用して重要な機能を用いることでライブラリクレートをテストすることが*できます*。 +この重要な機能が動作すれば、*src/main.rs*ファイルの少量のコードも動作し、その少量のコードはテストする必要がないわけです。 + + + +## まとめ + + + + + + + + + + +Rustのテスト機能は、変更を加えた後でさえ想定通りにコードが機能し続けることを保証して、 +コードが機能すべき方法を指定する手段を提供します。単体テストはライブラリの異なる部分を個別に用い、 +非公開の実装詳細をテストすることができます。結合テストは、ライブラリのいろんな部分が共同で正常に動作することを確認し、 +ライブラリの公開APIを使用して外部コードが使用するのと同じ方法でコードをテストします。 +Rustの型システムと所有権ルールにある種のバグは防がれるものの、それでもテストは、 +コードの振る舞い方に関するロジックのバグを減らすのに重要なのです。 + + + + +この章と以前の章で学んだ知識を結集して次章のプロジェクトに取り掛かりましょう! From ebc4954c7db6419e1f9b0dc0a3b62ea0b8202199 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 6 Dec 2017 20:13:20 +0900 Subject: [PATCH 066/428] First draft of the chapter 12-0 and modifications on SUMMARY.md --- second-edition/src/SUMMARY.md | 22 ++-- second-edition/src/ch12-00-an-io-project.md | 108 +++++++++++++------- 2 files changed, 85 insertions(+), 45 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index bf2ac51fb..e7ea3bb91 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -105,13 +105,21 @@ - [テストを走らせる](ch11-02-running-tests.md) - [テストの体系化](ch11-03-test-organization.md) -- [An I/O Project: Building a Command Line Program](ch12-00-an-io-project.md) - - [Accepting Command Line Arguments](ch12-01-accepting-command-line-arguments.md) - - [Reading a File](ch12-02-reading-a-file.md) - - [Refactoring to Improve Modularity and Error Handling](ch12-03-improving-error-handling-and-modularity.md) - - [Developing the Library’s Functionality with Test Driven Development](ch12-04-testing-the-librarys-functionality.md) - - [Working with Environment Variables](ch12-05-working-with-environment-variables.md) - - [Writing Error Messages to Standard Error Instead of Standard Output](ch12-06-writing-to-stderr-instead-of-stdout.md) + + + + + + + + +- [入出力プロジェクト: コマンドラインプログラムを構築する](ch12-00-an-io-project.md) + - [コマンドライン引数を受け付ける](ch12-01-accepting-command-line-arguments.md) + - [ファイルを読み込む](ch12-02-reading-a-file.md) + - [リファクタリングでモジュール性の向上とエラー処理](ch12-03-improving-error-handling-and-modularity.md) + - [テスト駆動開発でライブラリの機能を開発する](ch12-04-testing-the-librarys-functionality.md) + - [環境変数を取り扱う](ch12-05-working-with-environment-variables.md) + - [標準出力ではなく標準エラーにエラーメッセージを書き込む](ch12-06-writing-to-stderr-instead-of-stdout.md) ## Thinking in Rust diff --git a/second-edition/src/ch12-00-an-io-project.md b/second-edition/src/ch12-00-an-io-project.md index 31c17c9f7..a883e2d6e 100644 --- a/second-edition/src/ch12-00-an-io-project.md +++ b/second-edition/src/ch12-00-an-io-project.md @@ -1,38 +1,70 @@ -# An I/O Project: Building a Command Line Program - -This chapter is a recap of the many skills you’ve learned so far and an -exploration of a few more standard library features. We’ll build a command line -tool that interacts with file and command line input/output to practice some of -the Rust concepts you now have under your belt. - -Rust’s speed, safety, *single binary* output, and cross-platform support make -it an ideal language for creating command line tools, so for our project, we’ll -make our own version of the classic command line tool `grep` (**g**lobally -search a **r**egular **e**xpression and **p**rint). In the simplest use case, -`grep` searches a specified file for a specified string. To do so, `grep` takes -as its arguments a filename and a string, and then reads the file and finds -lines in that file that contain the string argument. It then prints those lines. - -Along the way, we’ll show how to make our command line tool use features of the -terminal that many command line tools use. We’ll read the value of an -environment variable to allow the user to configure the behavior of our tool. -We’ll also print to the standard error console stream (`stderr`) instead of -standard output (`stdout`), so, for example, the user can redirect successful -output to a file while still seeing error messages onscreen. - -One Rust community member, Andrew Gallant, has already created a fully -featured, very fast version of `grep`, called `ripgrep`. By comparison, our -version of `grep` will be fairly simple, but this chapter will give you some of -the background knowledge you need to understand a real-world project like -`ripgrep`. - -Our `grep` project will combine a number of concepts you’ve learned so far: - -* Organizing code (using what you learned in modules, Chapter 7) -* Using vectors and strings (collections, Chapter 8) -* Handling errors (Chapter 9) -* Using traits and lifetimes where appropriate (Chapter 10) -* Writing tests (Chapter 11) - -We’ll also briefly introduce closures, iterators, and trait objects, which -Chapters 13 and 17 will cover in detail. + + +# 入出力プロジェクト: コマンドラインプログラムを構築する + + + + + + +この章は、ここまでに学んできた多くのスキルを思い出すきっかけであり、もういくつか標準ライブラリの機能も探求します。 +ファイルやコマンドラインの入出力と相互作用するコマンドラインツールを構築し、 +今やあなたの支配下にあるRustの概念の一部を練習していきます。 + + + + + + + + + +Rustの速度、安全性、*単バイナリ*出力、クロスプラットフォームサポートにより、コマンドラインツールを作るのにふさわしい言語なので、 +このプロジェクトでは、独自の伝統的なコマンドラインツールの`grep`(**g**lobally search a **r**egular **e**xpression +and **p**rint: 正規表現をグローバルで検索し表示する)を作成していきます。最も単純な使用法では、 +`grep`は指定したファイルから指定した文字列を検索します。そうするには、 +`grep`は引数としてファイル名と文字列を受け取り、それからファイルを読み込んでそのファイル内で文字列引数を含む行を探すのです。 +そして、検索した行を出力します。 + + + + + + + + +その過程で、多くのコマンドラインツールが使用している端末の機能を使用させる方法を示します。 +環境変数の値を読み取ってユーザがこのツールの振る舞いを設定できるようにします。また、 +標準出力(`stdout`)の代わりに、標準エラー出力(`stderr`)するので、例えば、 +ユーザはエラーメッセージはスクリーン上で確認しつつ、成功した出力はファイルにリダイレクトできます。 + + + + + + + +あるRustコミュニティのメンバであるアンドリュー・ガラント(Andrew Gallant)が既に全機能装備の非常に高速な`grep`、 +`ripgrep`と呼ばれるものを作成しました。比較対象として、我々の`grep`はとても単純ですが、 +この章により、`ripgrep`のような現実世界のプロジェクトを理解するのに必要な背景知識の一部を身に付けられるでしょう。 + + + +この`grep`プロジェクトは、ここまでに学んできた多くの概念を集結させます: + + + + + + + +* コードを体系化する(モジュール、第7章で学んだことを使用) +* ベクタ型と文字列を使用する(コレクション、第8章) +* エラーを処理する(第9章) +* 適切な箇所でトレイトとライフタイムを使用する(第10章) +* テストを記述する(第11章) + + + + +さらに、クロージャ、イテレータ、トレイトオブジェクトなど、第13章、17章で詳しく解説するものもちょっとだけ紹介します。 From fc673617738e15906e14c4c81b1819a5680b0535 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 6 Dec 2017 22:18:09 +0900 Subject: [PATCH 067/428] First draft of the chapter 12-1 --- ...h12-01-accepting-command-line-arguments.md | 253 ++++++++++++------ 1 file changed, 168 insertions(+), 85 deletions(-) diff --git a/second-edition/src/ch12-01-accepting-command-line-arguments.md b/second-edition/src/ch12-01-accepting-command-line-arguments.md index b124f8ca3..6d12b354d 100644 --- a/second-edition/src/ch12-01-accepting-command-line-arguments.md +++ b/second-edition/src/ch12-01-accepting-command-line-arguments.md @@ -1,8 +1,13 @@ -## Accepting Command Line Arguments + -Let’s create a new project with, as always, `cargo new`. We’ll call our project -`minigrep` to distinguish it from the `grep` tool that you might already have -on your system. +## コマンドライン引数を受け付ける + + + + + +いつものように、`cargo new`で新しいプロジェクトを作りましょう。プロジェクトを`minigrep`と名付けて、 +既に自分のシステムに存在するかもしれない`grep`ツールと区別しましょう。 ```text $ cargo new --bin minigrep @@ -10,36 +15,58 @@ $ cargo new --bin minigrep $ cd minigrep ``` -The first task is to make `minigrep` accept its two command line arguments: the -filename and a string to search for. That is, we want to be able to run our -program with `cargo run`, a string to search for, and a path to a file to -search in, like so: + + + + + +最初の仕事は、`minigrep`を二つの引数を受け付けるようにすることです: ファイル名と検索する文字列ですね。 +つまり、`cargo run`で検索文字列と検索を行うファイルへのパスと共にプログラムを実行できるようになりたいということです。 +こんな感じにね: ```text $ cargo run searchstring example-filename.txt ``` -Right now, the program generated by `cargo new` cannot process arguments we -give it. However, some existing libraries on [Crates.io](https://crates.io/) -can help us with writing a program that accepts command line arguments, but -because you’re just learning this concept, let’s implement this capability -ourselves. + + + + + + +今現在は、`cargo new`で生成されたプログラムは、与えた引数を処理できません。しかしながら、 +[Crates.io](https://crates.io/)に存在するある既存のライブラリは、 +コマンドライン引数を受け付けるプログラムを書く手助けをしてくれますが、ちょうどこの概念を学んでいる最中なので、 +この機能を自分で実装しましょう。 + + -### Reading the Argument Values +### 引数の値を読み取る -To make sure `minigrep` is able to read the values of command line arguments we -pass to it, we’ll need a function provided in Rust’s standard library, which is -`std::env::args`. This function returns an *iterator* of the command line -arguments that were given to `minigrep`. We haven’t discussed iterators yet -(we’ll cover them fully in Chapter 13), but for now you only need to know two -details about iterators: iterators produce a series of values, and we can call -the `collect` function on an iterator to turn it into a collection, such as a -vector, containing all the elements the iterator produces. + + + + + + + + -Use the code in Listing 12-1 to allow your `minigrep` program to read any -command line arguments passed to it and then collect the values into a vector: +`minigrep`が渡したコマンドライン引数の値を読み取れていると確認するために、Rustの標準ライブラリで提供されている関数が必要になり、 +それは、`std::env::args`です。この関数は、`minigrep`に与えられたコマンドライン引数の*イテレータ*を返します。 +イテレータについてはまだ議論していません(完全には第13章で解説します)が、とりあえずイテレータに関しては、 +2つの詳細のみ知っていればいいです: イテレータは一連の値を生成すること、イテレータに対して`collect`関数を呼び出し、 +イテレータが生成する要素全部を含むベクタ型などのコレクションに変えられることです。 -Filename: src/main.rs + + + +リスト12-1のコードを使用して`minigrep`プログラムに渡されたあらゆるコマンドライン引数を読み取れるようにし、 +それからその値をベクタ型として集結させてください: + + + +ファイル名: src/main.rs ```rust use std::env; @@ -50,38 +77,65 @@ fn main() { } ``` -Listing 12-1: Collecting the command line arguments into -a vector and printing them - -First, we bring the `std::env` module into scope with a `use` statement so we -can use its `args` function. Notice that the `std::env::args` function is -nested in two levels of modules. As we discussed in Chapter 7, in cases where -the desired function is nested in more than one module, it’s conventional to -bring the parent module into scope rather than the function. As a result, we -can easily use other functions from `std::env`. It’s also less ambiguous than -adding `use std::env::args` and then calling the function with just `args` -because `args` might easily be mistaken for a function that’s defined in the -current module. - -> ### The `args` Function and Invalid Unicode + + + +リスト12-1: コマンドライン引数をベクタ型に集結させ、出力する + + + + + + + + + + + +まず、`std::env`モジュールを`use`文でスコープに導入したので、`args`関数が使用できます。 +`std::env::args`関数は、2レベルモジュールがネストされていることに気付いてください。 +第7章で議論したように、希望の関数が2モジュール以上ネストされている場合、 +関数ではなく親モジュールをスコープに導入するのが因習的です。結果として、 +`std::env`から別の関数も容易に使用することができます。また、 +`use std::env::args`を追記し、関数を`args`とするだけで呼び出すのに比べて曖昧でもありません。 +というのも、`args`は現在のモジュールに定義されている関数と容易に見間違えられるかもしれないからです。 + + + + + + + + + + +> ### `args`関数と不正なユニコード > -> Note that `std::env::args` will panic if any argument contains invalid -> Unicode. If your program needs to accept arguments containing invalid -> Unicode, use `std::env::args_os` instead. That function returns `OsString` -> values instead of `String` values. We’ve chosen to use `std::env::args` here -> for simplicity because `OsString` values differ per platform and are more -> complex to work with than `String` values. - -On the first line of `main`, we call `env::args`, and immediately use `collect` -to turn the iterator into a vector containing all the values produced by the -iterator. We can use the `collect` function to create many kinds of -collections, so we explicitly annotate the type of `args` to specify that we -want a vector of strings. Although we very rarely need to annotate types in -Rust, `collect` is one function you do often need to annotate because Rust -isn’t able to infer the kind of collection you want. - -Finally, we print the vector using the debug formatter, `:?`. Let’s try running -the code with no arguments, and then with two arguments: +> 引数のどれかが不正なユニコードを含んでいたら、`std::env::args`はパニックすることに注意してください。 +> プログラムが不正なユニコードを含む引数を受け付ける必要があるなら、代わりに`std::env::args_os`を使用してください。 +> この関数は、`String`値ではなく、`OsString`値を返します。ここでは、簡潔性のために`std::env::args`を使うことを選択しました。 +> なぜなら、`OsString`値はプラットフォームごとに異なり、`String`値に比べて取り扱いが煩雑だからです。 + + + + + + + + + +`main`の最初の行で`env::args`を呼び出し、そして即座に`collect`を使用して、 +イテレータをイテレータが生成する値全てを含むベクタ型に変換しています。 +`collect`関数を使用して多くの種類のコレクションを生成することができるので、 +`args`の型を明示的に注釈して文字列のベクタが欲しいのだと指定しています。Rustにおいて、 +型を注釈しなければならない頻度は非常に少ないのですが、`collect`はよく注釈が必要になる一つの関数なのです。 +コンパイラには、あなたが欲しているコレクションの種類が推論できないからです。 + + + + +最後に、デバッグ整形機の`:?`を使用してベクタを出力しています。引数なしでコードを走らせてみて、 +それから引数二つで試してみましょう: ```text $ cargo run @@ -93,22 +147,35 @@ $ cargo run needle haystack ["target/debug/minigrep", "needle", "haystack"] ``` -Notice that the first value in the vector is `"target/debug/minigrep"`, which -is the name of our binary. This matches the behavior of the arguments list in -C, letting programs use the name by which they were invoked in their execution. -It’s often convenient to have access to the program name in case we want to -print it in messages or change behavior of the program based on what command -line alias was used to invoke the program. But for the purposes of this -chapter, we’ll ignore it and save only the two arguments we need. + + + + + + + + +ベクタの最初の値は`"target/debug/minigrep"`であり、これはバイナリの名前であることに気付いてください。 +これはCの引数リストの振る舞いと合致し、実行時に呼び出された名前をプログラムに使わせてくれるわけです。 +メッセージで出力したり、プログラムを起動するのに使用されたコマンドラインエイリアスによってプログラムの振る舞いを変えたい場合に、 +プログラム名にアクセスするのにしばしば便利です。ですが、この章の目的には、これを無視し、必要な二つの引数のみを保存します。 + + + +### 引数の値を変数に保存する + + + + + -### Saving the Argument Values in Variables +引数のベクタの値を出力すると、プログラムはコマンドライン引数として指定された値にアクセスできることが具現化されました。 +さて、プログラムの残りを通して使用できるように、二つの引数の値を変数に保存する必要があります。 +それをしているのがリスト12-2です: -Printing the value of the vector of arguments illustrated that the program is -able to access the values specified as command line arguments. Now we need to -save the values of the two arguments in variables so we can use the values -throughout the rest of the program. We do that in Listing 12-2: + -Filename: src/main.rs +ファイル名: src/main.rs ```rust,should_panic use std::env; @@ -119,24 +186,36 @@ fn main() { let query = &args[1]; let filename = &args[2]; + // {}を探しています println!("Searching for {}", query); + // {}というファイルの中 println!("In file {}", filename); } ``` -Listing 12-2: Creating variables to hold the query -argument and filename argument + + -As we saw when we printed the vector, the program’s name takes up the first -value in the vector at `args[0]`, so we’re starting at index `1`. The first -argument `minigrep` takes is the string we’re searching for, so we put a -reference to the first argument in the variable `query`. The second argument -will be the filename, so we put a reference to the second argument in the -variable `filename`. +リスト12-2: クエリ引数とファイル名引数を保持する変数を生成 -We temporarily print the values of these variables to prove that the code is -working as we intend. Let’s run this program again with the arguments `test` -and `sample.txt`: + + + + + + + +ベクタを出力した時に確認したように、プログラム名がベクタの最初の値、`args[0]`を占めているので、 +添字`1`から始めます。`minigrep`が取る最初の引数は、検索する文字列なので、 +最初の引数への参照を変数`query`に置きました。2番目の引数はファイル名でしょうから、 +2番目の引数への参照は変数`filename`に置きました。 + + + + + +一時的にこれら変数の値を出力して、コードが意図通りに動いていることを証明しています。 +再度このプログラムを`test`と`sample.txt`という引数で実行しましょう: ```text $ cargo run test sample.txt @@ -147,8 +226,12 @@ Searching for test In file sample.txt ``` -Great, the program is working! The values of the arguments we need are being -saved into the right variables. Later we’ll add some error handling to deal -with certain potential erroneous situations, such as when the user provides no -arguments; for now, we’ll ignore that situation and work on adding file reading -capabilities instead. + + + + + + +素晴らしい、プログラムは動作しています!必要な引数の値が、正しい変数に保存されています。後ほど、 +何らかのエラー処理を加えて、特定の可能性のあるエラー状況に対処します。ユーザが引数を提供しなかった場合などです; +今は、そのような状況はないものとし、代わりにファイル読み取り機能を追加することに取り組みます。 From 691ffb40bda3a9ca5f1bb09674e94303842b83bf Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 6 Dec 2017 22:59:58 +0900 Subject: [PATCH 068/428] add a note on the chapter 8-2 --- second-edition/src/ch08-02-strings.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/second-edition/src/ch08-02-strings.md b/second-edition/src/ch08-02-strings.md index e6fb23d37..fa85f4357 100644 --- a/second-edition/src/ch08-02-strings.md +++ b/second-edition/src/ch08-02-strings.md @@ -260,6 +260,9 @@ s.push('l'); このコードの結果、`s`は`lol`を含むことになるでしょう。 +> 編者注: `lol`は`laughing out loud`(大笑いする)の頭文字からできたスラングです。 +> 日本語の`www`みたいなものですね。 + #### `+`演算子、または`format!`マクロで連結 From c3cee9614e46eadc31541cd164eba727a08aa5e9 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 7 Dec 2017 23:38:17 +0900 Subject: [PATCH 069/428] First draft of the chapters 12-2 and 12-3 (12-3 is not completed though) --- second-edition/src/SUMMARY.md | 2 +- second-edition/src/ch08-02-strings.md | 4 - second-edition/src/ch12-02-reading-a-file.md | 153 ++- ...improving-error-handling-and-modularity.md | 933 ++++++++++++------ 4 files changed, 716 insertions(+), 376 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index e7ea3bb91..97d68b7d7 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -116,7 +116,7 @@ - [入出力プロジェクト: コマンドラインプログラムを構築する](ch12-00-an-io-project.md) - [コマンドライン引数を受け付ける](ch12-01-accepting-command-line-arguments.md) - [ファイルを読み込む](ch12-02-reading-a-file.md) - - [リファクタリングでモジュール性の向上とエラー処理](ch12-03-improving-error-handling-and-modularity.md) + - [リファクタリングしてモジュール性の向上とエラー処理](ch12-03-improving-error-handling-and-modularity.md) - [テスト駆動開発でライブラリの機能を開発する](ch12-04-testing-the-librarys-functionality.md) - [環境変数を取り扱う](ch12-05-working-with-environment-variables.md) - [標準出力ではなく標準エラーにエラーメッセージを書き込む](ch12-06-writing-to-stderr-instead-of-stdout.md) diff --git a/second-edition/src/ch08-02-strings.md b/second-edition/src/ch08-02-strings.md index fa85f4357..965fb3acf 100644 --- a/second-edition/src/ch08-02-strings.md +++ b/second-edition/src/ch08-02-strings.md @@ -81,10 +81,6 @@ -Many of the same operations available with `Vec` are available with `String` -as well, starting with the `new` function to create a string, shown in Listing -8-11: - `Vec`で使用可能な処理の多くが`String`でも使用できます。文字列を生成する`new`関数から始めましょうか。 リスト8-11に示したようにね: diff --git a/second-edition/src/ch12-02-reading-a-file.md b/second-edition/src/ch12-02-reading-a-file.md index 671e0f9ed..020ad09c7 100644 --- a/second-edition/src/ch12-02-reading-a-file.md +++ b/second-edition/src/ch12-02-reading-a-file.md @@ -1,14 +1,24 @@ -## Reading a File + -Now we’ll add functionality to read the file that is specified in the -`filename` command line argument. First, we need a sample file to test it with: -the best kind of file to use to make sure `minigrep` is working is one with a -small amount of text over multiple lines with some repeated words. Listing 12-3 -has an Emily Dickinson poem that will work well! Create a file called -*poem.txt* at the root level of your project, and enter the poem “I’m Nobody! -Who are you?” +## ファイルを読み込む -Filename: poem.txt + + + + + + + + +では、`filename`コマンドライン引数で指定されたファイルを読み込む機能を追加しましょう。 +まず、テスト実行するためのサンプルファイルが必要ですね: `minigrep`が動作していることを確かめるために使用すべき好適なファイルは、 +複数行にわたって同じ単語の繰り返しのある少量のテキストです。リスト12-3は、 +うまくいくであろうエミリー・ディキンソン(Emily Dickinson)の詩です! +プロジェクトのルート階層に*poem.txt*というファイルを作成し、この詩「私は誰でもない!あなたは誰?」を入力してください。 + + + +ファイル名: poem.txt ```text I’m nobody! Who are you? @@ -20,15 +30,32 @@ How dreary to be somebody! How public, like a frog To tell your name the livelong day To an admiring bog! + +私は誰でもない!あなたは誰? +あなたも誰でもないの? +なら、私たちは組みだね、何も言わないで! +あの人たちは、私たちを追放するでしょう。わかりますよね? + +誰かでいるなんて侘しいじゃない! +カエルみたいで公すぎるじゃない。 +自分の名を長い1日に告げるのなんて。 +感服するような沼地にね! ``` -Listing 12-3: A poem by Emily Dickinson will make a good -test case. + + + +リスト12-3: エミリー・ディキンソンの詩は、いいテストケースになる + + + + +テキストを適当な場所に置いて、*src/main.rs*を編集し、ファイルを開くコードを追加してください。 +リスト12-4に示したようにね: -With the text in place, edit *src/main.rs* and add code to open the file, as -shown in Listing 12-4: + -Filename: src/main.rs +ファイル名: src/main.rs ```rust,should_panic use std::env; @@ -45,42 +72,65 @@ fn main() { // --snip-- println!("In file {}", filename); + // ファイルが見つかりませんでした let mut f = File::open(filename).expect("file not found"); let mut contents = String::new(); + // ファイルの読み込み中に問題がありました f.read_to_string(&mut contents) .expect("something went wrong reading the file"); + // テキストは\n{}です println!("With text:\n{}", contents); } ``` -Listing 12-4: Reading the contents of the file specified -by the second argument - -First, we add some more `use` statements to bring in relevant parts of the -standard library: we need `std::fs::File` to handle files, and -`std::io::prelude::*` contains various useful traits for doing I/O, including -file I/O. In the same way that Rust has a general prelude that brings certain -types and functions into scope automatically, the `std::io` module has its own -prelude of common types and functions you’ll need when working with I/O. Unlike -the default prelude, we must explicitly add a `use` statement for the prelude -from `std::io`. - -In `main`, we’ve added three statements: first, we get a mutable handle to the -file by calling the `File::open` function and passing it the value of the -`filename` variable. Second, we create a variable called `contents` and set it -to a mutable, empty `String`. This will hold the content of the file after we -read it in. Third, we call `read_to_string` on our file handle and pass a -mutable reference to `contents` as an argument. - -After those lines, we’ve again added a temporary `println!` statement that -prints the value of `contents` after the file is read, so we can check that the -program is working so far. - -Let’s run this code with any string as the first command line argument (because -we haven’t implemented the searching part yet) and the *poem.txt* file as the -second argument: + + + +リスト12-4: 第2引数で指定されたファイルの中身を読み込む + + + + + + + + + + +最初に、もう何個か`use`文を追記して、標準ライブラリの関係のある箇所を持ってきています: +ファイルを扱うのに`std::fs::File`が必要ですし、 +`std::io::prelude::*`はファイル入出力を含む入出力処理をするのに有用なトレイトを多く含んでいます。 +言語が一般的な初期化処理で特定の型や関数を自動的にスコープに導入するように、 +`std::io`モジュールにはそれ独自の共通の型や関数の初期化処理があり、入出力を行う際に必要になるわけです。 +標準の初期化処理とは異なり、`std::io`の初期化処理には明示的に`use`文を加えなければなりません。 + + + + + + + + +`main`で3文を追記しました: 一つ目が、`File::open`関数を呼んでファイルへの可変なハンドルを得て、 +`filename`変数の値に渡す処理です。二つ目が、`contents`という名の変数を生成して、 +可変で空の`String`を割り当てる処理です。この変数が、ファイル読み込み後に中身を保持します。 +三つ目が、ファイルハンドルに対して`read_to_string`を呼び出し、引数として`contents`への可変参照を渡す処理です。 + + + + + +それらの処理の後に、今回もファイル読み込み後に`contents`の値を出力する一時的な`println!`文を追記したので、 +ここまでプログラムがきちんと動作していることを確認できます。 + + + + + +第1コマンドライン引数には適当な文字列(まだ検索する箇所は実装してませんからね)を、第2引数に*poem.txt*ファイルを入れて、 +このコードを実行しましょう: ```text $ cargo run the poem.txt @@ -101,11 +151,18 @@ To tell your name the livelong day To an admiring bog! ``` -Great! The code read and then printed the content of the file. But the code has -a few flaws. The `main` function has multiple responsibilities: generally, -functions are clearer and easier to maintain if each function is responsible -for only one idea. The other problem is that we’re not handling errors as well -as we could be. The program is still small so these flaws aren’t a big problem, -but as the program grows, it will be harder to fix them cleanly. It’s good -practice to begin refactoring early on when developing a program, because it’s -much easier to refactor smaller amounts of code. We’ll do that next. + + + + + + + + + +素晴らしい!コードがファイルの中身を読み込み、出力するようになりました。しかし、このコードにはいくつか欠陥があります。 +`main`関数が複数の責任を受け持っています: 一般に、各関数がただ一つの責任だけを持つようになれば、 +関数は明確に管理しやすくなります。もう一つの問題点は、できうる限りのエラー処理を怠っていることです。 +まだプログラムが小規模なので、これらの欠陥は大きな問題にはなりませんが、プログラムが大規模になるにつれ、 +それを綺麗に解消するのは困難になっていきます。プログラムを開発する際に早い段階でリファクタングを行うのは、 +良い傾向です。リファクタリングするコードの量が少なければ、簡単になりますからね。次は、それを行いましょう。 diff --git a/second-edition/src/ch12-03-improving-error-handling-and-modularity.md b/second-edition/src/ch12-03-improving-error-handling-and-modularity.md index 0561c13d5..5ed0e0ea1 100644 --- a/second-edition/src/ch12-03-improving-error-handling-and-modularity.md +++ b/second-edition/src/ch12-03-improving-error-handling-and-modularity.md @@ -1,76 +1,138 @@ -## Refactoring to Improve Modularity and Error Handling - -To improve our program, we’ll fix four problems that have to do with the -program’s structure and how it’s handling potential errors. - -First, our `main` function now performs two tasks: it parses arguments and -opens files. For such a small function, this isn’t a major problem. However, if -we continue to grow our program inside `main`, the number of separate tasks the -`main` function handles will increase. As a function gains responsibilities, it -becomes more difficult to reason about, harder to test, and harder to change -without breaking one of its parts. It’s best to separate functionality so each -function is responsible for one task. - -This issue also ties into the second problem: although `query` and `filename` -are configuration variables to our program, variables like `f` and `contents` -are used to perform the program’s logic. The longer `main` becomes, the more -variables we’ll need to bring into scope; the more variables we have in scope, -the harder it will be to keep track of the purpose of each. It’s best to group -the configuration variables into one structure to make their purpose clear. - -The third problem is that we’ve used `expect` to print an error message when -opening the file fails, but the error message just prints `file not found`. -Opening a file can fail in a number of ways besides the file being missing: for -example, the file might exist, but we might not have permission to open it. -Right now, if we’re in that situation, we’d print the `file not found` error -message that would give the user the wrong information! - -Fourth, we use `expect` repeatedly to handle different errors, and if the user -runs our program without specifying enough arguments, they’ll get an `index out -of bounds` error from Rust that doesn’t clearly explain the problem. It would -be best if all the error handling code was in one place so future maintainers -have only one place to consult in the code if the error handling logic needs to -change. Having all the error handling code in one place will also ensure that -we’re printing messages that will be meaningful to our end users. - -Let’s address these four problems by refactoring our project. - -### Separation of Concerns for Binary Projects - -The organizational problem of allocating responsibility for multiple tasks to -the `main` function is common to many binary projects. As a result, the Rust -community has developed a type of guideline process for splitting the separate -concerns of a binary program when `main` starts getting large. The process has -the following steps: - -* Split your program into a *main.rs* and a *lib.rs*, and move your program’s -logic to *lib.rs*. -* While your command line parsing logic is small, it can remain in *main.rs*. -* When the command line parsing logic starts getting complicated, extract it -from *main.rs* and move it to *lib.rs*. -* The responsibilities that remain in the `main` function after this process -should be limited to: - - * Calling the command line parsing logic with the argument values - * Setting up any other configuration - * Calling a `run` function in *lib.rs* - * Handling the error if `run` returns an error - -This pattern is about separating concerns: *main.rs* handles running the -program, and *lib.rs* handles all the logic of the task at hand. Because we -can’t test the `main` function directly, this structure lets us test all of our -program’s logic by moving it into functions in *lib.rs*. The only code that -remains in *main.rs* will be small enough to verify its correctness by reading -it. Let’s rework our program by following this process. - -#### Extracting the Argument Parser - -We’ll extract the functionality for parsing arguments into a function that -`main` will call to prepare for moving the command line parsing logic to -*src/lib.rs*. Listing 12-5 shows the new start of `main` that calls a new -function `parse_config`, which we’ll define in *src/main.rs* for the moment. - -Filename: src/main.rs + + +## リファクタリングしてモジュール性の向上とエラー処理 + + + + +プログラムを改善するために、プログラムの構造と起こりうるエラーに対処する方法に関連する4つの問題を解消していきましょう。 + + + + + + + + + +1番目は、`main`関数が2つの仕事を受け持っていることです: 引数を解析し、ファイルを開いています。 +このような小さな関数なら、これは、大した問題ではありませんが、`main`内でプログラムを巨大化させ続けたら、 +`main`関数が扱う個別の仕事の数も増えていきます。関数が責任を受け持つごとに、 +内容が把握しにくくなり、テストも行いづらくなり、機能を壊さずに変更するのも困難になっていきます。 +機能を小分けして、各関数が1つの仕事のみに責任を持つようにするのが最善です。 + + + + + + + + +この問題は、2番目の問題にも紐付いています: `query`と`filename`はプログラムの設定用変数ですが、 +`f`や`contents`といった変数は、プログラムのロジックを担っています。`main`が長くなるほど、 +スコープに入れるべき変数も増えます; スコープにある変数が増えれば、各々の目的を追うのも大変になるわけです。 +設定用変数を一つの構造に押し込め、目的を明瞭化するのが最善です。 + + + + + + + + +3番目の問題は、ファイルを開き損ねた時に`expect`を使ってエラーメッセージを出力しているのに、 +エラーメッセージが`ファイルが見つかりませんでした`としか表示しないことです。 +ファイルを開く行為は、ファイルが存在しない以外にもいろんな方法で失敗することがあります: +例えば、ファイルは存在するかもしれないけれど、開く権限がないかもしれないなどです。 +現時点では、そのような状況になった時、 +「ファイルが見つかりませんでした」というユーザに間違った情報を与えるエラーメッセージを表示するわけです。 + + + + + + + + + + + +4番目は、異なるエラーを処理するのに`expect`を繰り返し使用しているので、ユーザが十分な数の引数を渡さずにプログラムを起動した時に、 +問題を明確に説明しない「範囲外アクセス(index out of bounds)」というエラーがRustから送られることです。 +エラー処理のコードが全て1箇所に存在し、将来エラー処理ロジックが変更になった時に、 +メンテナンス者が1箇所のコードのみを考慮すればいいようにするのが最善でしょう。 +エラー処理コードが1箇所にあれば、エンドユーザにとって意味のあるメッセージを出力していることを確認できることにもつながります。 + + + +プロジェクトをリファクタリングして、これら4つの問題を扱いましょう。 + + + +### バイナリプロジェクトで責任の分離 + + + + + + + +`main`関数に複数の仕事の責任を押し付けるという構造上の問題は、多くのバイナリプロジェクトでありふれています。 +結果として、`main`が肥大化し始めた際にバイナリプログラムの個別の責任を分割するためのある種のガイドライン工程をRustコミニュティは、 +開発しました。この工程は、以下のような手順になっています: + + + + + + + + + +* プログラムを*main.rs*と*lib.rs*に分け、ロジックを*lib.rs*に移動する。 +* コマンドライン引数の解析ロジックが小規模な間は、*main.rs*に置いても良い。 +* コマンドライン引数の解析ロジックが複雑化の様相を呈し始めたら、*main.rs*から抽出して*lib.rs*に移動する。 +* この工程の後に`main`関数に残る責任は以下に限定される: + + + + + + + * 引数の値でコマンドライン引数の解析ロジックを呼び出す + * 他のあらゆる設定を行う + * *lib.rs*の`run`関数を呼び出す + * `run`がエラーを返した時に処理する + + + + + + + + +このパターンは、責任の分離についてです: *main.rs*はプログラムの実行を行い、 +そして、*lib.rs*が手にある仕事のロジック全てを扱います。`main`関数を直接テストすることはできないので、 +この構造により、プログラムのロジック全てを*lib.rs*の関数に移すことでテストできるようになります。 +*main.rs*に残る唯一のコードは、読めばその正当性が評価できるだけ小規模になるでしょう。 +この工程に従って、プログラムのやり直しをしましょう。 + + + +#### 引数解析器を抽出する + + + + + + +引数解析の機能を`main`が呼び出す関数に抽出して、コマンドライン引数解析ロジックを*src/lib.rs*に移動する準備をしましょう。 +リスト12-5に新しい関数`parse_config`を呼び出す`main`の冒頭部を示し、 +この新しい関数は今だけ*src/main.rs*に定義します。 + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -89,48 +151,79 @@ fn parse_config(args: &[String]) -> (&str, &str) { } ``` -Listing 12-5: Extracting a `parse_config` function from -`main` - -We’re still collecting the command line arguments into a vector, but instead of -assigning the argument value at index `1` to the variable `query` and the -argument value at index `2` to the variable `filename` within the `main` -function, we pass the whole vector to the `parse_config` function. The -`parse_config` function then holds the logic that determines which argument -goes in which variable and passes the values back to `main`. We still create -the `query` and `filename` variables in `main`, but `main` no longer has the -responsibility of determining how the command line arguments and variables -correspond. - -This rework may seem like overkill for our small program, but we’re refactoring -in small, incremental steps. After making this change, run the program again to -verify that the argument parsing still works. It’s good to check your progress -often, because that will help you identify the cause of problems when they -occur. - -#### Grouping Configuration Values - -We can take another small step to improve the `parse_config` function further. -At the moment, we’re returning a tuple, but then we immediately break that -tuple into individual parts again. This is a sign that perhaps we don’t have -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 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. - -> Note: Some people call this anti-pattern of using primitive values when a -> complex type would be more appropriate *primitive obsession*. - -Listing12-6 shows the addition of a struct named `Config` defined to have -fields named `query` and `filename`. We’ve also changed the `parse_config` -function to return an instance of the `Config` struct and updated `main` to use -the struct fields rather than having separate variables: + + + +リスト12-5: `main`から`parse_config`関数を抽出する + + + + + + + + + + + +それでもまだ、コマンドライン引数をベクタ型に集結させていますが、`main`関数内で引数の値の添字`1`を変数`query`に、 +添字`2`を変数`filename`に代入する代わりに、ベクタ全体を`parse_config`関数に渡しています。 +そして、`parse_config`関数にはどの引数がどの変数に入り、それらの値を`main`に返すというロジックが存在します。 +まだ`main`内で`query`と`filename`という変数を生成していますが、もう`main`は、 +コマンドライン引数と変数がどう対応するかを決定する責任は持ちません。 + + + + + + + +このやり直しは、私たちの小規模なプログラムにはやりすぎに思えるかもしれませんが、 +少しずつ段階的にリファクタリングしているのです。この変更後、プログラムを再度実行して、 +引数解析がまだ動作していることを確かめてください。頻繁に進捗を確認するのはいいことです。 +問題が発生した時に原因を特定しやすくなりますからね。 + + + +#### 設定値をまとめる + + + + + + +もう少し`parse_config`関数を改善することができます。現時点では、タプルを返していますが、 +即座にタプルを分解して再度個別の値にしています。これは、正しい抽象化をまだできていないかもしれない兆候です。 + + + + + + + + + + +まだ改善の余地があると示してくれる他のものは、`parse_config`の`config`の部分であり、 +返却している二つの値は関係があり、一つの設定値の一部にどちらもなることを暗示しています。 +現状では、この意味を一つのタプルにまとめていること以外、データの構造に載せていません: +この二つの値を1構造体に置き換え、構造体のフィールドそれぞれに意味のある名前をつけることもできるでしょう。 +そうすることで将来このコードのメンテナンス者が、異なる値が相互に関係する仕方や、目的を理解しやすくできるでしょう。 + + + + +> 注釈: この複雑型(complex type)がより適切な時に組み込みの値を使うアンチパターンを、 +> *primitive obsession*(`脚注`: 初めて聞いた表現。*組み込み型強迫観念*といったところだろうか)と呼ぶ人もいます。 + + + + + + +リスト12-6は、`Config`という名前の構造体が`query`と`filename`というフィールドを持つよう定義された追加分を示しています。 +また、`parse_config`関数を`Config`構造体のインスタンを返すように変え、 +`main`も個別の変数ではなく構造体のフィールドを使うように更新しました。 Filename: src/main.rs @@ -164,67 +257,112 @@ fn parse_config(args: &[String]) -> Config { } ``` -Listing 12-6: Refactoring `parse_config` to return an -instance of a `Config` struct - -The signature of `parse_config` now indicates that it returns a `Config` value. -In the body of `parse_config`, where we used to return string slices that -reference `String` values in `args`, we now define `Config` to contain owned -`String` values. The `args` variable in `main` is the owner of the argument -values and is only letting the `parse_config` function borrow them, which means -we’d violate Rust’s borrowing rules if `Config` tried to take ownership of the -values in `args`. - -We could manage the `String` data in a number of different ways, but the -easiest, though somewhat inefficient, route is to call the `clone` method on -the values. This will make a full copy of the data for the `Config` instance to -own, which takes more time and memory than storing a reference to the string -data. However, cloning the data also makes our code very straightforward -because we don’t have to manage the lifetimes of the references; in this -circumstance, giving up a little performance to gain simplicity is a worthwhile -trade-off. - -> ### The Trade-Offs of Using `clone` + + + +リスト12-6: `parse_config`をリファクタリングして`Config`構造体のインスタンスを返すようにした + + + + + + + + + +`parse_config`のシグニチャは、これで`Config`値を返すと示すようになりました。`parse_config`の本体では、 +以前は`args`の`String`値を参照する文字列スライスを返していましたが、 +今では所有する`String`値を含むように`Config`を定義しています。`main`の`args`変数は引数値の所有者であり、 +`parse_config`関数だけに借用させていますが、これは`Config`が`args`の値の所有権を奪おうとしたら、 +Rustの借用規則に違反してしまうことを意味します。 + + + + + + + + + + +`String`のデータは、多くの異なる手法で管理できますが、最も単純だけれどもどこか非効率的な手段は、 +値に対して`clone`メソッドを呼び出すことです。これにより、`Config`インスタンスが所有するデータの総コピーが生成されるので、 +文字列データへの参照を保持するよりも時間とメモリを消費します。ですが、データをクローンすることで、 +コードがとても素直にもなります。というのも、参照のライフタイムを管理する必要がないからです。 +つまり、この場面において、少々のパフォーマンスを犠牲にして単純性を得るのは、価値のある交換です。 + + + + + + + + + + + + + +> ### `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 our 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 desirable solution, but for now, -> it’s perfectly acceptable to call `clone`. - -We’ve updated `main` so it places the instance of `Config` returned by -`parse_config` into a variable named `config`, and we updated the code that -previously used the separate `query` and `filename` variables so it now uses -the fields on the `Config` struct instead. - -Now our code more clearly conveys that `query` and `filename` are related, and -their purpose is to configure how the program will work. Any code that uses -these values knows to find them in the `config` instance in the fields named -for their purpose. - -#### Creating a Constructor for `Config` - -So far, we’ve extracted the logic responsible for parsing the command line -arguments from `main` and placed it in the `parse_config` function, which -helped us to see that the `query` and `filename` values were related and that -relationship should be conveyed in our code. We then added a `Config` struct to -name the related purpose of `query` and `filename`, and to be able to return -the values’ names as struct field names from the `parse_config` function. - -So now that the purpose of the `parse_config` function is to create a `Config` -instance, we can change `parse_config` from being a plain function to a -function named `new` that is associated with the `Config` struct. Making this -change will make the code more idiomatic: we can create instances of types in -the standard library, such as `String`, by calling `String::new`, and by -changing `parse_config` into a `new` function associated with `Config`, we’ll -be able to create instances of `Config` by calling `Config::new`. Listing 12-7 -shows the changes we need to make: - -Filename: src/main.rs +> 実行時コストのために`clone`を使用して所有権問題を解消するのを避ける傾向が多くのRustにあります。 +> 第13章で、この種の状況においてより効率的なメソッドの使用法を学ぶでしょう。ですがとりあえずは、 +> これらのコピーをするのは1回だけですし、ファイル名とクエリ文字列は非常に小さなものなので、 +> いくつかの文字列をコピーして進捗するのは良しとしましょう。最初の通り道でコードを究極的に効率化しようとするよりも、 +> ちょっと非効率的でも動くプログラムを用意する方がいいでしょう。もっとRustの経験を積めば、 +> 希望通りの解決法から開始することも簡単になるでしょうが、今は、`clone`を呼び出すのは完璧に受け入れられることです。 + + + + + + +`main`を更新したので、`parse_config`から返された`Config`のインスタンスを`config`という変数に置くようになり、 +以前は個別の`query`と`filename`変数を使用していたコードを更新したので、代わりに`Config`構造体のフィールドを使用するようになりました。 + + + + + + +これでコードは`query`と`filename`が関連しているとより明確に伝え、その目的はプログラムの振る舞い方を設定することになりました。 +これらの値を使用するあらゆるコードは、`config`インスタンスの目的の名前を冠したフィールドに発見することを把握しています。 + + + +#### `Config`のコンストラクタを作成する + + + + + + + + +ここまで、コマンドライン引数を解析するロジックを`main`から抽出し、`parse_config`関数に配置しました。 +これにより`query`と`filename`の値が関連し、その関係性がコードに載っていることを確認できました。 +それから`Config`構造体を追加して`query`と`filename`の関係する目的を名前付けし、 +構造体のフィールド名として`parse_config`関数からその値の名前を返すことができています。 + + + + + + + + + + +したがって、今や`parse_config`関数の目的は`Config`インスタンスを生成することになったので、 +`parse_config`をただの関数から`Config`構造体に紐付く`new`という関数に変えることができます。 +この変更を行うことで、コードがより慣用的になります: `String`などの標準ライブラリの型のインスタンスを、 +`String::new`を呼び出すことで生成できるように、`parse_config`を`Config`に紐付く`new`関数に変えれば、 +`Config::new`を呼び出すことで`Config`のインスタンスを生成できるようになります。リスト12-7が、 +行う必要のある変更を示しています: + + + +ファイル名: src/main.rs ```rust,should_panic # use std::env; @@ -254,20 +392,31 @@ impl Config { } ``` -Listing 12-7: Changing `parse_config` into -`Config::new` + + + +リスト12-7: `parse_config`を`Config::new`に変える + + + + + + +`parse_config`を呼び出していた`main`を代わりに`Config::new`を呼び出すように更新しました。 +`parse_config`の名前を`new`に変え、`impl`ブロックに入れ込んだので、`new`関数と`Config`が紐付くようになりました。 +再度このコードをコンパイルしてみて、動作することを確かめてください。 -We’ve updated `main` where we were calling `parse_config` to instead call -`Config::new`. We’ve changed the name of `parse_config` to `new` and moved it -within an `impl` block, which associates the `new` function with `Config`. Try -compiling this code again to make sure it works. + -### Fixing the Error Handling +### エラー処理を修正する -Now we’ll work on fixing our error handling. Recall that attempting to access -the values in the `args` vector at index `1` or index `2` will cause the -program to panic if the vector contains fewer than three items. Try running the -program without any arguments; it will look like this: + + + + + +さて、エラー処理の修正に取り掛かりましょう。ベクタが2個以下の要素しか含んでいないときに`args`ベクタの添字`1`か`2`にアクセスしようとすると、 +プログラムがパニックすることを思い出してください。試しに引数なしでプログラムを実行してください。すると、こんな感じになります: ```text $ cargo run @@ -276,44 +425,65 @@ $ cargo run Running `target/debug/minigrep` thread 'main' panicked at 'index out of bounds: the len is 1 but the index is 1', src/main.rs:29:21 +(スレッド'main'は、「境界外アクセス: 長さは1なのに添字は1です」でパニックしました) note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` -The line `index out of bounds: the len is 1 but the index is 1` is an error -message intended for programmers. It won’t help our end users understand what -happened and what they should do instead. Let’s fix that now. + + + -#### Improving the Error Message +`境界外アクセス: 長さは1なのに添字も1です`という行は、プログラマ向けのエラーメッセージです。 +エンドユーザが起きたことと代わりにすべきことを理解する手助けにはならないでしょう。これを今修正しましょう。 -In Listing 12-8, we add a check in the `new` function that will verify that the -slice is long enough before accessing index `1` and `2`. If the slice isn’t -long enough, the program panics and displays a better error message than the -`index out of bounds` message: + -Filename: src/main.rs +#### エラーメッセージを改善する + + + + + + +リスト12-8で、`new`関数に添字`1`と`2`にアクセスする前にスライスが十分長いことを確認するチェックを追加しています。 +スライスの長さが十分でなければ、プログラムはパニックし、`境界外アクセス`よりもいいエラーメッセージを表示します。 + + + +ファイル名: src/main.rs ```rust,ignore // --snip-- fn new(args: &[String]) -> Config { if args.len() < 3 { + // 引数の数が足りません panic!("not enough arguments"); } // --snip-- ``` -Listing 12-8: Adding a check for the number of -arguments + + -This code is similar to the `Guess::new` function we wrote in Listing 9-9 where -we called `panic!` when the `value` argument was out of the range of valid -values. Instead of checking for a range of values here, we’re checking that the -length of `args` is at least `3` and the rest of the function can operate under -the assumption that this condition has been met. If `args` has fewer than three -items, this condition will be true, and we call the `panic!` macro to end the -program immediately. +リスト12-8: 引数の数のチェックを追加する -With these extra few lines of code in `new`, let’s run the program without any -arguments again to see what the error looks like now: + + + + + + + + +このコードは、リスト9-9で記述した`value`引数が正常な値の範囲外だった時に`panic!`を呼び出した`Guess::new`関数と似ています。 +ここでは、値の範囲を確かめる代わりに、`args`の長さが少なくとも`3`であることを確かめていて、 +関数の残りの部分は、この条件が満たされているという前提のもとで処理を行うことができます。 +`args`に3要素以下しかなければ、この条件は真になり、`panic!`マクロを呼び出して、即座にプログラムを終了させます。 + + + + +では、`new`のこのおまけの数行がある状態で、再度引数なしでプログラムを走らせ、エラーがどんな見た目か確かめましょう: ```text $ cargo run @@ -321,32 +491,51 @@ $ cargo run 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. ``` -This output is better: we now have a reasonable error message. However, we also -have extraneous information we don’t want to give to our users. Perhaps using -the technique we used in Listing 9-9 isn’t the best to use here: a call to -`panic!` is more appropriate for a programming problem rather than a usage -problem, as discussed in Chapter 9. Instead, we can use the other technique you -learned about in Chapter 9—returning a `Result` that indicates either success -or an error. + + + + + + + -#### Returning a `Result` from `new` Instead of Calling `panic!` +この出力の方がマシです: これでエラーメッセージが合理的になりました。ですが、 +ユーザに与えたくない追加の情報も含まれてしまっています。おそらく、 +ここではリスト9-9で使用したテクニックを使用するのは最善ではありません: +`panic!`の呼び出しは、第9章で議論したように、使用の問題よりもプログラミング上の問題により適しています。 +代わりに、第9章で学んだ別のテクニックを使用することができます。成功か失敗かを示唆する`Result`を返すことです。 -We can instead return a `Result` value that will contain a `Config` instance in -the successful case and will describe the problem in the error case. When -`Config::new` is communicating to `main`, we can use the `Result` type to -signal there was a problem. Then we can change `main` to convert an `Err` -variant into a more practical error for our users without the surrounding text -about `thread 'main'` and `RUST_BACKTRACE` that a call to `panic!` causes. + -Listing 12-9 shows the changes we need to make to the return value of -`Config::new` and the body of the function needed to return a `Result`. Note -that this won’t compile until we update `main` as well, which we’ll do in the -next listing: +#### `panic!`を呼び出す代わりに`new`から`Result`を返す -Filename: src/main.rs + + + + + + + +代わりに、成功時には`Config`インスタンスを含み、エラー時には問題に言及する`Result`値を返すことができます。 +`Config::new`が`main`と対話する時、`Result`型を使用して問題があったとシグナルを送ることができます。 +それから`main`を変更して、`panic!`呼び出しが引き起こしていた`thread 'main'`と`RUST_BACKTRACE`に関する周囲のテキストがない、 +ユーザ向けのより実用的なエラーに`Err`バリアントを変換することができます。 + + + + + + +リスト12-9は、`Config::new`の戻り値に必要な変更と`Result`を返すのに必要な関数の本体を示しています。 +`main`も更新するまで、これはコンパイルできないことに注意してください。こちらは次のリストで行います: + + + +ファイル名: src/main.rs ```rust,ignore impl Config { @@ -363,33 +552,55 @@ impl Config { } ``` -Listing 12-9: Returning a `Result` from -`Config::new` + + -Our `new` function now returns a `Result` with a `Config` instance in the -success case and a `&'static str` in the error case. Recall from “The Static -Lifetime” section in Chapter 10 that `&'static str` is the type of string -literals, which is our error message type for now. +リスト12-9: `Config::new`から`Result`を返却する -We’ve made two changes in the body of the `new` function: instead of calling -`panic!` when the user doesn’t pass enough arguments, we now return an `Err` -value, and we’ve wrapped the `Config` return value in an `Ok`. These changes -make the function conform to its new type signature. + + + + -Returning an `Err` value from `Config::new` allows the `main` function to -handle the `Result` value returned from the `new` function and exit the process -more cleanly in the error case. +`new`関数は、今や、成功時には`Config`インスタンスを、エラー時には`&'static str`を伴う`Result`を返すようになりました。 +第10章の「静的ライフタイム」から`&'static str`は文字列リテラルの型であることを思い出してください。 +これは、今はエラーメッセージの型になっています。 -#### Calling `Config::new` and Handling Errors + + + + -To handle the error case and print a user-friendly message, we need to update -`main` to handle the `Result` being returned by `Config::new`, as shown in -Listing 12-10. We’ll also take the responsibility of exiting the command line -tool with a nonzero error code from `panic!` and implement it by hand. A -nonzero exit status is a convention to signal to the process that called our -program that the program exited with an error state. +`new`関数の本体で2つ変更を行いました: 十分な数の引数をユーザが渡さなかった場合に`panic!`を呼び出す代わりに、 +今は`Err`値を返し、`Config`戻り値を`Ok`に包んでいます。これらの変更により、関数が新しい型シグニチャに適合するわけです。 -Filename: src/main.rs + + + + +`Config::new`から`Err`値を返すことにより、`main`関数は、`new`関数から帰ってくる`Result`値を処理し、 +エラー時により明確にプロセスから抜け出すことができます。 + + + +#### `Config::new`を呼び出し、エラーを処理する + + + + + + + + +エラーケースを処理し、ユーザフレンドリーなメッセージを出力するために、`main`を更新して、 +リスト12-10に示したように`Config::new`から返される`Result`を処理する必要があります。 +また、`panic!`からコマンドラインツールを0以外のエラーコードで抜け出す責任も奪い取り、 +手作業でそれも実装します。0以外の終了コードは、 +我々のプログラムを呼び出したプロセスにプログラムがエラー状態で終了したことを通知する慣習です。 + + + +ファイル名: src/main.rs ```rust,ignore use std::process; @@ -398,6 +609,7 @@ fn main() { let args: Vec = env::args().collect(); let config = Config::new(&args).unwrap_or_else(|err| { + // 引数解析時に問題 println!("Problem parsing arguments: {}", err); process::exit(1); }); @@ -405,29 +617,46 @@ fn main() { // --snip-- ``` -Listing 12-10: Exiting with an error code if creating a -new `Config` fails - -In this listing, we’ve used a method we haven’t covered before: -`unwrap_or_else`, which is defined on `Result` by the standard library. -Using `unwrap_or_else` allows us to define some custom, non-`panic!` error -handling. If the `Result` is an `Ok` value, this method’s behavior is similar -to `unwrap`: it returns the inner value `Ok` is wrapping. However, if the value -is an `Err` value, this method calls the code in the *closure*, which is an -anonymous function we define and pass as an argument to `unwrap_or_else`. We’ll -cover closures in more detail in Chapter 13. For now, you just need to know -that `unwrap_or_else` will pass the inner value of the `Err`, which in this -case is the static string `not enough arguments` that we added in Listing 12-9, -to our closure in the argument `err` that appears between the vertical pipes. -The code in the closure can then use the `err` value when it runs. - -We’ve added a new `use` line to import `process` from the standard library. The -code in the closure that will be run in the error case is only two lines: we -print the `err` value and then call `process::exit`. The `process::exit` -function will stop the program immediately and return the number that was -passed as the exit status code. This is similar to the `panic!`-based handling -we used in Listing 12-8, but we no longer get all the extra output. Let’s try -it: + + + +リスト12-10: 新しい`Config`作成に失敗したら、エラーコードで終了する + + + + + + + + + + + + + + +このリストにおいて、以前には解説していないメソッドを使用しました: `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`の中身を、 +縦棒の間に出現する`err`引数のクロージャに渡していることだけ知っておく必要があります。 +クロージャのコードはそれから、実行された時に`err`値を使用できます。 + + + + + + + + + +新規`use`行を追加して標準ライブラリから`process`をインポートしました。クロージャ内のエラー時に走るコードは、 +たった2行です: `err`の値を出力し、それから`process:exit`を呼び出します。`process:exit`関数は、 +即座にプログラムを停止させ、渡された数字を終了コードとして返します。これは、リスト12-8で使用した`panic!`ベースの処理と似ていますが、 +もう余計な出力はされません。試しましょう: ```text $ cargo run @@ -437,23 +666,37 @@ $ cargo run Problem parsing arguments: not enough arguments ``` -Great! This output is much friendlier for our users. + -### Extracting Logic from `main` +素晴らしい!この出力の方が遥かにユーザに優しいです。 -Now that we’ve finished refactoring the configuration parsing, let’s turn to -the program’s logic. As we stated in “Separation of Concerns for Binary -Projects” on page XX, we’ll extract a function named `run` that will hold all -the logic currently in the `main` function that isn’t involved with setting up -configuration or handling errors. When we’re done, `main` will be concise and -easy to verify by inspection, and we’ll be able to write tests for all the -other logic. + -Listing 12-11 shows the extracted `run` function. For now, we’re just making -the small, incremental improvement of extracting the function. We’re still -defining the function in *src/main.rs*: +### `main`からロジックを抽出する -Filename: src/main.rs + + + + + + + + +ようやく設定解析のリファクタリングが終了したので、プログラムのロジックに目を向けましょう。 +ページXXの「バイナリプロジェクトの責任分離」で述べたように、 +現在`main`関数に存在する設定セットやエラー処理に関わらない全てのロジックを保持することになる`run`という関数を抽出します。 +やり終わったら、`main`は簡潔かつ視察で確かめやすくなり、他のロジック全部に対してテストを書くことができるでしょう。 + + + + + +リスト12-11は、抽出された`run`関数を示しています。今は少しずつ段階的に関数を抽出する改善を行っています。 +それでも、*src/main.rs*に関数を定義していきます: + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -478,24 +721,39 @@ fn run(config: Config) { // --snip-- ``` -Listing 12-11: Extracting a `run` function containing the -rest of the program logic + + -The `run` function now contains all the remaining logic from `main`, starting -from reading the file. The `run` function takes the `Config` instance as an -argument. +リスト12-11: 残りのプログラムロジックを含む`run`関数を抽出する -#### Returning Errors from the `run` Function + + + -With the remaining program logic separated into the `run` function, we can -improve the error handling, as we did with `Config::new` in Listing 12-9. -Instead of allowing the program to panic by calling `expect`, the `run` -function will return a `Result` when something goes wrong. This will let -us further consolidate into `main` the logic around handling errors in a -user-friendly way. Listing 12-12 shows the changes we need to make to the -signature and body of `run`: +これで`run`関数は、ファイル読み込みから始まる`main`関数の残りのロジック全てを含むようになりました。 +この`run`関数は、引数に`Config`インスタンスを取ります。 -Filename: src/main.rs + + +#### `run`関数からエラーを返す + + + + + + + + + +残りのプログラムロジックが`run`関数に隔離されたので、リスト12-9の`Config::new`のように、 +エラー処理を改善することができます。`expect`を呼び出してプログラムにパニックさせる代わりに、 +`run`関数は、何か問題が起きた時に`Result`を返します。これにより、 +さらにエラー処理周りのロジックをユーザに優しい形で`main`に統合することができます。 +リスト12-12にシグニチャと`run`本体に必要な変更を示しています: + + + +ファイル名: src/main.rs ```rust,ignore use std::error::Error; @@ -514,37 +772,59 @@ fn run(config: Config) -> Result<(), Box> { } ``` -Listing 12-12: Changing the `run` function to return -`Result` + + + +リスト12-12: `run`関数を変更して`Result`を返す + + + + + -We’ve made three significant changes here. First, we changed the return type of -the `run` function to `Result<(), Box>`. This function previously -returned the unit type, `()`, and we keep that as the value returned in the -`Ok` case. +ここでは、3つの大きな変更を行いました。まず、`run`関数の戻り値を`Result<(), Box>`に変えました。 +この関数は、前はユニット型、`()`を返していて、それを`Ok`の場合に返される値として残しました。 -For the error type, we used the *trait object* `Box` (and we’ve brought -`std::error::Error` into scope with a `use` statement at the top). We’ll cover -trait objects in Chapter 17. For now, just know that `Box` means the -function will return a type that implements the `Error` trait, but we don’t -have to specify what particular type the return value will be. This gives us -flexibility to return error values that may be of different types in different -error cases. + + + + + + + -Second, we’ve removed the calls to `expect` in favor of `?`, as we talked about -in Chapter 9. Rather than `panic!` on an error, `?` will return the error value -from the current function for the caller to handle. +エラー型については、*トレイトオブジェクト*の`Box`を使用しました(同時に冒頭で`use`文により、 +`std::error:Error`をスコープに導入しています)。トレイトオブジェクトについては、第17章で講義します。 +とりあえず、`Box`は、関数が`Error`トレイトを実装する型を返すことを意味しますが、 +戻り値の型を具体的に指定する必要はないことを知っておいてください。これにより、 +エラーケースによって異なる型のエラー値を返す柔軟性を得ます。 -Third, the `run` function now returns an `Ok` value in the success case. We’ve -declared the `run` function’s success type as `()` in the signature, which -means we need to wrap the unit type value in the `Ok` value. This `Ok(())` -syntax might look a bit strange at first, but using `()` like this is the -idiomatic way to indicate that we’re calling `run` for its side effects only; -it doesn’t return a value we need. + + + -When you run this code, it will compile but will display a warning: +2番目に、`expect`の呼び出しよりも`?`を選択して取り除きました。第9章で語りましたね。 +エラーでパニックするのではなく、`?`は呼び出し元が処理できるように、現在の関数からエラー値を返します。 + + + + + + + + +3番目に、`run`関数は今、成功時に`Ok`値を返すようになりました。`run`関数の成功型は、 +シグニチャで`()`と定義したので、ユニット型の値を`Ok`値に包む必要があります。 +最初は、この`Ok(())`という記法は奇妙に見えるかもしれませんが、このように`()`を使うことは、 +`run`を副作用のためだけに呼び出していると示唆する慣習的な方法です; 必要な値は返しません。 + + + +このコードを実行すると、コンパイルは通るものの、警告が表示されるでしょう: ```text warning: unused `std::result::Result` which must be used +(警告: 使用されるはずの`std::result::Result`が未使用です) --> src/main.rs:18:5 | 18 | run(config); @@ -552,10 +832,17 @@ warning: unused `std::result::Result` which must be used = note: #[warn(unused_must_use)] on by default ``` -Rust tells us that our code ignored the `Result` value, and the `Result` value -might indicate that an error occurred. But we’re not checking to see whether or -not there was an error, and the compiler reminds us that we probably meant to -have some error handling code here! Let’s rectify that problem now. + + + + + + + +コンパイラは、コードが`Result`値を無視していると教えてくれて、この`Result`値は、 +エラーが発生したと示唆しているかもしれません。しかし、エラーがあったか確認するつもりはありませんが、 +コンパイラは、ここにエラー処理コードを書くつもりだったんじゃないかと思い出させてくれています! +今、その問題を改修しましょう。 #### Handling Errors Returned from `run` in `main` From 16d0352fbf1d4f36871a33d71ac11ac1a18f14e4 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 8 Dec 2017 20:38:32 +0900 Subject: [PATCH 070/428] First draft of the chapter 12-3 --- ...improving-error-handling-and-modularity.md | 156 ++++++++++++------ 1 file changed, 105 insertions(+), 51 deletions(-) diff --git a/second-edition/src/ch12-03-improving-error-handling-and-modularity.md b/second-edition/src/ch12-03-improving-error-handling-and-modularity.md index 5ed0e0ea1..1749b928e 100644 --- a/second-edition/src/ch12-03-improving-error-handling-and-modularity.md +++ b/second-edition/src/ch12-03-improving-error-handling-and-modularity.md @@ -305,7 +305,7 @@ Rustの借用規則に違反してしまうことを意味します。 > ### `clone`を使用するトレードオフ > -> 実行時コストのために`clone`を使用して所有権問題を解消するのを避ける傾向が多くのRustにあります。 +> 実行時コストのために`clone`を使用して所有権問題を解消するのを避ける傾向が多くのRust市民にあります。 > 第13章で、この種の状況においてより効率的なメソッドの使用法を学ぶでしょう。ですがとりあえずは、 > これらのコピーをするのは1回だけですし、ファイル名とクエリ文字列は非常に小さなものなので、 > いくつかの文字列をコピーして進捗するのは良しとしましょう。最初の通り道でコードを究極的に効率化しようとするよりも、 @@ -326,7 +326,7 @@ Rustの借用規則に違反してしまうことを意味します。 これでコードは`query`と`filename`が関連しているとより明確に伝え、その目的はプログラムの振る舞い方を設定することになりました。 -これらの値を使用するあらゆるコードは、`config`インスタンスの目的の名前を冠したフィールドに発見することを把握しています。 +これらの値を使用するあらゆるコードは、`config`インスタンスの目的の名前を冠したフィールドにそれらを発見することを把握しています。 @@ -654,7 +654,7 @@ fn main() { 新規`use`行を追加して標準ライブラリから`process`をインポートしました。クロージャ内のエラー時に走るコードは、 -たった2行です: `err`の値を出力し、それから`process:exit`を呼び出します。`process:exit`関数は、 +たった2行です: `err`の値を出力し、それから`process::exit`を呼び出します。`process::exit`関数は、 即座にプログラムを停止させ、渡された数字を終了コードとして返します。これは、リスト12-8で使用した`panic!`ベースの処理と似ていますが、 もう余計な出力はされません。試しましょう: @@ -794,7 +794,7 @@ fn run(config: Config) -> Result<(), Box> { エラー型については、*トレイトオブジェクト*の`Box`を使用しました(同時に冒頭で`use`文により、 -`std::error:Error`をスコープに導入しています)。トレイトオブジェクトについては、第17章で講義します。 +`std::error::Error`をスコープに導入しています)。トレイトオブジェクトについては、第17章で講義します。 とりあえず、`Box`は、関数が`Error`トレイトを実装する型を返すことを意味しますが、 戻り値の型を具体的に指定する必要はないことを知っておいてください。これにより、 エラーケースによって異なる型のエラー値を返す柔軟性を得ます。 @@ -844,13 +844,20 @@ warning: unused `std::result::Result` which must be used コンパイラは、ここにエラー処理コードを書くつもりだったんじゃないかと思い出させてくれています! 今、その問題を改修しましょう。 -#### Handling Errors Returned from `run` in `main` + -We’ll check for errors and handle them using a technique similar to the way we -handled errors with `Config::new` in Listing 12-10, but with a slight -difference: +#### `main`で`run`から返ってきたエラーを処理する -Filename: src/main.rs + + + + +リスト12-10の`Config::new`に対してエラー処理を行った方法に似たテクニックを使用してエラーを確認し、扱いますが、 +少し違いがあります: + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -867,34 +874,57 @@ fn main() { } ``` -We use `if let` rather than `unwrap_or_else` to check whether `run` returns an -`Err` value and call `process::exit(1)` if it does. The `run` function doesn’t -return a value that we want to `unwrap` in the same way that `Config::new` -returns the `Config` instance. Because `run` returns a `()` in the success -case, we only care about detecting an error, so we don’t need `unwrap_or_else` -to return the unwrapped value because it would only be `()`. + + + + + + + +`unwrap_or_else`ではなく、`if let`で`run`が`Err`値を返したかどうかを確認し、そうなら`process::exit(1)`を呼び出しています。 +`run`関数は、`Config::new`が`Config`インスタンスを返すのと同じように`unwrap`したい値を返すことはありません。 +`run`は成功時に`()`を返すので、エラーを検知することにのみ興味があり、`()`でしかないので、 +`unwrap_or_else`に包まれた値を返してもらう必要はないのです。 + + + + +`if let`を`unwrap_or_else`関数の中身はどちらも同じです: エラーを出力して終了します。 + + + +### コードをライブラリクレートに分割する + + + + + +ここまで`minigrep`は良さそうですね!では、テストを行い、*src/main.rs*ファイルの責任が減らせるように、 +*src/main.rs*ファイルを分割し、一部のコードを*src/lib.rs*ファイルに置きましょう。 -The bodies of the `if let` and the `unwrap_or_else` functions are the same in -both cases: we print the error and exit. + + -### Splitting Code into a Library Crate +`main`関数以外のコード全部を*src/main.rs*から*src/lib.rs*に移動しましょう: -Our `minigrep` project is looking good so far! Now we’ll split the -*src/main.rs* file and put some code into the *src/lib.rs* file so we can test -it and have a *src/main.rs* file with fewer responsibilities. + + + + -Let’s move all the code that isn’t the `main` function from *src/main.rs* to -*src/lib.rs*: +* `run`関数定義 +* 関係する`use`文 +* `Config`の定義 +* `Config::new`関数定義 -* The `run` function definition -* The relevant `use` statements -* The definition of `Config` -* The `Config::new` function definition + + -The contents of *src/lib.rs* should have the signatures shown in Listing 12-13 -(we’ve omitted the bodies of the functions for brevity): +*src/lib.rs*の中身にはリスト12-13に示したようなシグニチャがあるはずです(関数の本体は簡潔性のために省略しました): -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust,ignore use std::error::Error; @@ -917,17 +947,27 @@ pub fn run(config: Config) -> Result<(), Box> { } ``` -Listing 12-13: Moving `Config` and `run` into -*src/lib.rs* + + -We’ve made liberal use of `pub` here: on `Config`, its fields and its `new` -method, and on the `run` function. We now have a library crate that has a -public API that we can test! +リスト12-13: `Config`と`run`を*src/lib.rs*に移動する -Now we need to bring the code we moved to *src/lib.rs* into the scope of the -binary crate in *src/main.rs*, as shown in Listing 12-14: + + + -Filename: src/main.rs +ここでは、寛大に`pub`を使用しています: `Config`のフィールドと`new`メソッドと、`run`関数です。 +これでテスト可能な公開APIのあるライブラリクレートができました! + + + + +さて、*src/lib.rs*に移動したコードを*src/main.rs*のバイナリクレートのスコープに持っていく必要があります。 +リスト12-14に示したようにね: + + + +ファイル名: src/main.rs ```rust,ignore extern crate minigrep; @@ -945,19 +985,33 @@ fn main() { } ``` -Listing 12-14: Bringing the `minigrep` crate into the -scope of *src/main.rs* + + + +リスト12-14: `minigrep`クレートを*src/main.rs*のスコープに持っていく + + + + + + + +ライブラリクレートをバイナリクレートに持っていくのに、`extern crate minigrep`を使用しています。 +それから`use minigrep::Config`行を追加して`Config`型をスコープに持っていき、 +`run`関数にクレート名をプレフィックスとして付けます。これで全機能が連結され、動くはずです。 +`cargo run`でプログラムを走らせて、すべてがうまくいっていることを確かめてください。 + + + + -To bring the library crate into the binary crate, we use `extern crate -minigrep`. Then we’ll add a `use minigrep::Config` line to bring the `Config` -type into scope, and we’ll prefix the `run` function with our crate name. Now -all the functionality should be connected and should work. Run the program with -`cargo run` and make sure everything works correctly. +ふう!作業量が多かったですね。ですが、将来成功する準備はできています。 +今では、エラー処理は遥かに楽になり、コードのモジュール化もできました。 +ここから先の作業は、ほぼ*src/lib.rs*で完結するでしょう。 -Whew! That was a lot of work, but we’ve set ourselves up for success in the -future. Now it’s much easier to handle errors, and we’ve made the code more -modular. Almost all of our work will be done in *src/lib.rs* from here on out. + + + -Let’s take advantage of this newfound modularity by doing something that would -have been difficult with the old code but is easy with the new code: we’ll -write some tests! +古いコードでは大変だけれども、新しいコードでは楽なことをして新発見のモジュール性を活用しましょう: +テストを書くのです! From cee51d42650a68d1c3b7299b345dc02963dc6fd4 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 9 Dec 2017 19:20:35 +0900 Subject: [PATCH 071/428] First draft of the chapter 12-4 --- ...2-04-testing-the-librarys-functionality.md | 438 ++++++++++++------ 1 file changed, 297 insertions(+), 141 deletions(-) diff --git a/second-edition/src/ch12-04-testing-the-librarys-functionality.md b/second-edition/src/ch12-04-testing-the-librarys-functionality.md index 4244f879c..0a1a31f47 100644 --- a/second-edition/src/ch12-04-testing-the-librarys-functionality.md +++ b/second-edition/src/ch12-04-testing-the-librarys-functionality.md @@ -1,43 +1,73 @@ -## Developing the Library’s Functionality with Test Driven Development - -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. - -In this section, we’ll add the searching logic to the `minigrep` program by -using the Test Driven Development (TDD) process. This software development -technique follows these steps: - -1. Write a test that fails, and run it to make sure it fails for the reason you - expected. -2. Write or modify just enough code to make the new test pass. -3. Refactor the code you just added or changed, and make sure the tests - continue to pass. -4. Repeat from step 1! - -This process is just one of many ways to write software, but TDD can help drive -code design as well. Writing the test before you write the code that makes the -test pass helps to maintain high test coverage throughout the process. - -We’ll test drive the implementation of the functionality that will actually do -the searching for the query string in the file contents and produce a list of -lines that match the query. We’ll add this functionality in a function called -`search`. - -### Writing a Failing Test - -Because we don’t need them anymore, let’s remove the `println!` statements from -*src/lib.rs* and *src/main.rs* that we used to check the program’s behavior. -Then, in *src/lib.rs*, we’ll add a `test` module with a test function, as we -did in Chapter 11. The test function specifies the behavior we want the -`search` function to have: it will take a query and the text to search for the -query in, and will return only the lines from the text that contain the query. -Listing 12-15 shows this test: - -Filename: src/lib.rs + + +## テスト駆動開発でライブラリの機能を開発する + + + + + + + + +今や、ロジックを*src/lib.rs*に抜き出し、引数集めとエラー処理を*src/main.rs*に残したので、 +コードの核となる機能のテストを書くのが非常に容易になりました。いろんな引数で関数を直接呼び出し、 +コマンドラインからバイナリを呼び出す必要なく戻り値を確認できます。ご自由に`Config::new`や`run`関数の機能のテストは、 +自身でお書きください。 + + + + + +この節では、テスト駆動開発(TDD)過程を使用して`minigrep`プログラムに検索ロジックを追加します。 +このソフトウェア開発テクニックは、以下の手順を追います: + + + + + + + + +1. 失敗するテストを書き、走らせて想定通りの理由で失敗することを確かめる。 +2. 十分な量のコードだけを書くか変更して新しいテストを通過するようにする。 +3. 追加または変更したばかりのコードをリファクタリングし、テストが通り続けることを確認する +4. 手順1から繰り返す! + + + + + +この過程は、ソフトウェアを書く多くの方法のうちの一つに過ぎませんが、TDDによりコードデザインも駆動することができます。 +テストを通過させるコードを書く前にテストを書くことで、過程を通して高いテストカバー率を保つ助けになります。 + + + + + + +実際にクエリ文字列の検索を行う機能の実装をテスト駆動し、クエリに合致する行のリストを生成します。 +この機能を`search`という関数に追加しましょう。 + + + +### 失敗するテストを記述する + + + + + + + + + +もう必要ないので、プログラムの振る舞いを確認していた`println!`文を*src/lib.rs*と*src/main.rs*から削除しましょう。 +それから*src/lib.rs*で、テスト関数のある`test`モジュールを追加します。第11章のようにね。 +このテスト関数が`search`関数に欲しい振る舞いを指定します: クエリとそれを検索するテキストを受け取り、 +クエリを含む行だけをテキストから返します。リスト12-15にこのテストを示しています: + + + +ファイル名: src/lib.rs ```rust # fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { @@ -51,6 +81,9 @@ mod test { #[test] fn one_result() { let query = "duct"; + // Rustは + // 安全で早く生産性も高い。 + // 3つ選んで。 let contents = "\ Rust: safe, fast, productive. @@ -64,21 +97,34 @@ Pick three."; } ``` -Listing 12-15: Creating a failing test for the `search` -function we wish we had + + + +リスト12-15: こうだったらいいなという`search`関数の失敗するテストを作成する + + + + -This test searches for the string “duct.” The text we’re searching is three -lines, only one of which contains “duct.” We assert that the value returned -from the `search` function contains only the line we expect. +このテストは、"duct."という文字列を検索します。検索対象の文字列は3行で、うち1行だけが"duct."を含みます。 +`search`関数から返る値が想定している行だけを含むことをアサーションします。 -We aren’t able to run this test and watch it fail because the test doesn’t even -compile: the `search` function doesn’t exist yet! So now we’ll add just enough -code to get the test to compile and run by adding a definition of the `search` -function that always returns an empty vector, as shown in Listing 12-16. Then -the test should compile and fail because an empty vector doesn’t match a vector -containing the line `"safe, fast, productive."`. + + + + + + -Filename: src/lib.rs +このテストを走らせ、失敗するところを観察することはできません。このテストはコンパイルできないからです: +まだ`search`関数が存在していません!ゆえに今度は、空のベクタを常に返す`search`関数の定義を追加することで、 +テストをコンパイルし走らせるだけのコードを追記します。リスト12-16に示したようにね。そうすれば、 +テストはコンパイルでき、失敗するはずです。なぜなら、空のベクタは、 +`"safe, fast, productive"`という行を含むベクタとは合致しないからです。 + + + +ファイル名: src/lib.rs ```rust pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { @@ -86,28 +132,44 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { } ``` -Listing 12-16: Defining just enough of the `search` -function so our test will compile + + + +リスト12-16: テストがコンパイルできるのに十分なだけ`search`関数を定義する -Notice that we need an explicit lifetime `'a` defined in the signature of -`search` and used with the `contents` argument and the return value. Recall in -Chapter 10 that the lifetime parameters specify which argument lifetime is -connected to the lifetime of the return value. In this case, we indicate that -the returned vector should contain string slices that reference slices of the -argument `contents` (rather than the argument `query`). + + + + + + -In other words, we tell Rust that the data returned by the `search` function -will live as long as the data passed into the `search` function in the -`contents` argument. This is important! The data referenced *by* a slice needs -to be valid for the reference to be valid; if the compiler assumes we’re making -string slices of `query` rather than `contents`, it will do its safety checking -incorrectly. +明示的なライフタイムの`'a`が`search`のシグニチャで定義され、`contents`引数と戻り値で使用されていることに注目してください。 +第10章からライフタイム仮引数は、どの実引数のライフタイムが戻り値のライフタイムに関連づけられているかを指定することを思い出してください。 +この場合、返却されるベクタは、 +(`query`引数よりも)`contents`引数のスライスを参照する文字列スライスを含むべきと示唆しています。 -If we forget the lifetime annotations and try to compile this function, we’ll -get this error: + + + + + + + +言い換えると、コンパイラに`search`関数に返されるデータは、 +`search`関数に`contents`引数で渡されているデータと同期間生きることを教えています。 +これは重要なことです!スライス*に*参照されるデータは、参照が有効になるために有効である必要があるのです; +コンパイラが`contents`ではなく`query`の文字列スライスを生成すると想定してしまったら、 +安全性チェックを間違って行うことになってしまいます。 + + + + +ライフタイム注釈を忘れてこの関数をコンパイルしようとすると、こんなエラーが出ます: ```text error[E0106]: missing lifetime specifier +(エラー: ライフタイム指定子が欠けています) --> src/lib.rs:5:51 | 5 | pub fn search(query: &str, contents: &str) -> Vec<&str> { @@ -116,19 +178,30 @@ 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`から借用されたものであるかが示されていません) ``` -Rust can’t possibly know which of the two arguments we need, so we need to tell -it. Because `contents` is the argument that contains all of our text and we -want to return the parts of that text that match, we know `contents` is the -argument that should be connected to the return value using the lifetime syntax. + + + + + +コンパイラには、二つの引数のどちらが必要なのか知る由がないので、教えてあげる必要があるのです。 +`contents`がテキストを全て含むテキストで、合致するそのテキストの一部を返したいので、 +`contents`がライフタイム記法で戻り値に関連づくはずの引数であることをプログラマは知っています。 -Other programming languages don’t require you to connect arguments to return -values in the signature, so although this might seem strange, it will get -easier over time. You might want to compare this example with “Validating -References with Lifetimes” in Chapter 10 on page XX. + + + + -Now let’s run the test: +他のプログラミング言語では、シグニチャで引数と戻り値を関連づける必要はないので、これは奇妙に思えるかもしれませんが、 +時間とともに楽になっていきます。この例を第10章、ページXXの「ライフタイムで参照を有効化する」と比較したくなるかもしれません。 + + + +さあ、テストを実行しましょう: ```text $ cargo test @@ -158,53 +231,91 @@ test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out error: test failed, to rerun pass '--lib' ``` -Great, the test fails, exactly as we expected. Let’s get the test to pass! + + +素晴らしい。テストは全く想定通りに失敗しています。テストが通るようにしましょう! -### Writing Code to Pass the Test + -Currently, our test is failing because we always return an empty vector. To fix -that and implement `search`, our program needs to follow these steps: +### テストを通過させるコードを書く -* Iterate through each line of the contents. -* Check whether the line contains our query string. -* If it does, add it to the list of values we’re returning. -* If it doesn’t, do nothing. -* Return the list of results that match. + + -Let’s work through each step, starting with iterating through lines. +空のベクタを常に返しているために、現状テストは失敗しています。それを解消し、`search`を実装するには、 +プログラムは以下の手順に従う必要があります: -#### Iterating Through Lines with the `lines` Method + + + + + -Rust has a helpful method to handle line-by-line iteration of strings, -conveniently named `lines`, that works as shown in Listing 12-17. Note this -won’t compile yet: +* 中身を各行ごとに見る。 +* 行にクエリ文字列が含まれるか確認する。 +* するなら、それを返却する値のリストに追加する。 +* しないなら、何もしない。 +* 合致する結果のリストを返す。 -Filename: src/lib.rs + + +各行を見る作業から、この手順に取り掛かりましょう。 + + + +#### `lines`メソッドで各行を見る + + + + + +Rustには、文字列を行ごとに繰り返す有用なメソッドがあり、利便性のために`lines`と名付けられ、 +リスト12-17のように動作します。まだこれはコンパイルできないことに注意してください: + + + +ファイル名: src/lib.rs ```rust,ignore pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { for line in contents.lines() { + // 行に対して何かする // do something with line } } ``` -Listing 12-17: Iterating through each line in `contents` - + + + +リスト12-17: `contents`の各行を繰り返す -The `lines` method returns an iterator. We’ll talk about iterators in depth in -Chapter 13, but recall that you saw this way of using an iterator in Listing -3-4, where we used a `for` loop with an iterator to run some code on each item -in a collection. + + + + -#### Searching Each Line for the Query +`lines`メソッドはイテレータを返します。イテレータについて詳しくは、第13章で話しますが、 +リスト3-4でこのようなイテレータの使用法は見かけたことを思い出してください。 +そこでは、イテレータに`for`ループを使用してコレクションの各要素に対して何らかのコードを走らせていました。 -Next, we’ll check whether the current line contains our query string. -Fortunately, strings have a helpful method named `contains` that does this for -us! Add a call to the `contains` method in the `search` function, as shown in -Listing 12-18. Note this still won’t compile yet: + -Filename: src/lib.rs +#### クエリを求めて各行を検索する + + + + + + +次に現在の行がクエリ文字列を含むか確認します。幸運なことに、 +文字列にはこれを行ってくれる`contains`という有用なメソッドがあります!`search`関数に、 +`contains`メソッドの呼び出しを追加してください。リスト12-18のようにね。 +これもまだコンパイルできないことに注意してください: + + + +ファイル名: src/lib.rs ```rust,ignore pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { @@ -216,17 +327,27 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { } ``` -Listing 12-18: Adding functionality to see whether the -line contains the string in `query` + + + +リスト12-18: 行が`query`の文字列を含むか確認する機能を追加する + + + +#### 合致した行を保存する -#### Storing Matching Lines + + + + -We also need a way to store the lines that contain our query string. For that, -we can make a mutable vector before the `for` loop and call the `push` method -to store a `line` in the vector. After the `for` loop, we return the vector, as -shown in Listing 12-19: +また、クエリ文字列を含む行を保存する方法が必要です。そのために、`for`ループの前に可変なベクタを生成し、 +`push`メソッドを呼び出して`line`をベクタに保存することができます。`for`ループの後でベクタを返却します。 +リスト12-19のようにね: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust,ignore pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { @@ -242,11 +363,16 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { } ``` -Listing 12-19: Storing the lines that match so we can -return them + + + +リスト12-19: 合致する行を保存したので、返すことができます -Now the `search` function should return only the lines that contain `query`, -and our test should pass. Let’s run the test: + + + +これで`search`関数は、`query`を含む行だけを返すはずであり、テストも通るはずです。 +テストを実行しましょう: ```text $ cargo test @@ -257,23 +383,37 @@ test test::one_result ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Our test passed, so we know it works! + + +テストが通りました。動いていることがわかりました! + + + + + + + + +ここで、テストが通過するよう保ったまま、同じ機能を保持しながら、検索関数の実装をリファクタリングする機会を考えることもできます。 +検索関数のコードは悪すぎるわけではありませんが、イテレータの有効な機能の一部を活用していません。 +この例には第13章で再度触れ、そこでは、イテレータをより深く探求し、改善する方法に目を向けます。 + + -At this point, we could consider opportunities for refactoring the -implementation of the search function while keeping the tests passing to -maintain the same functionality. The code in the search function isn’t too bad, -but it doesn’t take advantage of some useful features of iterators. We’ll -return to this example in Chapter 13 where we’ll explore iterators in detail -and look at how to improve it. +#### `run`関数内で`search`関数を使用する -#### Using the `search` Function in the `run` Function + + + + -Now that the `search` function is working and tested, we need to call `search` -from our `run` function. We need to pass the `config.query` value and the -`contents` that `run` reads from the file to the `search` function. Then `run` -will print each line returned from `search`: +`search`関数が動きテストできたので、`run`関数から`search`を呼び出す必要があります。`condif.query`の値と、 +ファイルから`run`が読み込む`contents`の値を`search`関数に渡す必要があります。 +それから`run`は、`search`から返ってきた各行を出力するでしょう: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust,ignore pub fn run(config: Config) -> Result<(), Box> { @@ -290,10 +430,15 @@ pub fn run(config: Config) -> Result<(), Box> { } ``` -We’re still using a `for` loop to return each line from `search` and print it. + + +それでも`for`ループで`search`から各行を返し、出力しています。 -Now the entire program should work! Let’s try it out, first with a word that -should return exactly one line from the Emily Dickinson poem, “frog”: + + + +さて、プログラム全体が動くはずです!試してみましょう。まずはエミリー・ディキンソンの詩から、 +ちょうど1行だけを返すはずの言葉から。"frog"です: ```text $ cargo run frog poem.txt @@ -303,7 +448,9 @@ $ cargo run frog poem.txt How public, like a frog ``` -Cool! Now let’s try a word that will match multiple lines, like “body”: + + +かっこいい!今度は、複数行にマッチするであろう言葉を試しましょう。"body"とかね: ```text $ cargo run body poem.txt @@ -314,8 +461,11 @@ Are you nobody, too? How dreary to be somebody! ``` -And finally, let’s make sure that we don’t get any lines when we search for a -word that isn’t anywhere in the poem, such as “monomorphization”: + + + +そして最後に、詩のどこにも表れない単語を探したときに、何も出力がないことを確かめましょう。 +"monomorphization"などね: ```text $ cargo run monomorphization poem.txt @@ -323,10 +473,16 @@ $ cargo run monomorphization poem.txt Running `target/debug/minigrep monomorphization poem.txt` ``` -Excellent! We’ve built our own mini version of a classic tool and learned a lot -about how to structure applications. We’ve also learned a bit about file input -and output, lifetimes, testing, and command line parsing. + + + + +最高です!古典的なツールの独自のミニバージョンを構築し、アプリケーションを構造化する方法を多く学びました。 +また、ファイル入出力、ライフタイム、テスト、コマンドライン引数の解析についても、少し学びました。 + + + + -To round out this project, we’ll briefly demonstrate how to work with -environment variables and how to print to standard error, both of which are -useful when you’re writing command line programs. +このプロジェクトをまとめ上げるために、環境変数を扱う方法と標準エラー出力に出力する方法を少しだけデモします。 +これらはどちらも、コマンドラインプログラムを書く際に有用です。 From da13463f03634d5b7932fad57e4f9feaeb47c44a Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 9 Dec 2017 22:58:02 +0900 Subject: [PATCH 072/428] First draft of the chapter 12-5 and fix an error in the chapter 12-4 --- ...2-04-testing-the-librarys-functionality.md | 2 +- ...2-05-working-with-environment-variables.md | 345 ++++++++++++------ 2 files changed, 229 insertions(+), 118 deletions(-) diff --git a/second-edition/src/ch12-04-testing-the-librarys-functionality.md b/second-edition/src/ch12-04-testing-the-librarys-functionality.md index 0a1a31f47..c24790a51 100644 --- a/second-edition/src/ch12-04-testing-the-librarys-functionality.md +++ b/second-edition/src/ch12-04-testing-the-librarys-functionality.md @@ -464,7 +464,7 @@ How dreary to be somebody! -そして最後に、詩のどこにも表れない単語を探したときに、何も出力がないことを確かめましょう。 +そして最後に、詩のどこにも現れない単語を探したときに、何も出力がないことを確かめましょう。 "monomorphization"などね: ```text diff --git a/second-edition/src/ch12-05-working-with-environment-variables.md b/second-edition/src/ch12-05-working-with-environment-variables.md index 41fd2ae19..7d5fa97f1 100644 --- a/second-edition/src/ch12-05-working-with-environment-variables.md +++ b/second-edition/src/ch12-05-working-with-environment-variables.md @@ -1,22 +1,38 @@ -## Working with Environment Variables + -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. +## 環境変数を取り扱う -### Writing a Failing Test for the Case-Insensitive `search` Function + + + + + + -We want to add a new `search_case_insensitive` function that we’ll call when -the environment variable is on. We’ll continue to follow the TDD process, so -the first step is again to write a failing test. We’ll add a new test for the -new `search``_case_insensitive` function and rename our old test from -`one_result` to `case_sensitive` to clarify the differences between the two -tests, as shown in Listing 12-20: +おまけの機能を追加して`minigrep`を改善します: 環境変数でユーザがオンにできる大文字小文字無視の検索用のオプションです。 +この機能をコマンドラインオプションにして、適用したい度にユーザが入力しなければならないようにすることもできますが、 +代わりに環境変数を使用します。そうすることでユーザは1回環境変数をセットすれば、そのターミナルセッションの間は、 +大文字小文字無視の検索を行うことができるようになるわけです。 -Filename: src/lib.rs + + +### 大文字小文字を区別しない`search`関数用に失敗するテストを書く + + + + + + + + +環境変数がオンの場合に呼び出す`search_case_insensitive`関数を新しく追加したいです。テスト駆動開発の過程に従い続けるので、 +最初の手順は、今回も失敗するテストを書くことです。新しい`search``_case_insensitive`関数用の新規テストを追加し、 +古いテストを`one_result`から`case_sensitive`に名前変更して、二つのテストの差異を明確化します。 +リスト12-20に示したようにね: + + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -55,33 +71,54 @@ Trust me."; } ``` -Listing 12-20: Adding a new failing test for the -case-insensitive function we’re about to add + + + +リスト12-20: 追加しようとしている大文字小文字を区別しない関数用の失敗するテストを新しく追加する + + + + + + + + +古いテストの`contents`も変更していることに注意してください。大文字小文字を区別する検索を行う際に、 +"duct"というクエリに合致しないはずの大文字Dを使用した`"Duct tape"`という新しい行を追加しました。 +このように古いテストを変更することで、すでに実装済みの大文字小文字を区別する検索機能を誤って壊してしまわないことを保証する助けになります。 +このテストはこれで通り、大文字小文字を区別しない検索に取り掛かっても通り続けるはずです。 -Note that we’ve edited the old test’s `contents` too. We’ve added a new line -with the text `“Duct tape”` using a capital D that shouldn’t match the query -“duct” when we’re searching in a case-sensitive manner. Changing the old test -in this way helps ensure that we don’t accidentally break the case-sensitive -search functionality that we’ve already implemented. This test should pass now -and should continue to pass as we work on the case-insensitive search. + + + + + + + + -The new test for the case-*insensitive* search uses “rUsT” as its query. In the -`search_case_insensitive` function we’re about to add, the query “rUsT” should -match the line containing “Rust:” with a capital R and also the line “Trust -me.” even though both have different casing than the query. This is our failing -test, and it will fail to compile because we haven’t yet defined the -`search_case_insensitive` function. Feel free to add a skeleton implementation -that always returns an empty vector, similar to the way we did for the `search` -function in Listing 12-16 to see the test compile and fail. +大文字小文字を区別*しない*検索の新しいテストは、クエリに"rUsT"を使用しています。 +追加直前の`search_case_insensitive`関数では、"rUsT"というクエリは、大文字Rの"Rust:"を含む行と、 +"Trust me."という行にもマッチするはずです。これが失敗するテストであり、まだ`search_case_insensitive`関数を定義していないので、 +コンパイルは失敗するでしょう。リスト12-16の`search`関数で行ったように空のベクタを常に返す実装の骨格を追加して、 +ご自由にテストがコンパイルされ、失敗する様を確認してください。 -### Implementing the `search_case_insensitive` Function + -The `search_case_insensitive` function, shown in Listing 12-21, will be almost -the same as the `search` function. The only difference is that we’ll lowercase -the `query` and each `line` so whatever the case of the input arguments, -they’ll be the same case when we check whether the line contains the query: +### `search_case_insensitive`関数を実装する -Filename: src/lib.rs + + + + + +`search_case_insensitive`関数は、リスト12-21に示しましたが、`search`関数とほぼ同じです。 +唯一の違いは、`query`と各`line`を小文字化していることなので、入力引数の大文字小文字によらず、 +行がクエリを含んでいるか確認する際には、同じになるわけです。 + + + +ファイル名: src/lib.rs ```rust fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { @@ -98,28 +135,45 @@ fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { } ``` -Listing 12-21: Defining the `search_case_insensitive` -function to lowercase the query and the line before comparing them + + + +リスト12-21: 比較する前にクエリと行を小文字化するよう、`search_case_insensitive`関数を定義する + + + + + + +まず、`query`文字列を小文字化し、同じ名前の上書きされた変数に保存します。ユーザのクエリが"rust"や"RUST"、 +"Rust"、"rUsT"などだったりしても、"rust"であり、大文字小文字を区別しないかのようにクエリを扱えるように、 +`to_lowercase`をクエリに対して呼び出すことは必須です。 + + + + + + + + -First, we lowercase the `query` string and store it in a shadowed variable with -the same name. Calling `to_lowercase` on the query is necessary so no matter -whether the user’s query is “rust”, “RUST”, “Rust”, or “rUsT”, we’ll treat the -query as if it was “rust” and be insensitive to the case. +`query`は最早、文字列スライスではなく`String`であることに注意してください。というのも、 +`to_lowercase`を呼び出すと、既存のデータを参照するというよりも、新しいデータを作成するからです。 +例として、クエリは"rUsT"としましょう: その文字列スライスは、小文字の"u"や"t"を使えるように含んでいないので、 +"rust"を含む新しい`String`のメモリを確保しなければならないのです。今、`contains`メソッドに引数として`query`を渡すと、 +アンド記号を追加する必要があります。`contains`のシグニチャは、文字列スライスを取るよう定義されているからです。 -Note that `query` is now a `String` rather than a string slice, because calling -`to_lowercase` creates new data rather than referencing existing data. Say the -query is “rUsT”, as an example: that string slice doesn’t contain a lowercase -“u” or “t” for us to use, so we have to allocate a new `String` containing -“rust”. When we pass `query` as an argument to the `contains` method now, we -need to add an ampersand because the signature of `contains` is defined to take -a string slice. + + + + -Next, we add a call to `to_lowercase` on each `line` before we check whether it -contains `query` to lowercase all characters. Now that we’ve converted `line` -and `query` to lowercase, we’ll find matches no matter what the case of the -query is. +次に、各`line`が`query`を含むか確かめる前に`to_lowercase`の呼び出しを追加し、全文字を小文字化しています。 +今や`line`と`query`を小文字に変換したので、クエリが大文字であろうと小文字であろうとマッチを検索するでしょう。 -Let’s see if this implementation passes the tests: + + +この実装がテストを通過するか確認しましょう: ```text running 2 tests @@ -129,13 +183,19 @@ test test::case_sensitive ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Great! They passed. Now, let’s call the new `search_case_insensitive` function -from the `run` function. First, we’ll add a configuration option to the -`Config` struct to switch between case-sensitive and case-insensitive search. -Adding this field will cause compiler errors since we aren’t initializing this -field anywhere yet: + + + + + + +素晴らしい!通りました。では、`run`関数から新しい`search_case_insensitive`関数を呼び出しましょう。 +1番目に大文字小文字の区別を切り替えられるよう、`Config`構造体に設定オプションを追加します。 +まだどこでも、このフィールドの初期化をしていないので、追加するとコンパイラエラーが起きます: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust pub struct Config { @@ -145,13 +205,19 @@ pub struct Config { } ``` -Note that we added the `case_sensitive` field that holds a Boolean. Next, we -need the `run` function to check the `case_sensitive` field’s value and use -that to decide whether to call the `search` function or the -`search_case_insensitive` function, as shown in Listing 12-22. Note this still -won’t compile yet: + + + + + + +論理値を持つ`case_sensitive`フィールドを追加したことに注意してください。次に、`run`関数に、 +`case_sensitive`フィールドの値を確認し、`search`関数か`search_case_insensitive`関数を呼ぶかを決定するのに使ってもらう必要があります。 +リスト12-22のようにね。それでも、これはまだコンパイルできないことに注意してください: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust # use std::error::Error; @@ -192,17 +258,26 @@ pub fn run(config: Config) -> Result<(), Box>{ } ``` -Listing 12-22: Calling either `search` or -`search_case_insensitive` based on the value in `config.case_sensitive` + + + +リスト12-22: `config.case_sensitive`の値に基づいて`search`か`search_case_insensitive`を呼び出す + + + + + + + + +最後に、環境変数を確認する必要があります。環境変数を扱う関数は、標準ライブラリの`env`モジュールにあるので、 +`use std::env;`行で*src/lib.rs*の冒頭でそのモジュールをスコープに持ってきたいです。そして、 +`env`モジュールから`var`メソッドを使用して`CASE_INSENSITIVE`という環境変数のチェックを行います。 +リスト12-23のようにね: -Finally, we need to check for the environment variable. The functions for -working with environment variables are in the `env` module in the standard -library, so we want to bring that module into scope with a `use std::env;` line -at the top of *src/lib.rs*. Then we’ll use the `var` method from the `env` -module to check for an environment variable named `CASE_INSENSITIVE`, as shown -in Listing 12-23: + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust use std::env; @@ -230,31 +305,49 @@ impl Config { } ``` -Listing 12-23: Checking for an environment variable named -`CASE_INSENSITIVE` + + -Here, we create a new variable `case_sensitive`. To set its value, we call the -`env::var` function and pass it the name of the `CASE_INSENSITIVE` environment -variable. The `env::var` method returns a `Result` that will be the successful -`Ok` variant that contains the value of the environment variable if the -environment variable is set. It will return the `Err` variant if the -environment variable is not set. +リスト12-23: `CASE_INSENSITIVE`という環境変数のチェックを行う -We’re using the `is_err` method on the `Result` to check whether it’s an error -and therefore unset, which means it *should* do a case-sensitive search. If the -`CASE_INSENSITIVE` environment variable is set to anything, `is_err` will -return false and will perform a case-insensitive search. We don’t care about -the *value* of the environment variable, just whether it’s set or unset, so -we’re checking `is_err` rather than `unwrap`, `expect`, or any of the other -methods we’ve seen on `Result`. + + + + + + -We pass the value in the `case_sensitive` variable to the `Config` instance so -the `run` function can read that value and decide whether to call `search` or -`search_case_insensitive` as we implemented in Listing 12-22. +ここで、`case_sensitive`という新しい変数を生成しています。その値をセットするために、 +`env::var`関数を呼び出し、`CASE_INSENSITIVE`環境変数の名前を渡しています。`env::var`メソッドは、 +環境変数がセットされていたら、環境変数の値を含む`Ok`バリアントの成功値になる`Result`を返します。 +環境変数がセットされていなければ、`Err`バリアントを返すでしょう。 -Let’s give it a try! First, we’ll run our program without the environment -variable set and with the query “to”, which should match any line that contains -the word “to” in all lowercase: + + + + + + + + +`Result`の`is_err`メソッドを使用して、エラーでありゆえに、セットされていないことを確認しています。 +これは大文字小文字を区別する検索をす*べき*ことを意味します。`CASE_INSENSITIVE`環境変数が何かにセットされていれば、 +`is_err`はfalseを返し、大文字小文字を区別しない検索を実行するでしょう。環境変数の値には興味がなく、 +セットされているかどうかだけ気にするので、`unwrap`や`expect`あるいは、他のここまで見かけた`Result`のメソッドはチェックしていません。 + + + + + +`case_sensitive`変数の値を`Config`インスタンスに渡しているので、リスト12-22で実装したように、 +`run`関数はその値を読み取り、`search`か`search_case_insensitive`を呼び出すか決定できるのです。 + + + + + +試行してみましょう!まず、環境変数をセットせずにクエリは、"to"でプログラムを実行し、 +この時は全て小文字で"to"という言葉を含むあらゆる行が合致するはずです。 ```text $ cargo run to poem.txt @@ -265,9 +358,12 @@ Are you nobody, too? How dreary to be somebody! ``` -Looks like that still works! Now, let’s run the program with `CASE_INSENSITIVE` -set to `1` but with the same query “to”; we should get lines that contain “to” -that might have uppercase letters: + + + + +まだそれは機能しているようです!では、`CASE_INSENSITIVE`を1にしつつ、同じクエリの"to"でプログラムを実行しましょう。 +つまり、大文字も含む"to"を含有する行が得られるはずです。 ```text $ CASE_INSENSITIVE=1 cargo run to poem.txt @@ -279,26 +375,41 @@ To tell your name the livelong day To an admiring bog! ``` -If you’re using PowerShell, you will need to set the environment variable and -run the program in two commands rather than one: + + + +PowerShellを使用していれば、1つではなく、2つのコマンドで環境変数をセットし、プログラムを走らせる必要があります: ```text $ $env.CASE_INSENSITIVE=1 $ cargo run to poem.txt ``` -Excellent, we also got lines containing “To”! Our `minigrep` program can now do -case-insensitive searching controlled by an environment variable. Now you know -how to manage options set using either command line arguments or environment -variables! - -Some programs allow arguments *and* environment variables for the same -configuration. In those cases, the programs decide that one or the other takes -precedence. For another exercise on your own, try controlling case -insensitivity through either a command line argument or an environment -variable. Decide whether the command line argument or the environment variable -should take precedence if the program is run with one set to case sensitive and -one set to case insensitive. - -The `std::env` module contains many more useful features for dealing with -environment variables: check out its documentation to see what is available. + + + + + +素晴らしい、"To"を含む行も出てきましたね!`minigrep`プログラムはこれで、 +環境変数によって制御できる大文字小文字を区別しない検索も行えるようになりました。コマンドライン引数か、 +環境変数を使ってオプションを管理する方法も知りましたね! + + + + + + + + + +引数*と*環境変数で同じ設定を行うことができるプログラムもあります。そのような場合、 +プログラムはどちらが優先されるか決定します。自身の別の練習として、コマンドライン引数か、 +環境変数で大文字小文字の区別を制御できるようにしてみてください。 +片方は大文字小文字を区別するようにセットされ、もう片方は区別しないようにセットしてプログラムが実行された時に、 +コマンドライン引数と環境変数のどちらの優先度が高くなるかを決めてください。 + + + + +`std::env`モジュールは、環境変数を扱うもっと多くの有用な機能を有しています: +ドキュメントを確認して、何が利用可能か確かめてください。 From aa3e99fb4295bdcc020b1b4a0151b4344020d77d Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 10 Dec 2017 17:05:31 +0900 Subject: [PATCH 073/428] First draft of the chapter 12-6 --- ...-06-writing-to-stderr-instead-of-stdout.md | 189 ++++++++++++------ 1 file changed, 127 insertions(+), 62 deletions(-) diff --git a/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md b/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md index 342d865bf..8763ca7ec 100644 --- a/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md +++ b/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md @@ -1,61 +1,102 @@ -## Writing Error Messages to Standard Error Instead of Standard Output + -At the moment we’re writing all of our output to the terminal using the -`println!` function. Most terminals provide two kinds of output: *standard -out**put* (`stdout`) for general information and *standard error* (`stderr`) -for error messages. This distinction enables users to choose to direct the -successful output of a program to a file but still print error messages to the -screen. +## 標準出力ではなく標準エラーにエラーメッセージを書き込む -The `println!` function is only capable of printing to standard output, so we -have to use something else to print to standard error. + + + + + + -### Checking Where Errors Are Written to +現時点では、すべての出力を`println!`関数を使用してターミナルに書き込んでいます。多くのターミナルは、 +2種類の出力を提供します: 普通の情報用の*標準**出力*(`stdout`)とエラーメッセージ用の*標準エラー出力*(`stderr`)です。 +この差異のおかげで、ユーザは、エラーメッセージを画面に表示しつつ、 +プログラムの成功した出力をファイルにリダイレクトすることを選択できます。 -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. + + -Command line programs are expected to send error messages to the standard error -stream so we can still see error messages on the screen even if we redirect the -standard output stream to a file. Our program is not currently well-behaved: -we’re about to see that it saves the error message output to a file instead! +`println!`関数は、標準出力に出力する能力しかないので、標準エラーに出力するには他のものを使用しなければなりません。 -The way to demonstrate this behavior is by running the program with `>` and the -filename, *output.txt*, that we want to redirect the standard output stream to. -We won’t pass any arguments, which should cause an error: + + +### エラーが書き込まれる場所を確認する + + + + + + + + +まず、`minigrep`に出力される中身が、代わりに標準エラーに書き込みたいいかなるエラーメッセージも含め、 +どのように標準出力に書き込まれているかを観察しましょう。意図的にエラーを起こしつつ、 +ファイルに標準出力ストリームをリダイレクトすることでそうします。標準エラーストリームはリダイレクトしないので、 +標準エラーに送られる内容は、すべて画面に表示され続けます。 + + + + + + +コマンドラインプログラムは、エラーメッセージを標準出力に送信していると期待されているので、 +標準出力ストリームをファイルにリダイレクトしても、画面にエラーメッセージが見られます。 +我々のプログラムは、現状、いい振る舞いをしていません: 代わりにファイルにエラーメッセージ出力を保存するところを、 +目撃するところです! + + + + + +この動作をデモする方法は、`>`と標準出力ストリームをリダイレクトする先のファイル名、*output.txt*でプログラムを走らせることによります。 +引数は何も渡しませんが、そうするとエラーが起きるはずです: ```text $ cargo run > output.txt ``` -The `>` syntax tells the shell to write the contents of standard output to -*output.txt* instead of the screen. We didn’t see the error message we were -expecting printed on the screen, so that means it must have ended up in the -file. This is what *output.txt* contains: + + + + + +`>`記法により、標準出力の中身を画面の代わりに*output.txt*に書き込むようシェルは指示されます。 +画面に出力されると期待していたエラーメッセージは見られないので、ファイルに入っているということでしょう。 +以下が*output.txt*が含んでいる内容です: ```text Problem parsing arguments: not enough arguments ``` -Yup, our error message is being printed to standard output. It’s much more -useful for error messages like this to be printed to standard error and have -only data from a successful run end up in the file when we redirect standard -output this way. We’ll change that. + + + + + +そうです。エラーメッセージは標準出力に出力されているのです。このように標準出力をリダイレクトしたら、 +このようなエラーメッセージは標準エラーに出力され、成功した状態のデータのみがファイルに残ると遥かに有用です。 +それを変更します。 + + + +### エラーを標準エラーに出力する -### Printing Errors to Standard Error + + + + + + -We’ll use the code in Listing 12-24 to change how error messages are printed. -Because of the refactoring we did earlier in this chapter, all the code that -prints error messages is in one function, `main`. The standard library provides -the `eprintln!` macro that prints to the standard error stream, so let’s change -the two places we were calling `println!` to print errors to use `eprintln!` -instead: +リスト12-24のコードを使用して、エラーメッセージの出力の仕方を変更します。この章の前で行ったリファクタリングのため、 +エラーメッセージを出力するコードはすべて1関数、`main`にあります。標準ライブラリは、 +標準エラーストリームに出力する`eprintln!`マクロを提供しているので、 +`println!`を呼び出してエラーを出力していた2箇所を代わりに`eprintln!`を使うように変更しましょう: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -74,50 +115,74 @@ fn main() { } ``` -Listing 12-24: Writing error messages to standard error -instead of standard output using `eprintln!` + + + +リスト12-24: `eprintln!`を使って標準出力ではなく、標準エラーにエラーメッセージを書き込む + + + -After changing `println!` to `eprintln!`, let’s run the program again in the -same way, without any arguments and redirecting standard output with `>`: +`println!`を`eprintln!`に変えてから、再度同じようにプログラムを実行しましょう。 +引数なしかつ、標準出力を`>`でリダイレクトしてね: ```text $ cargo run > output.txt Problem parsing arguments: not enough arguments ``` -Now we see the error onscreen and *output.txt* contains nothing, which is the -behavior we expect of command line programs. + + + +これで、エラーは画面に見えつつ、*output.txt*は何も含まなくなり、これはコマンドラインプログラムに期待する動作です。 + + + -Let’s run the program again with arguments that don’t cause an error but still -redirect standard output to a file, like so: +再度、エラーは起こさずに標準出力をファイルにリダイレクトする引数でプログラムを走らせましょう。以下のようにね: ```text $ cargo run to poem.txt > output.txt ``` -We won’t see any output to the terminal, and *output.txt* will contain our -results: + + -Filename: output.txt +ターミナルには出力は見られず、*output.txt*に結果が含まれます: + + + +ファイル名: output.txt ```text Are you nobody, too? How dreary to be somebody! ``` -This demonstrates that we’re now using standard output for successful output -and standard error for error output as appropriate. + + + +これは、今や成功した出力には標準出力を、エラー出力には標準エラーを適切に使用していることをデモしています。 + + + +## まとめ -## Summary + + + + + + + -In this chapter, we’ve recapped some of the major concepts you’ve learned so -far and covered how to do common I/O operations in a Rust context. By using -command line arguments, files, environment variables, and the `eprintln!` macro -for printing errors, you’re now prepared to write command line applications. By -using the concepts in previous chapters, your code will be well organized, -store data effectively in the appropriate data structures, handle errors -nicely, and be well tested. +この章では、ここまでに学んできた主要な概念の一部を想起させ、Rustの文脈で入出力処理を行う方法を講義しました。 +コマンドライン引数、ファイル、環境変数、そしてエラー出力に`eprintln!`マクロを使用することで、 +今は、コマンドラインアプリケーションを書く準備ができています。以前の章の概念を使用することで、 +コードはうまく体系化され、適切なデータ構造に効率的にデータを保存し、エラーをうまく扱い、 +よくテストされるでしょう。 -Next, we’ll explore some Rust features that were influenced by functional -languages: closures and iterators. + + +次に、関数型言語に影響されたRust機能の一部を探求します: クロージャとイテレータです。 From afea29c5d52baa9ba93bec813c9f0d48c6c98b5d Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 10 Dec 2017 17:56:11 +0900 Subject: [PATCH 074/428] First draft of the chapter 13-0 --- second-edition/src/SUMMARY.md | 28 +++++--- .../src/ch13-00-functional-features.md | 65 ++++++++++++------- 2 files changed, 62 insertions(+), 31 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index 7dd9e85ac..c73f4c46e 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -58,7 +58,9 @@ - [`match`制御フロー演算子](ch06-02-match.md) - [`if let`で簡潔な制御フロー](ch06-03-if-let.md) -## Basic Rust Literacy + + +## 基本的なRustリテラシー @@ -121,13 +123,21 @@ - [環境変数を取り扱う](ch12-05-working-with-environment-variables.md) - [標準出力ではなく標準エラーにエラーメッセージを書き込む](ch12-06-writing-to-stderr-instead-of-stdout.md) -## Thinking in Rust + + +## Rustで思考する -- [Functional Language Features: Iterators and Closures](ch13-00-functional-features.md) - - [Closures: Anonymous Functions that Can Capture Their Environment](ch13-01-closures.md) - - [Processing a Series of Items with Iterators](ch13-02-iterators.md) - - [Improving Our I/O Project](ch13-03-improving-our-io-project.md) - - [Comparing Performance: Loops vs. Iterators](ch13-04-performance.md) + + + + + + +- [関数型言語の機能: イテレータとクロージャ](ch13-00-functional-features.md) + - [クロージャ: 環境をキャプチャできる匿名関数](ch13-01-closures.md) + - [一連の要素をイテレータで処理する](ch13-02-iterators.md) + - [入出力プロジェクトを改善する](ch13-03-improving-our-io-project.md) + - [パフォーマンス比較: ループVSイテレータ](ch13-04-performance.md) - [More about Cargo and Crates.io](ch14-00-more-about-cargo.md) - [Customizing Builds with Release Profiles](ch14-01-release-profiles.md) @@ -155,7 +165,9 @@ - [Trait Objects for Using Values of Different Types](ch17-02-trait-objects.md) - [Object-Oriented Design Pattern Implementations](ch17-03-oo-design-patterns.md) -## Advanced Topics + + +## 高度なトピック - [Patterns Match the Structure of Values](ch18-00-patterns.md) - [All the Places Patterns May be Used](ch18-01-all-the-places-for-patterns.md) diff --git a/second-edition/src/ch13-00-functional-features.md b/second-edition/src/ch13-00-functional-features.md index 50eab0940..251ae9808 100644 --- a/second-edition/src/ch13-00-functional-features.md +++ b/second-edition/src/ch13-00-functional-features.md @@ -1,23 +1,42 @@ -# Functional Language Features: Iterators and Closures - -Rust’s design has taken inspiration from many existing languages and -techniques, and one significant influence is *functional programming*. -Programming in a functional style often includes using functions as values by -passing them in arguments, returning them from other functions, assigning them -to variables for later execution, and so forth. In this chapter, we won’t -debate the issue of what functional programming is or isn’t but will instead -discuss some features of Rust that are similar to features in many languages -often referred to as functional. - -More specifically, we’ll cover: - -* *Closures*, a function-like construct you can store in a variable -* *Iterators*, a way of processing a series of elements -* How to use these two features to improve the I/O project in Chapter 12 -* The performance of these two features (Spoiler alert: they’re faster than you - might think!) - -Other Rust features are influenced by the functional style as well, such as -pattern matching and enums, which we’ve covered in other chapters. Mastering -closures and iterators is an important part of writing idiomatic, fast Rust -code, so we’ll devote this entire chapter to them. + + +# 関数型言語の機能: イテレータとクロージャ + + + + + + + + + + +Rustの設計は、多くの既存の言語やテクニックにインスピレーションを得ていて、 +その一つの大きな影響が*関数型プログラミング*です。関数型でのプログラミングには、しばしば、 +引数で渡すことで関数を値として使用したり、関数から関数を返したり、関数を後ほど使用するために変数に代入することなどが含まれます。 +この章では、関数型プログラミングがどんなものであるかという問題については議論しませんが、 +代わりに関数型とよく言及される多くの言語の機能に似たRustの機能の一部について議論しましょう。 + + + +具体的には、以下を講義します: + + + + + + + +* *クロージャ*、変数に保存できる関数に似た文法要素 +* *イテレータ*、一連の要素を処理する方法 +* これら2つの機能を使用して第12章の入出力プロジェクトを改善する方法 +* これら2つの機能のパフォーマンス(ネタバレ: 思ったよりも速いです) + + + + + + +パターンマッチングやenumなど、他のRustの機能も関数型に影響されていますが、他の章で講義します。 +クロージャとイテレータをマスターすることは、慣用的で速いRustコードを書く重要な部分なので、 +この章を丸ごと捧げます。 From 5f467d7289739247af72f17c9accee5e1be622cb Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 11 Dec 2017 20:28:36 +0900 Subject: [PATCH 075/428] First drafts of the chapters 13-1 and 13-2 --- second-edition/src/ch13-01-closures.md | 1106 +++++++++++++++-------- second-edition/src/ch13-02-iterators.md | 632 ++++++++----- 2 files changed, 1158 insertions(+), 580 deletions(-) diff --git a/second-edition/src/ch13-01-closures.md b/second-edition/src/ch13-01-closures.md index 10edac330..a7d931a5c 100644 --- a/second-edition/src/ch13-01-closures.md +++ b/second-edition/src/ch13-01-closures.md @@ -1,65 +1,106 @@ -## Closures: Anonymous Functions that Can Capture Their Environment + -Rust’s *closures* are anonymous functions you can save in a variable or pass as -arguments to other functions. You can create the closure in one place, and then -call the closure to evaluate it in a different context. Unlike functions, -closures can capture values from the scope in which they’re called. We’ll -demonstrate how these closure features allow for code reuse and behavior -customization. +## クロージャ: 環境をキャプチャできる匿名関数 -### Creating an Abstraction of Behavior with Closures + + + + + + -Let’s work on an example of a situation in which it’s useful to store a closure -to be executed at a later time. Along the way, we’ll talk about the syntax of -closures, type inference, and traits. +Rustの*クロージャ*は、変数に保存したり、引数として他の関数に渡すことのできる匿名関数です。 +ある場所でクロージャを生成し、それから別の文脈でクロージャを呼び出して評価することができます。 +関数と異なり、呼び出されたスコープの値をクロージャは、キャプチャすることができます。 +これらのクロージャの機能がコードの再利用や、動作のカスタマイズを行わせてくれる方法を模擬しましょう。 -Consider this hypothetical situation: we work at a startup that’s making an app -to generate custom exercise workout plans. The backend is written in Rust, and -the algorithm that generates the workout plan takes into account many different -factors, such as the app user’s age, body mass index, preferences, recent -workouts, and an intensity number they specify. The actual algorithm used isn’t -important in this example; what’s important is that this calculation takes a -few seconds. We want to call this algorithm only when we need to and only call -it once, so we don’t make the user wait more than necessary. + -We’ll simulate calling this hypothetical algorithm with the -`simulated_expensive_calculation` function shown in Listing 13-1, which will -print `calculating slowly...`, wait for two seconds, and then return whatever -number we passed in: +### クロージャで動作の抽象化を生成する -Filename: src/main.rs + + + + +クロージャを保存して後々使用できるようにするのが有効な場面の例に取り掛かりましょう。その過程で、 +クロージャの記法、型推論、トレイトについて語ります。 + + + + + + + + + + +以下のような架空の場面を考えてください: カスタマイズされたエクササイズのトレーニングプランを生成するアプリを作る立ち上げにかかることになりました。 +バックエンドは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 } ``` -Listing 13-1: A function to stand in for a hypothetical -calculation that takes about two seconds to run + + + +リスト13-1: 実行に約2秒かかる架空の計算の代役を務める関数 -Next is the `main` function that contains the parts of the workout app -important for this example. This function represents the code that the app will -call when a user asks for a workout plan. Because the interaction with the -app’s frontend isn’t relevant to the use of closures, we’ll hardcode values -representing inputs to our program and print the outputs. + + + + + -The required inputs are: +次は、この例で重要なトレーニングアプリの部分を含む`main`関数です。この関数は、 +ユーザがトレーニングプランを要求した時にアプリが呼び出すコードを表します。 +アプリのフロントエンドと相互作用する部分は、クロージャの使用と関係ないので、プログラムへの入力を表す値をハードコードし、 +その出力を出力します。 -* *An intensity number from the user*, which is specified when they request - a workout to indicate whether they want a low-intensity workout or a - high-intensity workout. -* *A random number* that will generate some variety in the workout plans. + -The output will be the recommended workout plan. Listing 13-2 shows the `main` -function we’ll use: +必要な入力は: -Filename: src/main.rs + + + + + +* *ユーザの強弱値*、これはユーザがトレーニングを要求して、低強度のトレーニングか、 +高強度のトレーニングがしたいかを示します。 +* *乱数*、これはトレーニングプランにバリエーションを起こします。 + + + + +出力は、推奨されるトレーニングプランになります。リスト13-2は使用する`main`関数を示しています: + + + +ファイル名: src/main.rs ```rust fn main() { @@ -74,22 +115,34 @@ fn main() { # fn generate_workout(intensity: u32, random_number: u32) {} ``` -Listing 13-2: A `main` function with hardcoded values to -simulate user input and random number generation + + + +リスト13-2: ユーザ入力や乱数生成をシミュレートするハードコードされた値がある`main`関数 + + + + + + + + +簡潔性のために、変数`simulated_user_specified_value`は10に、変数`simulated_random_number`は7にハードコードしました; +実際のプログラムにおいては、強弱値はアプリのフロントエンドから取得し、乱数の生成には、`rand`クレートを使用します。 +第2章の数当てゲームの例みたいにね。`main`関数は、シミュレートされた入力値とともに`generate_workout`関数を呼び出します。 -We’ve hardcoded the variable `simulated_user_specified_value` to 10 and the -variable `simulated_random_number` to 7 for simplicity’s sake; in an actual -program, we’d get the intensity number from the app frontend and we’d use the -`rand` crate to generate a random number, as we did in the Guessing Game -example in Chapter 2. The `main` function calls a `generate_workout` function -with the simulated input values. + + + + -Now that we have the context, let’s get to the algorithm. The -`generate_workout` function in Listing 13-3 contains the business logic of the -app that we’re most concerned with in this example. The rest of the code -changes in this example will be made to this function: +今や文脈ができたので、アルゴリズムに取り掛かりましょう。リスト13-3の`generate_workout`関数は、 +この例で最も気にかかるアプリのビジネスロジックを含んでいます。この例での残りの変更は、 +この関数に対して行われるでしょう: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust # use std::thread; @@ -103,18 +156,22 @@ changes in this example will be made to this function: # 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) @@ -124,44 +181,73 @@ fn generate_workout(intensity: u32, random_number: u32) { } ``` -Listing 13-3: The business logic that prints the workout -plans based on the inputs and calls to the `simulated_expensive_calculation` -function + + + + +リスト13-3: 入力に基づいてトレーニングプランを出力するビジネスロジックと、 +`simulated_expensive_calculation`関数の呼び出し -The code in Listing 13-3 has multiple calls to the slow calculation function. -The first `if` block calls `simulated_expensive_calculation` twice, the `if` -inside the outer `else` doesn’t call it at all, and the code inside the -second `else` case calls it once. + + + + + +リスト13-3のコードには、遅い計算を行う関数への呼び出しが複数あります。最初の`if`ブロックが、 +`simulated_expensive_calculation`を2回呼び出し、外側の`else`内の`if`は全く呼び出さず、 +2番目の`else`ケースの内側にあるコードは1回呼び出しています。 -The desired behavior of the `generate_workout` function is to first check -whether the user wants a low-intensity workout (indicated by a number less -than 25) or a high-intensity workout (a number of 25 or greater). + + + + +`generate_workout`関数の期待される振る舞いは、まずユーザが低強度のトレーニング(25より小さい数値で表される)か、 +高強度のトレーニング(25以上の数値)を欲しているか確認することです。 + + + + +低強度のトレーニングプランは、シミュレーションしようとしている複雑なアルゴリズムに基づいて、 +多くの腕立て伏せや腹筋運動を推奨してきます。 + + + + + + +ユーザが高強度のトレーニングを欲していれば、追加のロジックがあります: アプリが生成した乱数がたまたま3なら、 +アプリは休憩と水分補給を勧めます。そうでなければ、ユーザは複雑なアルゴリズムに基づいて数分間のランニングをします。 -Low-intensity workout plans will recommend a number of push-ups and sit-ups -based on the complex algorithm we’re simulating. + + + + + + + -If the user wants a high-intensity workout, there’s some additional logic: if -the value of the random number generated by the app happens to be 3, the app -will recommend a break and hydration. If not, the user will get a number of -minutes of running based on the complex algorithm. +データサイエンスチームは、将来アルゴリズムを呼び出す方法に何らかの変更を加える必要があると知らせてくれました。 +そのような変更が起きた時に更新を簡略化するため、`simulated_expensive_calculation`関数を1回だけ呼び出すように、 +このコードをリファクタリングしたいです。また、過程でその関数への呼び出しを増やすことなく無駄に2回、 +この関数を現時点で呼んでいるところを切り捨てたくもあります。要するに、結果が必要なければ関数を呼び出したくなく、 +それでも1回だけ呼び出したいのです。 -The data science team has let us know that we’ll have to make some changes to -the way we call the algorithm in the future. To simplify the update when those -changes happen, we want to refactor this code so it calls the -`simulated_expensive_calculation` function only once. We also want to cut the -place where we’re currently unnecessarily calling the function twice without -adding any other calls to that function in the process. That is, we don’t want -to call it if the result isn’t needed, and we still want to call it only once. + -#### Refactoring Using Functions +#### 関数でリファクタリング -We could restructure the workout program in many ways. First, we’ll try -extracting the duplicated call to the `expensive_calculation` function into -a variable, as shown in Listing 13-4: + + + -Filename: src/main.rs +多くの方法でトレーニングプログラムを再構築することもできます。 +1番目に`expensive_calculation`関数への重複した呼び出しを変数に抽出しようとしましょう。リスト13-4に示したように: + + + +ファイル名: src/main.rs ```rust # use std::thread; @@ -199,28 +285,46 @@ fn generate_workout(intensity: u32, random_number: u32) { } ``` -Listing 13-4: Extracting the calls to -`simulated_expensive_calculation` to one place and storing the result in the -`expensive_result` variable + + + + +リスト13-4: 複数の`simulated_expensive_calculation`の呼び出しを1箇所に抽出し、 +結果を`expensive_result`変数に保存する + + + + + + + +この変更により`simulated_expensive_calculation`の呼び出しが単一化され、 +最初の`if`ブロックが無駄に関数を2回読んでいた問題を解消します。不幸なことに、これでは、 +あらゆる場合にこの関数を呼び出し、その結果を待つことになり、結果値を全く使用しない内側の`if`ブロックでもそうしてしまいます。 + + + + +プログラムの1箇所でコードを定義したいですが、結果が本当に必要なコードだけを実行します。 +これは、クロージャのユースケースです! + + -This change unifies all the calls to `simulated_expensive_calculation` and -solves the problem of the first `if` block unnecessarily calling the function -twice. Unfortunately, we’re now calling this function and waiting for the -result in all cases, which includes the inner `if` block that doesn’t use the -result value at all. +#### クロージャでリファクタリングして、コードを保存する -We want to define code in one place in our program, but only *execute* that -code where we actually need the result. This is a use case for closures! + + + + + -#### Refactoring with Closures to Store Code +`if`ブロックの前にいつも`simulated_expensive_calculation`関数を呼び出す代わりに、 +クロージャを定義し、結果を保存するのではなく、その*クロージャ*を変数に保存できます。リスト13-5のようにね。 +`simulated_expensive_calculation`の本体全体を実際に、ここで導入するクロージャ内に移すことができます: -Instead of always calling the `simulated_expensive_calculation` function before -the `if` blocks, we can define a closure and store the *closure* in a variable -rather than storing the result, as shown in Listing 13-5. We can actually move -the whole body of `simulated_expensive_calculation` within the closure we’re -introducing here: + -Filename: src/main.rs +ファイル名: src/main.rs ```rust # use std::thread; @@ -234,36 +338,59 @@ let expensive_closure = |num| { # expensive_closure(5); ``` -Listing 13-5: Defining a closure and storing it in the -`expensive_closure` variable - -The closure definition comes after the `=` to assign it to the variable -`expensive_closure`. To define a closure, we start with a pair of vertical -pipes (`|`), inside which we specify the parameters to the closure; this syntax -was chosen because of its similarity to closure definitions in Smalltalk and -Ruby. This closure has one parameter named `num`: if we had more than one -parameter, we would separate them with commas, like `|param1, param2|`. - -After the parameters, we place curly brackets that hold the body of the -closure—these are optional if the closure body is a single expression. The end -of the closure, after the curly brackets, needs a semicolon to complete the -`let` statement. The value returned from the last line in the closure body -(`num`) will be the value returned from the closure when it’s called, because -that line doesn’t end in a semicolon; just like in function bodies. - -Note that this `let` statement means `expensive_closure` contains the -*definition* of an anonymous function, not the *resulting value* of calling the -anonymous function. Recall that we’re using a closure because we want to define -the code to call at one point, store that code, and call it at a later point; -the code we want to call is now stored in `expensive_closure`. - -With the closure defined, we can change the code in the `if` blocks to call the -closure to execute the code and get the resulting value. We call a closure like -we do a function: we specify the variable name that holds the closure -definition and follow it with parentheses containing the argument values we -want to use, as shown in Listing 13-6: - -Filename: src/main.rs + + + +リスト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; @@ -298,46 +425,75 @@ fn generate_workout(intensity: u32, random_number: u32) { } ``` -Listing 13-6: Calling the `expensive_closure` we’ve -defined + + + +リスト13-6: 定義した`expensive_closure`を呼び出す + + + + +今では、重い計算はたった1箇所でのみ呼び出され、結果が必要なところでそのコードを実行するだけになりました。 + + + + + + + + + + +ところが、リスト13-3の問題の一つを再浮上させてしまいました: それでも、最初の`if`ブロックでクロージャを2回呼んでいて、 +そうすると、重いコードを2回呼び出し、必要な分の2倍ユーザを待たせてしまいます。その`if`ブロックのみに属する変数を生成して、 +クロージャの呼び出し結果を保持することでこの問題を解消することもできますが、クロージャは他の解決法も用意してくれます。 +その解決策については、もう少し先で語りましょう。でもまずは、クロージャ定義に型注釈がない理由とクロージャに関わるトレイトについて話しましょう。 -Now the expensive calculation is called in only one place, and we’re only -executing that code where we need the results. + -However, we’ve reintroduced one of the problems from Listing 13-3: we’re still -calling the closure twice in the first `if` block, which will call the -expensive code twice and make the user wait twice as long as they need to. We -could fix this problem by creating a variable local to that `if` block to hold -the result of calling the closure, but closures provide us with another -solution. We’ll talk about that solution in a bit. But first let’s talk about -why there aren’t type annotations in the closure definition and the traits -involved with closures. +### クロージャの型推論と注釈 -### Closure Type Inference and Annotation + + + + + + + -Closures don’t require you to annotate the types of the parameters or the -return value like `fn` functions do. Type annotations are required on functions -because they’re part of an explicit interface exposed to your users. Defining -this interface rigidly is important for ensuring that everyone agrees on what -types of values a function uses and returns. But closures aren’t used in an -exposed interface like this: they’re stored in variables and used without -naming them and exposing them to users of our library. +クロージャでは、`fn`関数のように引数の型や戻り値の型を注釈する必要はありません。関数では、 +型注釈は必要です。ユーザに露出する明示的なインターフェイスの一部だからです。このインターフェイスを堅実に定義することは、 +関数が使用したり、返したりする値の型についてみんなが合意していることを保証するために重要なのです。 +しかし、クロージャはこのような露出するインターフェイスには使用されません: 変数に保存され、 +名前付けしたり、ライブラリの使用者に晒されることなく、使用されます。 -Additionally, closures are usually short and only relevant within a narrow -context rather than in any arbitrary scenario. Within these limited contexts, -the compiler is reliably able to infer the types of the parameters and return -type, similar to how it’s able to infer the types of most variables. + + + + -Making programmers annotate the types in these small, anonymous functions would -be annoying and largely redundant with the information the compiler already has -available. +加えて、クロージャは通常短く、あらゆる任意のシナリオではなく、狭い文脈でのみ関係します。 +このような限定された文脈内では、コンパイラは、多くの変数の型を推論できるのに似て、 +引数や戻り値の型を頼もしく推論することができます。 -Like variables, we can add type annotations if we want to increase explicitness -and clarity at the cost of being more verbose than is strictly necessary; -annotating the types for the closure we defined in Listing 13-4 would look like -the definition shown in Listing 13-7: + + + -Filename: src/main.rs +このような小さく、匿名の関数で型をプログラマに注釈させることは、煩わしくコンパイラがすでに利用可能な情報と、 +大筋で余分でしょう。 + + + + + + +変数のように、厳格に必要な以上に冗長になることと引き換えに、明示性と明瞭性を向上させたいなら、型注釈を加えることができます; +リスト13-4で定義したクロージャに型を注釈するなら、リスト13-7に示した定義のようになるでしょう: + + + +ファイル名: src/main.rs ```rust # use std::thread; @@ -350,15 +506,22 @@ let expensive_closure = |num: u32| -> u32 { }; ``` -Listing 13-7: Adding optional type annotations of the -parameter and return value types in the closure + + -The syntax of closures and functions looks more similar with type annotations. -The following is a vertical comparison of the syntax for the definition of a -function that adds one to its parameter, and a closure that has the same -behavior. We’ve added some spaces to line up the relevant parts. This -illustrates how closure syntax is similar to function syntax except for the use -of pipes and the amount of syntax that is optional: +リスト13-7: クロージャの引数と戻り値の省略可能な型注釈を追加する + + + + + + + + +クロージャと関数の記法は、型注釈があると酷似して見えます。以下が、引数に1を加える関数の定義と、 +同じ振る舞いをするクロージャの定義の記法を縦に比べたものです。 +空白を追加して、関連のある部分を並べています。これにより、縦棒の使用と省略可能な記法の量を除いて、 +クロージャ記法が関数記法に似ているところが浮かび上がっています。 ```rust,ignore fn add_one_v1 (x: u32) -> u32 { x + 1 } @@ -367,21 +530,34 @@ let add_one_v3 = |x| { x + 1 }; let add_one_v4 = |x| x + 1 ; ``` -The first line shows a function definition, and the second line shows a fully -annotated closure definition. The third line removes the type annotations from -the closure definition, and the fourth line removes the brackets that are -optional, because the closure body has only one expression. These are all valid -definitions that will produce the same behavior when they’re called. + + + + + + +1行目が関数定義を示し、2行目がフルに注釈したクロージャ定義を示しています。 +3行目は、クロージャ定義から型注釈を取り除き、クロージャの本体がただ1つの式からなるので、 +4行目は、省略可能なかっこを取り除いています。これらは全て、 +呼び出された時に同じ振る舞いになる有効な定義です。 + + + + + + + + -Closure definitions will have one concrete type inferred for each of their -parameters and for their return value. For instance, Listing 13-8 shows the -definition of a short closure that just returns the value it receives as a -parameter. This closure isn’t very useful except for the purposes of this -example. Note that we haven’t added any type annotations to the definition: if -we then try to call the closure twice, using a `String` as an argument the -first time and a `u32` the second time, we’ll get an error: +クロージャ定義には、引数それぞれと戻り値に対して推論される具体的な型が一つあります。例えば、 +リスト13-8に引数として受け取った値を返すだけの短いクロージャの定義を示しました。 +このクロージャは、この例での目的以外には有用ではありません。この定義には、 +何も型注釈を加えていないことに注意してください: それから1回目に`String`を引数に、 +2回目に`u32`を引数に使用してクロージャを2回呼び出そうとしたら、エラーになります: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust,ignore let example_closure = |x| x; @@ -390,10 +566,14 @@ let s = example_closure(String::from("hello")); let n = example_closure(5); ``` -Listing 13-8: Attempting to call a closure whose types -are inferred with two different types + + + +リスト13-8: 2つの異なる型で型が推論されるクロージャの呼び出しを試みる -The compiler gives us this error: + + +コンパイラは、次のエラーを返します: ```text error[E0308]: mismatched types @@ -407,48 +587,80 @@ error[E0308]: mismatched types found type `{integer}` ``` -The first time we call `example_closure` with the `String` value, the compiler -infers the type of `x` and the return type of the closure to be `String`. Those -types are then locked in to the closure in `example_closure`, and we get a type -error if we try to use a different type with the same closure. - -### Storing Closures Using Generic Parameters and the `Fn` Traits - -Let’s return to our workout generation app. In Listing 13-6, our code was still -calling the expensive calculation closure more times than it needed to. One -option to solve this issue is to save the result of the expensive closure in a -variable for reuse and use the variable instead in each place we need the -result instead of calling the closure again. However, this method could result -in a lot of repeated code. - -Fortunately, another solution is available to us. We can create a struct that -will hold the closure and the resulting value of calling the closure. The -struct will only execute the closure if we need the resulting value, and it -will cache the resulting value so the rest of our code doesn’t have to be -responsible for saving and reusing the result. You may know this pattern as -*memoization* or *lazy evaluation*. - -To make a struct that holds a closure, we need to specify the type of the -closure, because a struct definition needs to know the types of each of its -fields. Each closure instance has its own unique anonymous type: that is, even -if two closures have the same signature, their types are still considered -different. To define structs, enums, or function parameters that use closures, -we use generics and trait bounds, as we discussed in Chapter 10. - -The `Fn` traits are provided by the standard library. All closures implement -one of the traits: `Fn`, `FnMut`, or `FnOnce`. We’ll discuss the difference -between these traits in the next section on capturing the environment; in this -example, we can use the `Fn` trait. - -We add types to the `Fn` trait bound to represent the types of the parameters -and return values the closures must have to match this trait bound. In this -case, our closure has a parameter of type `u32` and returns a `u32`, so the -trait bound we specify is `Fn(u32) -> u32`. - -Listing 13-9 shows the definition of the `Cacher` struct that holds a closure -and an optional result value: - -Filename: src/main.rs + + + + + +`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`です。 + + + + +リスト13-9は、クロージャとオプションの結果値を保持する`Cacher`構造体の定義を示しています: + + + +ファイル名: src/main.rs ```rust struct Cacher @@ -459,31 +671,49 @@ struct Cacher } ``` -Listing 13-9: Defining a `Cacher` struct that holds a -closure in `calculation` and an optional result in `value` + + + +リスト13-9: クロージャを`calculation`に、オプションの結果値を`value`に保持する`Cacher`構造体を定義する + + + + + + + +`Cacher`構造体には、ジェネリックな型の`T`の`calculation`フィールドがあります。`T`に関するトレイト境界は、 +`Fn`トレイトを使ったクロージャであると指定しています。`calculation`フィールドに保存したいクロージャは全て、 +1つの`u32`引数(`Fn`の後の括弧内で指定されている)を取り、`u32`(`->`の後に指定されている)を返さなければなりません。 + + + + + -The `Cacher` struct has a `calculation` field of the generic type `T`. The -trait bounds on `T` specify that it’s a closure by using the `Fn` trait. Any -closure we want to store in the `calculation` field must have one `u32` -parameter (specified within the parentheses after `Fn`) and must return a -`u32` (specified after the `->`). +> 注釈: 関数も3つの`Fn`トレイト全部を実装します。したいことに環境から値をキャプチャすることが必要ないなら、 +> `Fn`トレイトを実装する何かが必要になるクロージャではなく、関数を使用できます。 -> Note: Functions implement all three of the `Fn` traits too. If what we want -> to do doesn’t require capturing a value from the environment, we can use a -> function rather than a closure where we need something that implements an `Fn` -> trait. + + + + + + -The `value` field is of type `Option`. Before we execute the closure, -`value` will be `None`. When code using a `Cacher` asks for the *result* of the -closure, the `Cacher` will execute the closure at that time and store the -result within a `Some` variant in the `value` field. Then if the code asks for -the result of the closure again, instead of executing the closure again, the -`Cacher` will return the result held in the `Some` variant. +`value`フィールドの型は、`Option`です。クロージャを実行する前に、`value`は`None`になるでしょう。 +`Cacher`を使用するコードがクロージャの*結果*を求めてきたら、その時点で`Cacher`はクロージャを実行し、 +その結果を`value`フィールドの`Some`バリアントに保存します。それから、コードが再度クロージャの結果を求めたら、 +クロージャを再実行するのではなく、`Cacher`は`Some`バリアントに保持された結果を返すでしょう。 -The logic around the `value` field we’ve just described is defined in Listing -13-10: + + -Filename: src/main.rs +たった今説明した`value`フィールド周りのロジックは、リスト13-10で定義されています: + + + +ファイル名: src/main.rs ```rust # struct Cacher @@ -516,31 +746,52 @@ impl Cacher } ``` -Listing 13-10: The caching logic of `Cacher` + + +リスト13-10: `Cacher`のキャッシュ機構 + + + + + +呼び出し元のコードにこれらのフィールドの値を直接変えてもらうのではなく、`Cacher`に構造体のフィールドの値を管理してほしいので、 +これらのフィールドは非公開になっています。 + + + + + + + +`Cacher::new`関数は、ジェネリックな引数の`T`を取り、これは、`Cacher`構造体と同じトレイト境界を持つと定義しました。 +それから`calculation`フィールドに指定されたクロージャと、 +`value`フィールドに`None`値を保持する`Cacher`インスタンスを`Cacher::new`は返します。 +まだクロージャを実行していないからですね。 + + + + + + -We want `Cacher` to manage the struct fields’ values rather than letting the -calling code potentially change the values in these fields directly, so these -fields are private. +呼び出し元のコードがクロージャの評価結果を欲しくなったら、クロージャを直接呼ぶ代わりに、`value`メソッドを呼びます。 +このメソッドは、結果の値が`self.value`の`Some`にすでにあるかどうか確認します; そうなら、 +クロージャを再度実行することなく`Some`内の値を返します。 -The `Cacher::new` function takes a generic parameter `T`, which we’ve defined -as having the same trait bound as the `Cacher` struct. Then `Cacher::new` -returns a `Cacher` instance that holds the closure specified in the -`calculation` field and a `None` value in the `value` field, because we haven’t -executed the closure yet. + + -When the calling code wants the result of evaluating the closure, instead of -calling the closure directly, it will call the `value` method. This method -checks whether we already have a resulting value in `self.value` in a `Some`; -if we do, it returns the value within the `Some` without executing the closure -again. +`self.value`が`None`なら、`self.calculation`に保存されたクロージャを呼び出し、 +結果を将来使えるように`self.value`に保存し、その値を返しもします。 -If `self.value` is `None`, we call the closure stored in `self.calculation`, -save the result in `self.value` for future use, and return the value as well. + + -Listing 13-11 shows how we can use this `Cacher` struct in the -`generate_workout` function from Listing 13-6: +リスト13-11は、リスト13-6の`generate_workout`関数でこの`Cacher`構造体を使用する方法を示しています: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust # use std::thread; @@ -604,33 +855,53 @@ fn generate_workout(intensity: u32, random_number: u32) { } ``` -Listing 13-11: Using `Cacher` in the `generate_workout` -function to abstract away the caching logic + + + +リスト13-11: `generate_workout`関数内で`Cacher`を使用し、キャッシュ機構を抽象化する + + + + + + + +クロージャを変数に直接保存する代わりに、クロージャを保持する`Cacher`の新規インスタンスを保存しています。 +そして、結果が必要な場所それぞれで、その`Cacher`インスタンスに対して`value`メソッドを呼び出しています。 +必要なだけ`value`メソッドを呼び出したり、全く呼び出さないこともでき、重い計算は最大でも1回しか走りません。 -Instead of saving the closure in a variable directly, we save a new instance of -`Cacher` that holds the closure. Then, in each place we want the result, we -call the `value` method on the `Cacher` instance. We can call the `value` -method as many times as we want, or not call it at all, and the expensive -calculation will be run a maximum of once. + + + + + + + -Try running this program with the `main` function from Listing 13-2. Change the -values in the `simulated_user_specified_value` and `simulated_random_number` -variables to verify that in all the cases in the various `if` and `else` -blocks, `calculating slowly...` only appears once and only when needed. The -`Cacher` takes care of the logic necessary to ensure we aren’t calling the -expensive calculation more than we need to, so `generate_workout` can focus on -the business logic. +リスト13-2の`main`関数とともにこのプログラムを走らせてみてください。 +`simulated_user_specified_value`と`simulated_random_number`変数の値を変えて、 +いろんな`if`や`else`ブロックの場合全てで、`calculating slowly`は1回だけ、必要な時にのみ出現することを実証してください。 +必要以上に重い計算を呼び出さないことを保証するのに必要なロジックの面倒を`Cacher`は見るので、 +`generate_workout`はビジネスロジックに集中できるのです。 -### Limitations of the `Cacher` Implementation + -Caching values is a generally useful behavior that we might want to use in -other parts of our code with different closures. However, there are two -problems with the current implementation of `Cacher` that would make reusing it -in different contexts difficult. +### `Cacher`実装の限界 -The first problem is that a `Cacher` instance assumes it will always get the -same value for the parameter `arg` to the `value` method. That is, this test of -`Cacher` will fail: + + + + + +値をキャッシュすることは、コードの他の部分でも異なるクロージャで行いたくなるかもしれない有用な振る舞いです。 +しかし、現在の`Cacher`の実装には、他の文脈で再利用することを困難にしてしまう問題が2つあります。 + + + + + +1番目の問題は、`Cacher`インスタンスが、常に`value`メソッドの引数`arg`に対して同じ値になると想定していることです。 +言い換えると、`Cacher`のこのテストは、失敗するでしょう: ```rust,ignore #[test] @@ -644,13 +915,20 @@ fn call_with_different_values() { } ``` -This test creates a new `Cacher` instance with a closure that returns the value -passed into it. We call the `value` method on this `Cacher` instance with an -`arg` value of 1 and then an `arg` value of 2, and we expect that the call to -`value` with the `arg` value of 2 should return 2. + + + + + +このテストは、渡された値を返すクロージャを伴う`Cacher`インスタンスを新しく生成しています。 +この`Cacher`インスタンスに対して1という`arg`値で呼び出し、それから2という`arg`値で呼び出し、 +2という`arg`値の`value`呼び出しには2が返るはずと期待しています。 -Run this test with the `Cacher` implementation in Listing 13-9 and Listing -13-10, and the test will fail on the `assert_eq!` with this message: + + + +このテストをリスト13-9とリスト13-10の`Cacher`実装で動かすと、`assert_eq`からこんなメッセージが出て、 +このテストは失敗します: ```text thread 'call_with_different_values' panicked at 'assertion failed: `(left == right)` @@ -658,35 +936,58 @@ thread 'call_with_different_values' panicked at 'assertion failed: `(left == rig right: `2`', src/main.rs ``` -The problem is that the first time we called `c.value` with 1, the `Cacher` -instance saved `Some(1)` in `self.value`. Thereafter, no matter what we pass in -to the `value` method, it will always return 1. + + + + +問題は、初めて`c.value`を1で呼び出した時に、`Cacher`インスタンスは`self.value`に`Some(1)`を保存したことです。 +その後`value`メソッドに何を渡しても、常に1を返すわけです。 + + + + + + + + + +単独の値ではなく、ハッシュマップを保持するように`Cacher`を改変してみてください。ハッシュマップのキーは、 +渡される`arg`値になり、ハッシュマップの値は、そのキーでクロージャを呼び出した結果になるでしょう。 +`self.value`が直接`Some`か`None`値であることを調べる代わりに、`value`関数はハッシュマップの`arg`を調べ、 +存在するならその値を返します。存在しないなら、`Cacher`はクロージャを呼び出し、 +`arg`値に紐づけてハッシュマップに結果の値を保存します。 + + + + + + + +現在の`Cacher`実装の2番目の問題は、引数の型に`u32`を取り、`u32`を返すクロージャしか受け付けないことです。 +例えば、文字列スライスを取り、`usize`を返すクロージャの結果をキャッシュしたくなるかもしれません。 +この問題を解決するには、`Cacher`機能の柔軟性を向上させるためによりジェネリックな引数を導入してみてください。 + + + +### クロージャで環境をキャプチャする -Try modifying `Cacher` to hold a hash map rather than a single value. The keys -of the hash map will be the `arg` values that are passed in, and the values of -the hash map will be the result of calling the closure on that key. Instead of -looking at whether `self.value` directly has a `Some` or a `None` value, the -`value` function will look up the `arg` in the hash map and return the value if -it’s present. If it’s not present, the `Cacher` will call the closure and save -the resulting value in the hash map associated with its `arg` value. + + + + -The second problem with the current `Cacher` implementation is that it only -accepts closures that take one parameter of type `u32` and return a `u32`. We -might want to cache the results of closures that take a string slice and return -`usize` values, for example. To fix this issue, try introducing more generic -parameters to increase the flexibility of the `Cacher` functionality. +トレーニング生成の例において、クロージャをインラインの匿名関数として使っただけでした。しかし、 +クロージャには、関数にはない追加の能力があります: 環境をキャプチャし、 +自分が定義されたスコープの変数にアクセスできるのです。 -### Capturing the Environment with Closures + + -In the workout generator example, we only used closures as inline anonymous -functions. However, closures have an additional capability that functions don’t -have: they can capture their environment and access variables from the scope in -which they’re defined. +リスト13-12は、変数`equal_to_x`に保持されたクロージャを囲む環境から変数`x`を使用するクロージャの例です: -Listing 13-12 has an example of a closure stored in the variable `equal_to_x` -that uses the variable `x` from the closure’s surrounding environment: + -Filename: src/main.rs +ファイル名: src/main.rs ```rust fn main() { @@ -700,17 +1001,26 @@ fn main() { } ``` -Listing 13-12: Example of a closure that refers to a -variable in its enclosing scope + + -Here, even though `x` is not one of the parameters of `equal_to_x`, the -`equal_to_x` closure is allowed to use the `x` variable that’s defined in the -same scope that `equal_to_x` is defined in. +リスト13-12: 内包するスコープの変数を参照するクロージャの例 -We can’t do the same with functions; if we try with the following example, our -code won’t compile: + + + -Filename: src/main.rs +ここで、`x`は`equal_to_x`の引数でもないのに、 +`equal_to_x`が定義されているのと同じスコープで定義されている`x`変数を`equal_to_x`クロージャは使用できています。 + + + + +同じことを関数では行うことができません; 以下の例で試したら、コードはコンパイルできません: + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -724,56 +1034,90 @@ fn main() { } ``` -We get an error: + + +エラーが出ます: ```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 } | ^ ``` -The compiler even reminds us that this only works with closures! - -When a closure captures a value from its environment, it uses memory to store -the values for use in the closure body. This use of memory is overhead that we -don’t want to pay in more common cases where we want to execute code that -doesn’t capture its environment. Because functions are never allowed to capture -their environment, defining and using functions will never incur this overhead. - -Closures can capture values from their environment in three ways, which -directly map to the three ways a function can take a parameter: taking -ownership, borrowing immutably, and borrowing mutably. These are encoded in the -three `Fn` traits as follows: - -* `FnOnce` consumes the variables it captures from its enclosing scope, known - as the closure’s *environment*. To consume the captured variables, the - closure must take ownership of these variables and move them into the closure - when it is defined. The `Once` part of the name represents the fact that the - closure can’t take ownership of the same variables more than once, so it can - only be called one time. -* `Fn` borrows values from the environment immutably. -* `FnMut` can change the environment because it mutably borrows values. - -When we create a closure, Rust infers which trait to use based on how the -closure uses the values from the environment. In Listing 13-12, the -`equal_to_x` closure borrows `x` immutably (so `equal_to_x` has the `Fn` trait) -because the body of the closure only needs to read the value in `x`. - -If we want to force the closure to take ownership of the values it uses in the -environment, we can use the `move` keyword before the parameter list. This -technique is mostly useful when passing a closure to a new thread to move the -data so it’s owned by the new thread. - -We’ll have more examples of `move` closures in Chapter 16 when we talk about -concurrency. For now, here’s the code from Listing 13-12 with the `move` -keyword added to the closure definition and using vectors instead of integers, -because integers can be copied rather than moved; note that this code will not -yet compile: - -Filename: src/main.rs + + +コンパイラは、この形式はクロージャでのみ動作することにも触れています! + + + + + + + +クロージャが環境から値をキャプチャすると、メモリを使用してクロージャ本体で使用できるようにその値を保存します。 +このメモリ使用は、環境をキャプチャしないコードを実行するようなもっと一般的な場合には払いたくないオーバーヘッドです。 +関数は、絶対に環境をキャプチャすることが許可されていないので、関数を定義して使えば、このオーバーヘッドを招くことは絶対にありません。 + + + + + + +クロージャは、3つの方法で環境から値をキャプチャでき、この方法は関数が引数を取れる3つの方法に直に対応します: +所有権を奪う、不変で借用する、可変で借用するです。これらは、以下のように3つの`Fn`トレイトでコード化されています: + + + + + + + + + + +* `FnOnce`は内包されたスコープからキャプチャした変数を消費し、これがクロージャの*環境*として知られています。 +キャプチャした変数を消費するために、定義された際にクロージャはこれらの変数の所有権を奪い、 +自身にムーブするのです。名前のうち、`Once`の部分は、 +このクロージャは同じ変数の所有権を2回以上奪うことができないという事実を表しているので、1回しか呼ぶことができないのです。 +* `Fn`は、環境から値を不変で借用する。 +* `FnMut`は、可変で値を借用するので、環境を変更することができます。 + + + + + + +クロージャを生成する時、クロージャが環境を使用する方法に基づいて、コンパイラはどのトレイトを使用するか推論します。 +リスト13-12では、`equal_to_x`クロージャは`x`を不変で借用しています(ゆえに`equal_to_x`は`Fn`トレイトです)。 +クロージャの本体は、`x`を読む必要しかないからです。 + + + + + + +環境でクロージャが使用している値の所有権を奪うことをクロージャに強制したいなら、引数リストの前に`move`キーワードを使用できます。 +このテクニックは、新しいスレッドにデータが所有されるように、クロージャを新しいスレッドに渡して、 +データをムーブする際に大概は有用です。 + + + + + + + +並行性について語る第16章で、`move`クロージャの例はもっと多く出てきます。とりあえず、 +こちらが`move`キーワードがクロージャ定義に追加され、整数の代わりにベクタを使用するリスト13-12からのコードです。 +整数はムーブではなく、コピーされてしまいますからね; このコードはまだコンパイルできないことに注意してください: + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -781,6 +1125,7 @@ fn main() { let equal_to_x = move |z| z == x; + // ここでは、xを使用できません: {:?} println!("can't use x here: {:?}", x); let y = vec![1, 2, 3]; @@ -789,30 +1134,45 @@ fn main() { } ``` -We receive the following error: + + +以下のようなエラーを受けます: ```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`トレイトを実装しない型のため、ムーブが起きました) ``` -The `x` value is moved into the closure when the closure is defined, because we -added the `move` keyword. The closure then has ownership of `x`, and `main` -isn’t allowed to use `x` anymore in the `println!` statement. Removing -`println!` will fix this example. + + + + + +クロージャが定義された際に、クロージャに`x`の値はムーブされています。`move`キーワードを追加したからです。 +そして、クロージャは`x`の所有権を持ち、`main`は`println!`で`x`を使うことはもう叶わないのです。 +`println!`を取り除けば、この例は修正されます。 + + + + + +`Fn`トレイトのどれかを指定するほとんどの場合、`Fn`から始めると、コンパイラがクロージャ本体内で起こっていることにより、 +`FnMut`や`FnOnce`が必要な場合、教えてくれるでしょう。 -Most of the time when specifying one of the `Fn` trait bounds, you can start -with `Fn` and the compiler will tell you if you need `FnMut` or `FnOnce` based -on what happens in the closure body. + + -To illustrate situations where closures that can capture their environment are -useful as function parameters, let’s move on to our next topic: iterators. +環境をキャプチャできるクロージャが関数の引数として有用な場面を具体化するために、次のトピックに移りましょう: イテレータです。 diff --git a/second-edition/src/ch13-02-iterators.md b/second-edition/src/ch13-02-iterators.md index 71d560446..a78a22464 100644 --- a/second-edition/src/ch13-02-iterators.md +++ b/second-edition/src/ch13-02-iterators.md @@ -1,15 +1,25 @@ -## Processing a Series of Items with Iterators + -The iterator pattern allows you to perform some task on a sequence of items in -turn. An *iterator* is responsible for the logic of iterating over each item -and determining when the sequence has finished. When we use iterators, we don’t -have to reimplement that logic ourselves. +## 一連の要素をイテレータで処理する -In Rust, iterators are *lazy*, meaning they have no effect until we call -methods that consume the iterator to use it up. For example, the code in -Listing 13-13 creates an iterator over the items in the vector `v1` by calling -the `iter` method defined on `Vec`. This code by itself doesn’t do anything -useful: + + + + + +イテレータパターンにより、一連の要素に順番に何らかの作業を行うことができます。*イテレータ*は、 +各要素を繰り返し、シーケンスが終わったことを決定するロジックの責任を負います。イテレータを使用すると、 +自身でそのロジックを再実装する必要がなくなるのです。 + + + + + + + +Rustにおいて、イテレータは*怠惰*です。つまり、イテレータを使い込んで消費するメソッドを呼ぶまで何の効果もないということです。 +例えば、リスト13-13のコードは、`Vec`に定義された`iter`メソッドを呼ぶことで`v1`ベクタの要素に対するイテレータを生成しています。 +このコード単独では、何も有用なことはしません: ```rust let v1 = vec![1, 2, 3]; @@ -17,17 +27,27 @@ let v1 = vec![1, 2, 3]; let v1_iter = v1.iter(); ``` -Listing 13-13: Creating an iterator + + +リスト13-13: イテレータを生成する + + + + -Once we’ve created an iterator, we can use it in a variety of ways. In Listing -3-4 in Chapter 3, we used iterators with `for` loops to execute some code on -each item, although we glossed over what the call to `iter` did until now. +一旦イテレータを生成したら、いろんな手段で使用することができます。第3章のリスト3-4では、 +ここまで`iter`の呼び出しが何をするかごまかしてきましたが、`for`ループでイテレータを使い、 +各要素に何かコードを実行しています。 -The example in Listing 13-14 separates the creation of the iterator from the -use of the iterator in the `for` loop. The iterator is stored in the `v1_iter` -variable, and no iteration takes place at that time. When the `for` loop is -called using the iterator in `v1_iter`, each element in the iterator is used in -one iteration of the loop, which prints out each value: + + + + + + +リスト13-14の例は、イテレータの生成と`for`ループでイテレータを使用することを区別しています。 +イテレータは、`v1_iter`変数に保存され、その時には繰り返しは起きていません。`v1_iter`のイテレータで、 +`for`ループが呼び出された時に、イテレータの各要素がループの繰り返しで使用され、各値が出力されます。 ```rust let v1 = vec![1, 2, 3]; @@ -35,28 +55,44 @@ let v1 = vec![1, 2, 3]; let v1_iter = v1.iter(); for val in v1_iter { + // {}でした println!("Got: {}", val); } ``` -Listing 13-14: Making use of an iterator in a `for` -loop + + + +リスト13-14: `for`ループでイテレータを使用する + + + + + + + +標準ライブラリにより提供されるイテレータが存在しない言語では、変数を添字0から始め、 +その変数でベクタを覗き見て値を得て、ベクタの総要素数に到達するまでループでその変数の値をインクリメントすることで、 +この同じ機能を書く可能性が高いでしょう。 + + + + + -In languages that don’t have iterators provided by their standard libraries, we -would likely write this same functionality by starting a variable at index 0, -using that variable to index into the vector to get a value, and incrementing -the variable value in a loop until it gets to the total number of items in the -vector. +イテレータはそのロジック全てを処理してくれるので、めちゃくちゃにしてしまう可能性のあるコードの繰り返しを減らしてくれます。 +イテレータにより、添字を使えるデータ構造、ベクタなどだけではなく、多くの異なるシーケンスに対して同じロジックを使う柔軟性も得られます。 +イテレータがそれをする方法を調査しましょう。 -Iterators handle all that logic for us, cutting down on repetitive code we -could potentially mess up. Iterators give us more flexibility to use the same -logic with many different kinds of sequences, not just data structures we can -index into, like vectors. Let’s examine how iterators do that. + -### The `Iterator` Trait and the `next` Method +### `Iterator`トレイトと`next`メソッド -All iterators implement a trait named `Iterator` that is defined in the -standard library. The definition of the trait looks like this: + + + +全てのイテレータは、標準ライブラリで定義されている`Iterator`というトレイトを実装しています。 +このトレイトの定義は、以下のようになっています: ```rust trait Iterator { @@ -64,27 +100,42 @@ trait Iterator { fn next(&mut self) -> Option; + // デフォルト実装のあるメソッドは省略 // methods with default implementations elided } ``` -Notice some new syntax that we haven’t covered yet: `type Item` and -`Self::Item`, which are defining an *associated type* with this trait. We’ll -talk about associated types in depth in Chapter 19. For now, all you need to -know is that this code says implementing the `Iterator` trait requires that you -also define an `Item` type, and this `Item` type is used in the return type of -the `next` method. In other words, the `Item` type will be the type returned -from the iterator. + + + + + + + + +まだ講義していない新しい記法があることに気付いてください: `type Item`と`Self::Item`で、 +これらはこのトレイトとの*関連型*(associated type)を定義しています。関連型についての詳細は、第19章で語ります。 +今知っておく必要があることは、このコードが`Iterator`トレイトを実装するには、`Item`型も定義する必要があり、 +そしてこの`Item`型が`next`メソッドの戻り値の型に使われていると述べていることです。換言すれば、 +`Item`型がイテレータから返ってくる型になるだろうということです。 + + + + + +`Iterator`トレイトは、一つのメソッドを定義することを実装者に要求することだけします: `next`メソッドで、 +これは1度に`Some`に包まれたイテレータの1要素を返し、繰り返しが終わったら、`None`を返します。 + + + + -The `Iterator` trait only requires implementors to define one method: the -`next` method, which returns one item of the iterator at a time wrapped in -`Some` and, when iteration is over, it returns `None`. +イテレータに対して直接`next`メソッドを呼び出すこともできます; リスト13-15は、 +ベクタから生成されたイテレータの`next`を繰り返し呼び出した時にどんな値が返るかを模擬しています: -We can call the `next` method on iterators directly; Listing 13-15 demonstrates -what values are returned from repeated calls to `next` on the iterator created -from the vector: + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust,test_harness #[test] @@ -100,40 +151,67 @@ fn iterator_demonstration() { } ``` -Listing 13-15: Calling the `next` method on an -iterator - -Note that we needed to make `v1_iter` mutable: calling the `next` method on an -iterator changes state that keeps track of where it is in the sequence. In -other words, this code *consumes*, or uses up, the iterator. Each call to -`next` eats up an item from the iterator. We didn’t need to make `v1_iter` -mutable when we used a `for` loop because the loop took ownership of `v1_iter` -and made it mutable behind the scenes. - -Also note that the values we get from the calls to `next` are immutable -references to the values in the vector. The `iter` method produces an iterator -over immutable references. If we want to create an iterator that takes -ownership of `v1` and returns owned values, we can call `into_iter` instead of -`iter`. Similarly, if we want to iterate over mutable references, we can call -`iter_mut` instead of `iter`. - -### Methods that Consume the Iterator - -The `Iterator` trait has a number of different methods with default -implementations provided for us by the standard library; you can find out about -these methods by looking in the standard library API documentation for the -`Iterator` trait. Some of these methods call the `next` method in their -definition, which is why we’re required to implement the `next` method when -implementing the `Iterator` trait. - -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 -test illustrating a use of the `sum` method: - -Filename: src/lib.rs + + + +リスト13-15: イテレータに対して`next`メソッドを呼び出す + + + + + + + + +`v1_iter`を可変にする必要があったことに注目してください: イテレータの`next`メソッドを呼び出すと、 +今シーケンスのどこにいるかを追いかける状態が変わります。つまり、このコードはイテレータを*消費*、または使い込むのです。 +`next`の各呼び出しは、イテレータの要素を一つ、食います。`for`ループを使用した時には、 +`v1_iter`を可変にする必要はありませんでした。というのも、ループが`v1_iter`の所有権を奪い、 +陰で可変にしていたからです。 + + + + + + + + +また、`next`の呼び出しで得られる値は、ベクタの値への不変な参照であることにも注目してください。 +`iter`メソッドは、不変参照へのイテレータを生成します。`v1`の所有権を奪い、所有された値を返すイテレータを生成したいなら、 +`iter`ではなく`into_iter`を呼び出すことができます。同様に、可変参照を繰り返したいなら、 +`iter`ではなく`iter_mut`を呼び出せます。 + + + +### イテレータを消費するメソッド + + + + + + + + +`Iterator`トレイトには、標準ライブラリが提供してくれているデフォルト実装のある多くの異なるメソッドがあります; +`Iterator`トレイトの標準ライブラリのAPIドキュメントを検索することで、これらのメソッドについて知ることができます。 +これらのメソッドの中には、定義内で`next`メソッドを呼ぶものもあり、故に`Iterator`トレイトを実装する際には、 +`next`メソッドを実装する必要があるのです。 + + + + + + + + +`next`を呼び出すメソッドは、*消費アダプタ*(consuming adaptors)と呼ばれます。呼び出しがイテレータの使い込みになるからです。 +一例は、`sum`メソッドで、これはイテレータの所有権を奪い、`next`を繰り返し呼び出すことで要素を繰り返し、 +故にイテレータを消費するのです。繰り返しが進むごとに、各要素を一時的な合計に追加し、 +繰り返しが完了したら、その合計を返します。リスト13-16は、`sum`の使用を具体化したテストです: + + + +ファイル名: src/lib.rs ```rust #[test] @@ -148,26 +226,43 @@ fn iterator_sum() { } ``` -Listing 13-16: Calling the `sum` method to get the total -of all items in the iterator + + + +リスト13-16: `sum`メソッドを呼び出してイテレータの全要素の合計を得る + + + -We aren’t allowed to use `v1_iter` after the call to `sum` because `sum` takes -ownership of the iterator we call it on. +`sum`は呼び出し対象のイテレータの所有権を奪うので、`sum`呼び出し後に`v1_iter`を使用することはできません。 -### Methods that Produce Other Iterators + -Other methods defined on the `Iterator` trait, known as *iterator adaptors*, -allow us to change iterators into different kind of iterators. We can chain -multiple calls to iterator adaptors to perform complex actions in a readable -way. But because all iterators are lazy, we have to call one of the consuming -adaptor methods to get results from calls to iterator adaptors. +## 他のイテレータを生成するメソッド -Listing 13-17 shows an example of calling the iterator adaptor method `map`, -which takes a closure to call on each item to produce a new iterator. The -closure here creates a new iterator in which each item from the vector has been -incremented by 1. However, this code produces a warning: + + + + + -Filename: src/main.rs +`Iterator`トレイトに定義された他のメソッドは、*イテレータアダプタ*(iterator adaptors)として知られていますが、 +イテレータを別の種類のイテレータに変えさせてくれます。イテレータアダプタを複数回呼ぶ呼び出しを連結して、 +複雑な動作を読みやすい形で行うことができます。ですが、全てのイテレータは怠惰なので、消費アダプタメソッドのどれかを呼び出し、 +イテレータアダプタの呼び出しから結果を得なければなりません。 + + + + + + +リスト13-17は、イテレータアダプタメソッドの`map`の呼び出し例を示し、各要素に対して呼び出すクロージャを取り、 +新しいイテレータを生成します。ここのクロージャは、ベクタの各要素が1インクリメントされる新しいイテレータを作成します。 +ところが、このコードは警告を発します: + + + +ファイル名: src/main.rs ```rust let v1: Vec = vec![1, 2, 3]; @@ -175,14 +270,20 @@ let v1: Vec = vec![1, 2, 3]; v1.iter().map(|x| x + 1); ``` -Listing 13-17: Calling the iterator adaptor `map` to -create a new iterator + + + +リスト13-17: イテレータアダプタの`map`を呼び出して新規イテレータを作成する -The warning we get is: + + +出る警告は: ```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); @@ -191,19 +292,30 @@ and do nothing unless consumed = note: #[warn(unused_must_use)] on by default ``` -The code in Listing 13-17 doesn’t do anything; the closure we’ve specified -never gets called. The warning reminds us why: iterator adaptors are lazy, and -we need to consume the iterator here. + + + + +リスト13-17のコードは何もしません: 指定したクロージャは、決して呼ばれないのです。警告が理由に触れています: +イテレータアダプタは怠惰で、ここでイテレータを消費する必要があるのです。 + + + + + +これを解消し、イテレータを消費するには、`collect`メソッドを使用し、これは第12章でちょっとだけ見かけました。 +このメソッドはイテレータを消費し、結果の値をコレクションデータ型に集結させます。 -To fix this and consume the iterator, we’ll use the `collect` method, which you -saw briefly in Chapter 12. This method consumes the iterator and collects the -resulting values into a collection data type. + + + -In Listing 13-18, we collect the results of iterating over the iterator that’s -returned from the call to `map` into a vector. This vector will end up -containing each item from the original vector incremented by 1: +リスト13-18において、`map`呼び出しから返ってきたイテレータを繰り返した結果をベクタに集結させています。 +このベクタは、最終的に元のベクタの各要素に1を足したものが含まれます。 -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust let v1: Vec = vec![1, 2, 3]; @@ -213,29 +325,48 @@ let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); assert_eq!(v2, vec![2, 3, 4]); ``` -Listing 13-18: Calling the `map` method to create a new -iterator, and then calling the `collect` method to consume the new iterator and -create a vector + + + + +リスト13-18: `map`メソッドを呼び出して新規イテレータを作成し、 +それから`collect`メソッドを呼び出してその新規イテレータを消費し、ベクタを生成する + + + + + + +`map`はクロージャを取るので、各要素に対して行いどんな処理も指定することができます。 +これは、`Iterator`トレイトが提供する繰り返し動作を再利用しつつ、 +クロージャによりある動作をカスタマイズできる好例になっています。 + + -Because `map` takes a closure, we can specify any operation we want to perform -on each item. This is a great example of how closures let us customize some -behavior while reusing the iteration behavior that the `Iterator` trait -provides. +### 環境をキャプチャするクロージャを使用する -### Using Closures that Capture Their Environment + + + + + + -Now that we’ve introduced iterators, we can demonstrate a common use of -closures that capture their environment by using the `filter` iterator adaptor. -The `filter` method on an iterator takes a closure that takes each item from -the iterator and returns a Boolean. If the closure returns `true`, the value -will be included in the iterator produced by `filter`. If the closure returns -`false`, the value won’t be included in the resulting iterator. +イテレータが出てきたので、`filter`イテレータアダプタを使って環境をキャプチャするクロージャの一般的な使用をデモすることができます。 +イテレータの`filter`メソッドは、イテレータの各要素を取り、論理値を返すクロージャを取ります。 +このクロージャが`true`を返せば、`filter`が生成するイテレータにその値が含まれます。クロージャが`false`を返したら、 +結果のイテレータにその値は含まれません。 -In Listing 13-19 we use `filter` with a closure that captures the `shoe_size` -variable from its environment to iterate over a collection of `Shoe` struct -instances. It will return only shoes that are the specified size: + + + -Filename: src/lib.rs +リスト13-19では、環境から`shoe_size`変数をキャプチャするクロージャで`filter`を使って、 +`Shoe`構造体インスタンスのコレクションを繰り返しています。指定したサイズの靴だけを返すわけです: + + + +ファイル名: src/lib.rs ```rust,test_harness #[derive(PartialEq, Debug)] @@ -270,45 +401,73 @@ fn filters_by_size() { } ``` -Listing 13-19: Using the `filter` method with a closure -that captures `shoe_size` + + + +リスト13-19: `shoe_size`をキャプチャするクロージャで`fileter`メソッドを使用する + + + + + +`shoes_in_my_size`関数は、引数として靴のベクタとサイズの所有権を奪います。指定されたサイズの靴だけを含むベクタを返します。 -The `shoes_in_my_size` function takes ownership of a vector of shoes and a shoe -size as parameters. It returns a vector containing only shoes of the specified -size. + + + + -In the body of `shoes_in_my_size`, we call `into_iter` to create an iterator -that takes ownership of the vector. Then we call `filter` to adapt that -iterator into a new iterator that only contains elements for which the closure -returns `true`. +`shoes_in_my_size`の本体で、`into_iter`を呼び出してベクタの所有権を奪うイテレータを作成しています。 +そして、`filter`を呼び出してそのイテレータをクロージャが`true`を返した要素だけを含む新しいイテレータに適合させます。 -The closure captures the `shoe_size` parameter from the environment and -compares the value with each shoe’s size, keeping only shoes of the size -specified. Finally, calling `collect` gathers the values returned by the -adapted iterator into a vector that’s returned by the function. + + + + -The test shows that when we call `shoes_in_my_size`, we only get back shoes -that have the same size as the value we specified. +クロージャは、環境から`shoe_size`引数をキャプチャし、指定されたサイズの靴だけを保持しながら、 +その値を各靴のサイズと比較します。最後に、`collect`を呼び出すと、 +関数により返ってきたベクタに適合させたイテレータから返ってきた値が集まるのです。 -### Creating Our Own Iterators with `Iterator` + + -We’ve shown that we can create an iterator by calling `iter`, `into_iter`, or -`iter_mut` on a vector. We can create iterators from the other collection types -in the standard library, such as hash map. We can also create iterators that do -anything we want by implementing the `Iterator` trait on our own types. As -previously mentioned, the only method we’re required to provide a definition -for is the `next` method. Once we’ve done that, we can use all other methods -that have default implementations provided by the `Iterator` trait! +`shoes_in_my_size`を呼び出した時に、指定した値と同じサイズの靴だけが得られることをテストは示しています。 -To demonstrate, let’s create an iterator that will only ever count from 1 to 5. -First, we’ll create a struct to hold some values, and then we’ll make this -struct into an iterator by implementing the `Iterator` trait and use the values -in that implementation. + -Listing 13-20 has the definition of the `Counter` struct and an associated -`new` function to create instances of `Counter`: +### `Iterator`で独自のイテレータを作成する -Filename: src/lib.rs + + + + + + + + +ベクタに対し、`iter`、`into_iter`、`iter_mut`を呼び出すことでイテレータを作成できることを示してきました。 +ハッシュマップなどの標準ライブラリの他のコレクション型からもイテレータを作成できます。 +`Iterator`トレイトを自分で実装することで、したいことをどんなものでもするイテレータを作成することもできます。 +前述の通り、定義を提供する必要のある唯一のメソッドは、`next`メソッドなのです。一旦、そうしてしまえば、 +`Iterator`トレイトが用意しているデフォルト実装のある他の全てのメソッドを使うことができるのです! + + + + + + +デモ用に、1から5をカウントするだけのイテレータを作成しましょう。まず、値を保持する構造体を生成し、 +`Iterator`トレイトを実装することでこの構造体をイテレータにし、その実装内の値を使用します。 + + + + +リスト13-20は、`Counter`構造体と`Counter`のインスタンスを作る`new`関連関数の定義です: + + + +ファイル名: src/lib.rs ```rust struct Counter { @@ -322,21 +481,32 @@ impl Counter { } ``` -Listing 13-20: Defining the `Counter` struct and a `new` -function that creates instances of `Counter` with an initial value of 0 for -`count` + + + + +リスト13-20: `Counter`構造体と`count`に対して0という初期値で`Counter`のインスタンスを作る`new`関数を定義する + + + + + + -The `Counter` struct has one field named `count`. This field holds a `u32` -value that will keep track of where we are in the process of iterating from 1 -to 5. The `count` field is private because we want the implementation of -`Counter` to manage its value. The `new` function enforces the behavior of -always starting new instances with a value of 0 in the `count` field. +`Counter`構造体には、`count`というフィールドがあります。このフィールドは、 +1から5までの繰り返しのどこにいるかを追いかける`u32`値を保持しています。`Counter`の実装にその値を管理してほしいので、 +`count`フィールドは非公開です。`count`フィールドは常に0という値から新規インスタンスを開始するという動作を`new`関数は強要します。 -Next, we’ll implement the `Iterator` trait for our `Counter` type by defining -the body of the `next` method to specify what we want to happen when this -iterator is used, as shown in Listing 13-21: + + + -Filename: src/lib.rs +次に、`next`メソッドの本体をこのイテレータが使用された際に起きてほしいことを指定するように定義して、 +`Counter`型に対して`Iterator`トレイトを実装します。リスト13-21のようにね: + + + +ファイル名: src/lib.rs ```rust # struct Counter { @@ -358,26 +528,43 @@ impl Iterator for Counter { } ``` -Listing 13-21: Implementing the `Iterator` trait on our -`Counter` struct + + + +リスト13-21: `Counter`構造体に`Iterator`トレイトを実装する + + + + + +イテレータの`Item`関連型を`u32`に設定しました。つまり、イテレータは、`u32`の値を返します。 +ここでも、まだ関連型について心配しないでください。第19章で講義します。 -We set the associated `Item` type for our iterator to `u32`, meaning the -iterator will return `u32` values. Again, don’t worry about associated types -yet, we’ll cover them in Chapter 19. + + + + -We want our iterator to add one to the current state, so we initialized `count` -to 0 so it would return 1 first. If the value of `count` is less than 6, `next` -will return the current value wrapped in `Some`, but if `count` is 6 or higher, -our iterator will return `None`. +イテレータに現在の状態に1を足してほしいので、まず1を返すように0に`count`を初期化しました。 +`count`の値が5以下なら、`next`は`Some`に包まれた現在の値を返しますが、 +`count`が6以上なら、イテレータは`None`を返します。 -#### Using Our `Counter` Iterator’s `next` Method + -Once we’ve implemented the `Iterator` trait, we have an iterator! Listing 13-22 -shows a test demonstrating that we can use the iterator functionality of our -`Counter` struct by calling the `next` method on it directly, just like we did -with the iterator created from a vector in Listing 13-15: +#### `Counter`イテレータの`next`メソッドを使用する -Filename: src/lib.rs + + + + + +一旦`Iterator`トレイトを実装し終わったら、イテレータの出来上がりです!リスト13-22は、 +リスト13-15のベクタから生成したイテレータと全く同様に、直接`next`メソッドを呼び出すことで、 +`Counter`構造体のイテレータ機能を使用できることをデモするテストを示しています。 + + + +ファイル名: src/lib.rs ```rust # struct Counter { @@ -411,26 +598,46 @@ fn calling_next_directly() { } ``` -Listing 13-22: Testing the functionality of the `next` -method implementation + + + +リスト13-22: `next`メソッド実装の機能をテストする + + + + -This test creates a new `Counter` instance in the `counter` variable and then -calls `next` repeatedly, verifying that we have implemented the behavior we -want this iterator to have: returning the values from 1 to 5. +このテストは、`counter`変数に新しい`Counter`インスタンスを生成し、それから`next`を繰り返し呼び出して、 +イテレータにほしい動作が実装し終わっていることを実証しています: 1から5の値を返すことです。 -#### Using Other `Iterator` Trait Methods + -Because we implemented the `Iterator` trait by defining the `next` method, we -can now use any `Iterator` trait method’s default implementations as defined in -the standard library, because they all use the `next` method’s functionality. +#### 他の`Iterator`トレイトメソッドを使用する -For example, if for some reason we wanted to take the values produced by an -instance of `Counter`, pair them with values produced by another `Counter` -instance after skipping the first value, multiply each pair together, keep only -those results that are divisible by three, and add all the resulting values -together, we could do so, as shown in the test in Listing 13-23: + + + -Filename: src/lib.rs +`next`メソッドを定義して`Iterator`トレイトを実装したので、今では、標準ライブラリで定義されているように、 +どんな`Iterator`トレイトメソッドのデフォルト実装も使えるようになりました。全て`next`メソッドの機能を使っているからです。 + + + + + + + + + +例えば、何らかの理由で、`Counter`インスタンスが生成する値を受け取りたくなったら、最初の値を飛ばしてから、 +別の`Counter`インスタンスが生成する値と一組にし、各ペアを掛け算し、3で割り切れる結果だけを残し、 +全結果の値を足し合わせます。リスト13-23のテストに示したように、そうすることができます: + + + +ファイル名: src/lib.rs + + ```rust # struct Counter { @@ -444,13 +651,16 @@ together, we could do so, as shown in the test in Listing 13-23: # } # # 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) @@ -470,13 +680,21 @@ fn using_other_iterator_trait_methods() { } ``` -Listing 13-23: Using a variety of `Iterator` trait -methods on our `Counter` iterator + + + +リスト13-23: `Counter`イテレータに対していろんな`Iterator`トレイトのメソッドを使用する + + + + + +`zip`は4組しか生成しないことに注意してください; 理論的な5番目の組の`(5, None)`は、 +入力イテレータのどちらかが`None`を返したら、`zip`は`None`を返却するため、決して生成されることはありません。 -Note that `zip` produces only four pairs; the theoretical fifth pair `(5, -None)` is never produced because `zip` returns `None` when either of its input -iterators return `None`. + + + -All of these method calls are possible because we specified how the `next` -method works, and the standard library provides default implementations for -other methods that call `next`. +`next`メソッドの動作方法を指定し、標準ライブラリが`next`を呼び出す他のメソッドにデフォルト実装を提供しているので、 +これらのメソッド呼び出しは全てあり得ます。 From a4f96d840fae3057088f470dd220c536306af7b1 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 11 Dec 2017 22:46:27 +0900 Subject: [PATCH 076/428] First draft of the chapter 13-3 --- .../src/ch13-03-improving-our-io-project.md | 329 ++++++++++++------ 1 file changed, 220 insertions(+), 109 deletions(-) diff --git a/second-edition/src/ch13-03-improving-our-io-project.md b/second-edition/src/ch13-03-improving-our-io-project.md index 3ce466062..299e59a75 100644 --- a/second-edition/src/ch13-03-improving-our-io-project.md +++ b/second-edition/src/ch13-03-improving-our-io-project.md @@ -1,20 +1,32 @@ -## Improving Our I/O Project + -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. +## 入出力プロジェクトを改善する + + + + -### Removing a `clone` Using an Iterator +このイテレータに関する新しい知識があれば、第12章の入出力プロジェクトをイテレータを使用してコードのいろんな場所をより明確で簡潔にすることで、 +改善することができます。イテレータが`Config::new`関数と`search`関数の実装を改善する方法に目を向けましょう。 -In Listing 12-6, we added code that took a slice of `String` values and created -an instance of the `Config` struct by indexing into the slice and cloning the -values, allowing the `Config` struct to own those values. In Listing 13-24, -we’ve reproduced the implementation of the `Config::new` function as it was in -Listing 12-23 at the end of Chapter 12: + -Filename: src/lib.rs +### イテレータを使用して`clone`を取り除く + + + + + + + +リスト12-6において、スライスに添字アクセスして値をクローンすることで、`Config`構造体に値を所有させながら、 +`String`値のスライスを取り、`Config`構造体のインスタンスを作るコードを追記しました。リスト13-24では、 +第12章の最後、リスト12-23のような`Config::new`の実装を再現しました。 + + + +ファイル名: src/lib.rs ```rust,ignore impl Config { @@ -33,32 +45,55 @@ impl Config { } ``` -Listing 13-24: Reproduction of the `Config::new` function -from the end of Chapter 12 + + + +リスト13-24: 第12章の最後から`Config::new`関数の再現 + + + + +その際、将来的に除去する予定なので、非効率的な`clone`呼び出しを憂慮するなと述べました。 +えっと、その時は今です! + + + + + -At the time, we said not to worry about the inefficient `clone` calls because -we would remove them in the future. Well, that time is now! +引数に`args`に`String`要素のスライスがあるためにここで`clone`が必要だったのですが、 +`new`関数は`args`を所有していません。`Config`インスタンスの所有権を返すためには、 +`Config`インスタンスがその値を所有できるように、`Config`の`query`と`filename`フィールドから値をクローンしなければなりませんでした。 -We needed `clone` here because we have a slice with `String` elements in the -parameter `args`, but the `new` function doesn’t own `args`. To return -ownership of a `Config` instance, we had to clone the values from the `query` -and `filename` fields of `Config` so the `Config` instance can own its values. + + + + + -With our new knowledge about iterators, we can change the `new` function to -take ownership of an iterator as its argument instead of borrowing a slice. -We’ll use the iterator functionality instead of the code that checks the length -of the slice and indexes into specific locations. This will clarify what the -`Config::new` function is doing because the iterator will access the values. +イテレータについての新しい知識があれば、`new`関数をスライスを借用する代わりに、 +引数としてイテレータの所有権を奪うように変更することができます。スライスの長さを確認し、 +特定の場所に添字アクセスするコードの代わりにイテレータの機能を使います。これにより、 +イテレータは値にアクセスするので、`Config::new`関数がすることが明確化します。 -Once `Config::new` takes ownership of the iterator and stops using indexing -operations that borrow, we can move the `String` values from the iterator into -`Config` rather than calling `clone` and making a new allocation. + + + -#### Using the Returned Iterator Directly +ひとたび、`Config::new`がイテレータの所有権を奪い、借用する添字アクセス処理をやめたら、 +`clone`を呼び出して新しくメモリ確保するのではなく、イテレータからの`String`値を`Config`にムーブできます。 -Open your I/O project’s *src/main.rs* file, which should look like this: + -Filename: src/main.rs +#### 返却されるイテレータを直接使う + + + +入出力プロジェクトの*src/main.rs*ファイルを開いてください。こんな見た目のはずです: + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -73,11 +108,16 @@ fn main() { } ``` -We’ll change the start of the `main` function that we had in Listing 12-24 at -the end of Chapter 12 to the code in Listing 13-25. This won’t compile yet -until we update `Config::new` as well: + + + -Filename: src/main.rs +第12章の終わり、リスト12-24のような`main`関数の冒頭をリスト13-25のコードに変更します。 +これは、`Config::new`も更新するまでコンパイルできません: + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -90,20 +130,31 @@ fn main() { } ``` -Listing 13-25: Passing the return value of `env::args` to -`Config::new` + + + +リスト13-25: `env::args`の戻り値を`Config::new`に渡す + + + + + -The `env::args` function returns an iterator! Rather than collecting the -iterator values into a vector and then passing a slice to `Config::new`, now -we’re passing ownership of the iterator returned from `env::args` to -`Config::new` directly. +`env::args`関数は、イテレータを返します!イテレータの値をベクタに集結させ、それからスライスを`Config::new`に渡すのではなく、 +今では`env::args`から返ってくるイテレータの所有権を直接`Config::new`に渡しています。 -Next, we need to update the definition of `Config::new`. In your I/O project’s -*src/lib.rs* file, let’s change the signature of `Config::new` to look like -Listing 13-26. This still won’t compile yet because we need to update the -function body: + + + + -Filename: src/lib.rs +次に、`Config::new`の定義を更新する必要があります。入出力プロジェクトの*src/lib.rs*ファイルで、 +`Config::new`のシグニチャをリスト13-26のように変えましょう。関数本体を更新する必要があるので、 +これはそれでもコンパイルできません: + + + +ファイル名: src/lib.rs ```rust,ignore impl Config { @@ -111,24 +162,40 @@ impl Config { // --snip-- ``` -Listing 13-26: Updating the signature of `Config::new` to -expect an iterator + + + +リスト13-26: `Config::new`のシグニチャをイテレータを期待するように更新する + + + + + + + -The standard library documentation for the `env::args` function shows that the -type of the iterator it returns is `std::env::Args`. We’ve updated the -signature of the `Config::new` function so the parameter `args` has the type -`std::env::Args` instead of `&[String]`. Because we’re taking ownership of -`args` and we’ll be mutating `args` by iterating over it, we can add the `mut` -keyword into the specification of the `args` parameter to make it mutable. +`env::args`関数の標準ライブラリドキュメントは、自身が返すイテレータの型は、`std::env::Args`であると表示しています。 +`Config::new`関数のシグニチャを更新したので、引数`args`の型は、`&[String]`ではなく、 +`std::env::Args`になりました。`args`の所有権を奪い、繰り返しを行うことで`args`を可変化する予定なので、 +`args`引数の仕様に`mut`キーワードを追記し、可変にできます。 -#### Using `Iterator` Trait Methods Instead of Indexing + -Next, we’ll fix the body of `Config::new`. The standard library documentation -also mentions that `std::env::Args` implements the `Iterator` trait, so we know -we can call the `next` method on it! Listing 13-27 updates the code from -Listing 12-23 to use the `next` method: +#### 添字の代わりに`Iterator`トレイトのメソッドを使用する -Filename: src/lib.rs + + + + + +次に、`Config::new`の本体を修正しましょう。標準ライブラリのドキュメントは、 +`std::env::Args`が`Iterator`トレイトを実装していることにも言及しているので、 +それに対して`next`メソッドを呼び出せることがわかります!リスト13-27は、 +リスト13-23のコードを`next`メソッドを使用するように更新したものです: + + + +ファイル名: src/lib.rs ```rust # use std::env; @@ -145,11 +212,13 @@ impl Config { 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"), }; @@ -160,24 +229,39 @@ impl Config { } ``` -Listing 13-27: Changing the body of `Config::new` to use -iterator methods + + + +リスト13-27: `Config::new`の本体をイテレータメソッドを使うように変更する -Remember that the first value in the return value of `env::args` is the name of -the program. We want to ignore that and get to the next value, so first we call -`next` and do nothing with the return value. Second, we call `next` on the -value we want to put in the `query` field of `Config`. If `next` returns a -`Some`, we use a `match` to extract the value. If it returns `None`, it means -not enough arguments were given and we return early with an `Err` value. We do -the same thing for the `filename` value. + + + + + + + -### Making Code Clearer with Iterator Adaptors +`env::args`の戻り値の1番目の値は、プログラム名であることを思い出してください。それは無視し、 +次の値を取得したいので、まず`next`を呼び出し、戻り値に対して何もしません。2番目に、 +`Config`の`query`フィールドに置きたい値に対して`next`を呼び出します。`next`が`Some`を返したら、 +`match`を使用してその値を抜き出します。`None`を返したら、十分な引数が与えられなかったということなので、 +`Err`値で早期リターンします。`filename`値に対しても同じことをします。 -We can also take advantage of iterators in the `search` function in our I/O -project, which is reproduced here in Listing 13-28 as it was in Listing 12-19 -at the end of Chapter 12: + -Filename: src/lib.rs +### イテレータアダプタでコードをより明確にする + + + + + +入出力プロジェクトの`search`関数でも、イテレータを活用することができ、その関数は、 +第12章の最後、リスト12-19のように、ここリスト13-28に再現しました。 + + + +ファイル名: src/lib.rs ```rust,ignore pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { @@ -193,18 +277,28 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { } ``` -Listing 13-28: The implementation of the `search` -function from Chapter 12 + + + +リスト13-28: 第12章の`search`関数の実装 + + + + + + + + + +イテレータアダプタメソッドを使用して、このコードをもっと簡潔に書くことができます。そうすれば、 +可変な中間の`results`ベクタをなくすこともできます。関数型プログラミングスタイルは、可変な状態の量を最小化し、 +コードを明瞭化することを好みます。可変な状態を除去すると、検索を同時並行に行うという将来的な改善をするのが、 +簡単になるかもしれません。なぜなら、`results`ベクタへの同時アクセスを管理する必要がなくなるからです。 +リスト13-29は、この変更を示しています: -We can write this code in a more concise way using iterator adaptor methods. -Doing so also lets us avoid having a mutable intermediate `results` vector. The -functional programming style prefers to minimize the amount of mutable state to -make code clearer. Removing the mutable state might make it easier for us to -make a future enhancement to make searching happen in parallel, because we -wouldn’t have to manage concurrent access to the `results` vector. Listing -13-29 shows this change: + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust,ignore pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { @@ -214,28 +308,45 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { } ``` -Listing 13-29: Using iterator adaptor methods in the -implementation of the `search` function - -Recall that the purpose of the `search` function is to return all lines in -`contents` that contain the `query`. Similar to the `filter` example in Listing -13-19, we can use the `filter` adaptor to keep only the lines that -`line.contains(query)` returns true for. We then collect the matching lines -into another vector with `collect`. Much simpler! Feel free to make the same -change to use iterator methods in the `search_case_insensitive` function as -well. - -The next logical question is which style you should choose in your own code and -why: the original implementation in Listing 13-28 or the version using -iterators in Listing 13-29. Most Rust programmers prefer to use the iterator -style. It’s a bit tougher to get the hang of at first, but once you get a feel -for the various iterator adaptors and what they do, iterators can be easier to -understand. Instead of fiddling with the various bits of looping and building -new vectors, the code focuses on the high-level objective of the loop. This -abstracts away some of the commonplace code so it’s easier to see the concepts -that are unique to this code, such as the filtering condition each element in -the iterator must pass. - -But are the two implementations truly equivalent? The intuitive assumption -might be that the more low-level loop will be faster. Let’s talk about -performance. + + + +リスト13-29: `search`関数の実装でイテレータアダプタのメソッドを使用する + + + + + + + + + +`search`関数の目的は、`query`を含む`contents`の行全てを返すことであることを思い出してください。 +リスト13-19の`filter`例に酷似して、`filter`アダプタを使用して`line.contains(query)`が真を返す行だけを残すことができます。 +それから、合致した行を別のベクタに`collect`で集結させます。ずっと単純です!ご自由に、 +同じ変更を行い、`search_case_insensitive`関数でもイテレータメソッドを使うようにしてください。 + + + + + + + + + + + + +次の論理的な疑問は、自身のコードでどちらのスタイルを選ぶかと理由です: リスト13-28の元の実装とリスト13-29のイテレータを使用するバージョンです。 +多くのRustプログラマは、イテレータスタイルを好みます。とっかかりが少し困難ですが、 +いろんなイテレータアダプタとそれがすることの感覚を一度掴めれば、イテレータの方が理解しやすいこともあるでしょう。 +いろんなループを少しずつもてあそんだり、新しいベクタを構築する代わりに、コードは、ループの高難度の目的に集中できるのです。 +これは、ありふれたコードの一部を抽象化するので、イテレータの各要素が通過しなければならないふるい条件など、 +このコードに独特の概念を理解しやすくなります。 + + + + + +ですが、本当に2つの実装は等価なのでしょうか?直観的な仮説は、より低レベルのループの方がより高速ということかもしれません。 +パフォーマンスに触れましょう。 From 3f0cb22d45779058843408673d2ad41def87163a Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 12 Dec 2017 19:51:49 +0900 Subject: [PATCH 077/428] First draft of the chapter 13-4 and fix some errors in the chapter 11-1 --- README.md | 11 +- second-edition/src/ch11-01-writing-tests.md | 42 +++-- second-edition/src/ch13-04-performance.md | 197 +++++++++++++------- 3 files changed, 156 insertions(+), 94 deletions(-) diff --git a/README.md b/README.md index ce5ed356e..ffe0d1489 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -<<<<<<< HEAD # Rust言語 このリポジトリには、Rust本第1版と第2版両方がありますが、今回は第2版のみの翻訳です。 @@ -6,7 +5,7 @@ * 逐語訳に拘らず、読者にとってわかりやすい訳を目指す(適宜、脚注を挟む、文意に沿った訳語を選択するなど) * 原文の語順を極力尊重する。(..., like so)みたいな句を文中に持っていかず、(...。こんな感じに) -のような形で訳す。つまり、ですます調で訳しますが、あまり堅すぎる文章にはしたくないという意図です +のような形で訳す。つまり、ですます調で訳しますが、あまり堅すぎる文章にはしたくないという意図です。 僭越ながら、頑張りますので、よろしくお願いいたします。 @@ -50,12 +49,17 @@ * `:`、`;`は基本的に変更せずそのままにするが、`;`は意味が伝わりづらいと考えられるので、可能ならば`つまり`などと訳出して、削除する * 英語だとit, thatなどの指示語が多用されるが日本語だと繰り返した方が自然なことが多いので無理に指示語を使わずに自然な方を使う * theに関しては文意によって(`この`、`その`)などと訳出していることがあります。(`a`も同様) +* someについて。someは、漠然と(ぼやけてるけど)あるというイメージを表す単語。通常学校文法などでは[`いくつか`]などと訳されますが、 +その訳語では、イメージを表せないので、some people say that ...などなら(...と述べる人もいる)などのように訳します。 +some of the peopleも(一部の人々)などと訳し、[`いくつか`]は`a few`や`several`などの訳語にします。 +`何か`、`何らかの`などと訳していることも多いです。 * 逆にyou, your, we, ourなどの英語の文法上仕方なく出てくる人称代名詞は日本語には訳さない方が自然なことが多いので無理に訳に出さない。 特に、一般論を語る時のyouは 訳してはならない 参考 【雑談】"あなた"と訳さない"you" ~ einzelzelle * (こんな訳し方はしないので、大丈夫です) + * このような代名詞に関しては、訳出しないと不自然な場合のみ、訳します [translation-table]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/TranslationTable.md [contributing]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/CONTRIBUTING.md -======= + # NOTICE ABOUT STATUS The second edition of The Rust Programming Language is getting ever closer to being printed! @@ -65,7 +69,6 @@ requests submitted for frozen chapters are welcome but will be closed until we s on a third edition. Thank you! [proj]: https://github.com/rust-lang/book/projects/1 ->>>>>>> fork_master_master # The Rust Programming Language diff --git a/second-edition/src/ch11-01-writing-tests.md b/second-edition/src/ch11-01-writing-tests.md index 20de66ead..76b547822 100644 --- a/second-edition/src/ch11-01-writing-tests.md +++ b/second-edition/src/ch11-01-writing-tests.md @@ -48,7 +48,7 @@ Rustコードの欠片に関するメタデータです; 一例を挙げれば -第7章で、Cargoで新規ライブラリプロジェクトを作成した時に、テスト関数が含まれるテストモジュールが自動で生成されたことを確かめました。 +第7章で、Cargoで新規ライブラリプロジェクトを作成した時に、テスト関数が含まれるテストモジュールが自動で生成されたことを見かけました。 このモジュールのおかげでテストを書き始めることができるので、新しいプロジェクトを立ち上げる度に、 テスト関数の正確な構造と記法を調べる必要がなくなるわけです。必要なだけテスト関数とテストモジュールは追加することができます。 @@ -58,7 +58,7 @@ Rustコードの欠片に関するメタデータです; 一例を挙げれば 実際にテストすることなしにテンプレートのテストが生成されるのを実験することでテストの動作法の一部を探求しましょう。 -それから、自分で書いたコードを呼び出し、振る舞いが正しいかアサーションする現実世界のテストを書きましょう。 +それから、自分で書いた何らかのコードを呼び出し、振る舞いが正しいかアサーションする現実世界のテストを書きましょう。 @@ -102,9 +102,9 @@ mod tests { とりあえず、最初の2行は無視し、関数に集中してその動作法を見ましょう。 -`fn`行の`#[test]`アノテーションに注目してください:このアトリビュートは、これがテスト関数であることを示唆しますので、 +`fn`行の`#[test]`アノテーションに注目してください: このアトリビュートは、これがテスト関数であることを示唆しますので、 テスト実行機はこの関数をテストとして扱うとわかるのです。さらに、`tests`モジュール内には非テスト関数を入れ込み、 -一般的なシナリオをセットアップする手助けをしたり、共通の処理を行ったりもできるので、 +一般的なシナリオをセットアップしたり、共通の処理を行う手助けをしたりもできるので、 `#[test]`アトリビュートでどの関数がテストかを示唆する必要があるのです。 @@ -150,9 +150,9 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Cargoがテストをコンパイルし、走らせました。`Compiling`, `Finished`, `Running`の行の後に`running 1 test`の行があります。 -次行が、生成されたテスト関数の`it_works`とこのテストの実行結果、`ok`を示しています。 +次行が、生成されたテスト関数の`it_works`という名前とこのテストの実行結果、`ok`を示しています。 テスト実行の総合的なまとめが次に出現します。`test result:ok.`というテキストは、 -全テストが通ったことを意味し、`1 passed; 0 failed`と読める部分は、通過または失敗したテストの数を総評しているのです。 +全テストが通ったことを意味し、`1 passed; 0 failed`と読める部分は、通過または失敗したテストの数を合計しているのです。 @@ -205,7 +205,7 @@ mod tests { -そして、`cargo test`を再度走らせます。出力が`it_works`の代わりに`exploration`と表示するようになりました: +そして、`cargo test`を再度走らせます。これで出力が`it_works`の代わりに`exploration`と表示しています: ```text running 1 test @@ -298,7 +298,7 @@ error: test failed これは、*src/lib.rs*ファイルの10行で起きました。次の区域は失敗したテストの名前だけを列挙し、 テストがたくさんあり、失敗したテストの詳細がたくさん表示されるときに有用になります。 失敗したテストの名前を使用してそのテストだけを実行し、より簡単にデバッグすることができます。 -ただし、テストの実行方法については、「テストの走らせ方を制御する」節でもっと語りましょう。 +ただし、テストの実行方法については、「テストの実行され方を制御する」節でもっと語りましょう。 @@ -326,7 +326,7 @@ error: test failed `assert!`マクロは、標準ライブラリで提供されていますが、テスト内の何らかの条件が`true`と評価されることを確かめたいときに有効です。 `assert!`マクロには、論理値に評価される引数を与えます。その値が`true`なら、 `assert!`は何もせず、テストは通ります。その値が`false`なら、`assert!`マクロは`panic!`マクロを呼び出し、 -テストは失敗します。`assert!`マクロを使用することで、コードが意図した通りに機能していることを確認できるわけです。 +テストは失敗します。`assert!`マクロを使用することで、コードが意図した通りに機能していることを確認する助けになるわけです。 @@ -364,7 +364,7 @@ impl Rectangle { -`can_hold`メソッドは論理値を返すので、`assert!`マクロの完璧な実行例になるわけです。 +`can_hold`メソッドは論理値を返すので、`assert!`マクロの完璧なユースケースになるわけです。 リスト11-6で、長さが8、幅が7の`Rectangle`インスタンスを生成し、これが長さ5、 幅1の別の`Rectangle`インスタンスを保持できるとアサーションすることで`can_hold`を用いるテストを書きます: @@ -678,9 +678,10 @@ test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out 表面下では、`assert_eq!`と`assert_ne!`マクロはそれぞれ、`==`と`!=`演算子を使用しています。 アサーションが失敗すると、これらのマクロは引数をデバッグフォーマットを使用して出力するので、 比較対象の値は`PartialEq`と`Debug`トレイトを実装していなければなりません。 +組み込み型の全部と、標準ライブラリの型はほぼ全てこれらのトレイトを実装しています。 自分で定義した構造体とenumについては、`PartialEq`を実装して、 その型の値が等しいか等しくないかアサーションする必要があるでしょう。`Debug`を実装して、 -アサーションが失敗した時に値を出力できるようにする必要もあるでしょう。 +アサーションが失敗した時に値を出力する必要もあるでしょう。 第5章のリスト5-12で触れたように、どちらのトレイトも継承可能トレイトなので、 これは通常、構造体やenum定義に`#[derive(PartialEq, Debug)]`というアノテーションを追加するくらい率直になります。 これらや他の継承可能トレイトに関する詳細については、おまけCをご覧ください。 @@ -741,7 +742,7 @@ mod tests { このプログラムの必要事項はまだ合意が得られておらず、挨拶の先頭の`Hello`というテキストは変わるだろうということは確かです。 -そうなった時に名前のためにテストを更新する必要はないと決定したので、 +そうなった時に名前のためにテストを更新しなければならなくはしたくないと決定したので、 `greeting`関数から返る値と正確な等値性を確認するのではなく、出力が入力引数のテキストを含むことをアサーションするだけにします。 @@ -781,8 +782,8 @@ failures: この結果は、アサーションが失敗し、どの行にアサーションがあるかを示しているだけです。 -より役に立つ失敗メッセージは今回の場合、`greeting`関数から得た値を出力することでしょう。 -`greeting`関数から得た実際の値で埋められたプレースホルダーを含むフォーマット文字列からなるカスタムの失敗メッセージを与え、 +より有用な失敗メッセージは今回の場合、`greeting`関数から得た値を出力することでしょう。 +`greeting`関数から得た実際の値で埋められるプレースホルダーを含むフォーマット文字列からなるカスタムの失敗メッセージを与え、 テスト関数を変更しましょう: ```rust,ignore @@ -816,7 +817,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. -### `should_panic`でパニックが発生することを確認する +### `should_panic`でパニックを確認する @@ -887,7 +888,7 @@ mod tests { -`#[test]`アトリビュートの後、適用するテスト関数の前に`#[should_panic]`アトリビュートを配置しました。 +`#[test]`アトリビュートの後、適用するテスト関数の前に`#[should_panic]`アトリビュートを配置しています。 このテストが通るときの結果を見ましょう: ```text @@ -900,7 +901,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -よさそうですね!では、値が100より大きいときに`new`関数がパニックするという状態を除去することでコードにバグを導入しましょう: +よさそうですね!では、値が100より大きいときに`new`関数がパニックするという条件を除去することでコードにバグを導入しましょう: ```rust # pub struct Guess { @@ -955,7 +956,7 @@ test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out `should_panic`を使用するテストは不正確なこともあります。なぜなら、コードが何らかのパニックを起こしたことしか示さないからです。 `should_panic`のテストは、起きると想定していたもの以外の理由でテストがパニックしても通ってしまうのです。 -`should_panic`のテストの正確を期すために、`should_panic`アトリビュートのオプションの`expected`引数を追加できます。 +`should_panic`のテストの正確を期すために、`should_panic`アトリビュートの省略可能な`expected`引数を追加できます。 このテストの拘束具が、失敗メッセージに与えられたテキストが含まれていることを確かめてくれるでしょう。 例えば、リスト11-9の`Guess`の変更されたコードを考えてください。ここでは、 `new`関数は、値の大小によって異なるメッセージでパニックします。 @@ -994,6 +995,7 @@ mod tests { use super::*; #[test] + // 予想値は100以下でなければなりません #[should_panic(expected = "Guess value must be less than or equal to 100")] fn greater_than_100() { Guess::new(200); @@ -1016,11 +1018,11 @@ mod tests { -`should_panic`アトリビュートの`expected`引数においた値が`Guess::new`関数がパニックしたメッセージの一部になっているので、 +`should_panic`アトリビュートの`expected`引数に置いた値が`Guess::new`関数がパニックしたメッセージの一部になっているので、 このテストは通ります。予想されるパニックメッセージ全体を指定することもでき、そうすれば今回の場合、 `Guess value must be less than or equal to 100, got 200.`となります。 `should_panic`の予想される引数に指定すると決めたものは、パニックメッセージの固有性や活動性、 -テストの正確性によります。今回の場合、パニックメッセージの一部でテスト関数内のコードが、 +テストの正確性によります。今回の場合、パニックメッセージの一部でも、テスト関数内のコードが、 `else if value > 100`ケースを実行していると確認するのに事足りるのです。 diff --git a/second-edition/src/ch13-04-performance.md b/second-edition/src/ch13-04-performance.md index 5c9f6a192..04ae18028 100644 --- a/second-edition/src/ch13-04-performance.md +++ b/second-edition/src/ch13-04-performance.md @@ -1,48 +1,81 @@ -## Comparing Performance: Loops vs. Iterators + -To determine whether to use loops or iterators, we need to know which version -of our `search` functions is faster: the version with an explicit `for` loop or -the version with iterators. +## パフォーマンス比較: ループVSイテレータ -We ran a benchmark by loading the entire contents of *The Adventures of -Sherlock Holmes* by Sir Arthur Conan Doyle into a `String` and looking for the -word “the” in the contents. Here are the results of the benchmark on the -version of `search` using the `for` loop and the version using iterators: + + + + +ループを使うべきかイテレータを使うべきか決定するために、`search`関数のうち、どちらのバージョンが速いか知る必要があります: +明示的な`for`ループがあるバージョンと、イテレータのバージョンです。 + + + + + + +サー・アーサー・コナン・ドイル(Sir Arthur Conan Doyle)の、 +*シャーロックホームズの冒険*(The Adventures of Sherlock Homes)全体を`String`に読み込み、 +そのコンテンツで"the"という単語を検索することでベンチマークを行いました。 +こちらが、`for`を使用した`search`関数のバージョンと、イテレータを使用したバージョンに関するベンチマーク結果です。 ```text test bench_search_for ... bench: 19,620,300 ns/iter (+/- 915,700) test bench_search_iter ... bench: 19,234,900 ns/iter (+/- 657,200) ``` -The iterator version was slightly faster! We won’t explain the benchmark code -here, because the point is not to prove that the two versions are equivalent -but to get a general sense of how these two implementations compare -performance-wise. - -For a more comprehensive benchmark, you should check various texts of various -sizes, different words, words of different lengths, and all kinds of other -variations. The point is this: iterators, although a high-level abstraction, -get compiled down to roughly the same code as if you’d written the lower-level -code yourself. Iterators are one of Rust’s *zero-cost* *abstractions*, by which -we mean using the abstraction imposes no additional runtime overhead in the -same way that Bjarne Stroustrup, the original designer and implementor of C++, -defines *zero-overhead*: - -> In general, C++ implementations obey the zero-overhead principle: What you -> don’t use, you don’t pay for. And further: What you do use, you couldn’t hand -> code any better. + + + + + +イテレータバージョンの方が些か高速ですね!ここでは、ベンチマークのコードは説明しません。 +なぜなら、要点は、2つのバージョンが等価であることを証明することではなく、 +これら2つの実装がパフォーマンス的にどう比較されるかを大まかに把握することだからです。 + + + + + + + + + + +より理解しやすいベンチマークには、いろんなサイズの様々なテキスト、異なる単語、異なる長さの単語、 +他のあらゆる種類のバリエーションを確認するべきです。重要なのは: イテレータは、 +高度な抽象化にも関わらず、低レベルのコードを自身で書いているかのように、ほぼ同じコードにコンパイルされることです。 +イテレータは、Rustの*ゼロ代償**抽象化*の一つであり、これは、C++の元の設計者であり実装者の、 +ビャーネ・ストルヴストルップ(Bjarne Stroustrup)が、*ゼロオーバーヘッド*を定義したのと同様に、 +抽象化を使うことが何ら追加の実行時オーバーヘッドを生まないことを意味しています。 + + + + + + + +> 一般的に、C++の実装は、ゼロオーバーヘッド原則を遵守します: 使用しないものには、支払わなくてよい。 +> さらに: 実際に使っているものに対して、コードをそれ以上うまく渡すことはできない。 > -> Bjarne Stroustrup’s “Foundations of C++” - -As another example, the following code is taken from an audio decoder. The -decoding algorithm uses the linear prediction mathematical operation to -estimate future values based on a linear function of the previous samples. This -code uses an iterator chain to do some math on three variables in scope: a -`buffer` slice of data, an array of 12 `coefficients`, and an amount by which -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: +> ビャーネ・ストルヴストルップの「C++の基礎」 + + + + + + + + + + + +別の例として、以下のコードは、オーディオデコーダから取ってきました。デコードアルゴリズムは、 +線形予測数学演算を使用して、以前のサンプルの線形関数に基づいて未来の値を予測します。このコードは、 +イテレータ連結をしてスコープにある3つの変数に計算を行っています: `buffer`というデータのスライス、 +12の`coefficients`の配列、`qlp_shift`でデータをシフトする量です。この例の中で変数を宣言しましたが、 +値は与えていません; このコードは、文脈の外では大して意味を持ちませんが、 +それでもRustが高レベルな概念を低レベルなコードに翻訳する簡潔で現実的な例になっています: ```rust,ignore let buffer: &mut [i32]; @@ -59,37 +92,61 @@ for i in 12..buffer.len() { } ``` -To calculate the value of `prediction`, this code iterates through each of the -12 values in `coefficients` and uses the `zip` method to pair the coefficient -values with the previous 12 values in `buffer`. Then, for each pair, we -multiply the values together, sum all the results, and shift the bits in the -sum `qlp_shift` bits to the right. - -Calculations in applications like audio decoders often prioritize performance -most highly. Here, we’re creating an iterator, using two adaptors, and then -consuming the value. What assembly code would this Rust code compile to? Well, -as of this writing, it compiles down to the same assembly you’d write by hand. -There’s no loop at all corresponding to the iteration over the values in -`coefficients`: Rust knows that there are 12 iterations, so it “unrolls” the -loop. *Unrolling* is an optimization that removes the overhead of the loop -controlling code and instead generates repetitive code for each iteration of -the loop. - -All of the coefficients get stored in registers, which means it’s very fast to -access the values. There are no bounds checks on the array access at runtime. -All these optimizations Rust is able to apply make the resulting code extremely -efficient. Now that you know this, you can use iterators and closures without -fear! They make code seem like it’s higher level but don’t impose a runtime -performance penalty for doing so. - -## Summary - -Closures and iterators are Rust features inspired by functional programming -language ideas. They contribute to Rust’s capability to clearly express -high-level ideas at low-level performance. The implementations of closures and -iterators are such that runtime performance is not affected. This is part of -Rust’s goal to strive to provide zero-cost abstractions. - -Now that we’ve improved the expressiveness of our I/O project, let’s look at -some more features of `cargo` that will help us share the project with the -world. + + + + + + +`prediction`の値を算出するには、このコードは、`coefficients`の12の値を繰り返し、`zip`メソッドを使用して、 +係数値を前の`buffer`の12の値と組にします。それから各組について、その値を足し合わせ、結果を全て合計し、 +合計のビットを`qlp_shift`分だけ右にシフトさせます。 + + + + + + + + + + + +オーディオデコーダのようなアプリケーションの計算は、しばしばパフォーマンスに最も重きを置きます。 +ここでは、イテレータを作成し、2つのアダプタを使用し、それから値を消費しています。 +このRustコードは、どんな機械語コードにコンパイルされるのでしょうか?えー、執筆時点では、 +手作業で書いたものと同じ機械語にコンパイルされます。`coefficients`の値の繰り返しに対応するループは全く存在しません: +コンパイラは、12回繰り返しがあることを把握しているので、ループを「展開」します。 +*ループの展開*は、ループ制御コードのオーバーヘッドを除去し、代わりにループの繰り返しごとに同じコードを生成する最適化です。 + + + + + + + + +係数は全てレジスタに保存されます。つまり、値に非常に高速にアクセスします。実行時に配列の境界チェックをすることもありません。 +コンパイラが適用可能なこれらの最適化全てにより、結果のコードは究極的に効率化されます。このことがわかったので、 +イテレータとクロージャを恐れなしに使用することができますね!それらのおかげでコードは、高レベルだけれども、 +そうすることに対して実行時のパフォーマンスを犠牲にしないようにします。 + + + +## まとめ + + + + + + + +クロージャとイテレータは、関数型言語の考えに着想を得たRustの機能です。低レベルのパフォーマンスで、 +高レベルの考えを明確に表現するというRustの能力に貢献しています。クロージャとイテレータの実装は、 +実行時のパフォーマンスが影響されないようなものです。これは、ゼロ代償抽象化を提供するのに努力を惜しまないRustの目標の一部です。 + + + + + +今や入出力プロジェクトの表現力を改善したので、プロジェクトを世界と共有するのに役に立つ`cargo`の機能にもっと目を向けましょう。 From b919ad0a8727dc9d8edf5a7e7001356c39f39c94 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 12 Dec 2017 22:22:31 +0900 Subject: [PATCH 078/428] Fix some errors and improve the chapter 11-2 --- second-edition/src/ch11-02-running-tests.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/second-edition/src/ch11-02-running-tests.md b/second-edition/src/ch11-02-running-tests.md index e2b7e8ca2..04ce5a3d8 100644 --- a/second-edition/src/ch11-02-running-tests.md +++ b/second-edition/src/ch11-02-running-tests.md @@ -1,6 +1,6 @@ -## テストの実行法を制御する +## テストの実行され方を制御する @@ -14,8 +14,8 @@ `cargo test`はコードをテストモードでコンパイルし、出来上がったテストバイナリを実行します。 コマンドラインオプションを指定して`cargo test`の規定動作を変更することができます。 例えば、`cargo test`で生成されるバイナリの規定動作は、テストを全て並行に実行し、 -テスト実行中に生成された出力をキャプチャし、出力が表示されるのを防ぎ、 -テスト結果に関係する出力を読みやすくします。 +テスト実行中に生成された出力をキャプチャして出力が表示されるのを防ぎ、 +テスト結果に関係する出力を読みやすくすることです。 @@ -96,7 +96,7 @@ $ cargo test -- --test-threads=1 -標準では、テストが通ると、Rustのテストライブラリは標準出力に表示されたものをキャプチャします。例えば、 +標準では、テストが通ると、Rustのテストライブラリは標準出力に出力されたものを全てキャプチャします。例えば、 テストで`println!`を呼び出してテストが通ると、`println!`の出力は、ターミナルに表示されません: テストが通ったことを示す行しか見れないでしょう。テストが失敗すれば、 残りの失敗メッセージと共に、標準出力に出力されたものが全て見えるでしょう。 @@ -325,7 +325,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out -テスト名の一部を指定して、その値に合致するあらゆるテストを走らせることができます。例えば、 +テスト名の一部を指定でき、その値に合致するあらゆるテストが走ります。例えば、 我々のテストの2つが`add`という名前を含むので、`cargo test add`を実行することで、その二つを走らせることができます: ```text @@ -417,6 +417,8 @@ test expensive_test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out ``` + + From b150858df4cd7c8ed1d762adfd20cb3b3faf585a Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 12 Dec 2017 23:09:32 +0900 Subject: [PATCH 079/428] Fix some errors in the chapter 11-3 and improve the chapter 11-3 --- .../src/ch11-03-test-organization.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/second-edition/src/ch11-03-test-organization.md b/second-edition/src/ch11-03-test-organization.md index 9ac427876..a6eafc6c6 100644 --- a/second-edition/src/ch11-03-test-organization.md +++ b/second-edition/src/ch11-03-test-organization.md @@ -61,7 +61,7 @@ testsモジュールの`#[cfg(test)]`という注釈は、コンパイラに`car -この章の最初の節で新しい`adder`プロジェクトを生成した時に、Cargoがこのコードも生成したことを思い出してください: +この章の最初の節で新しい`adder`プロジェクトを生成した時に、Cargoがこのコードも生成してくれたことを思い出してください: @@ -103,10 +103,10 @@ Cargoがテストコードをコンパイルします。これには、このモ -テストコミュニティ内で非公開関数を直接テストできるべきかについては議論があり、 +テストコミュニティ内で非公開関数を直接テストするべきかについては議論があり、 他の言語では非公開関数をテストするのは困難だったり、不可能だったりします。 あなたがどちらのテストイデオロギーを支持しているかに関わらず、Rustの公開性規則により、 -非公開関数をテストすることが可能です。リスト11-12の非公開関数`internal_adder`を含むコードを考えてください: +非公開関数をテストすることが確かに可能です。リスト11-12の非公開関数`internal_adder`を含むコードを考えてください: @@ -144,7 +144,7 @@ mod tests { `internal_adder`関数は`pub`とマークされていないものの、テストも単なるRustのコードであり、 `tests`モジュールもただのモジュールでしかないので、テスト内で`internal_adder`を普通にインポートし呼び出すことができます。 -非公開関数はテストできるべきではないとお考えなら、Rustにはそれを強制するものは何もありません。 +非公開関数はテストするべきではないとお考えなら、Rustにはそれを強制するものは何もありません。 @@ -175,7 +175,7 @@ Rustにおいて、結合テストは完全にライブラリ外のものです プロジェクトディレクトリのトップ階層、*src*の隣に*tests*ディレクトリを作成します。 -Cargoは、このディレクトリに結合テストのファイルを探せることを把握しています。 +Cargoは、このディレクトリに結合テストのファイルを探すことを把握しています。 そして、このディレクトリ内にいくらでもテストファイルを作成することができ、 Cargoはそれぞれのファイルを個別のクレートとしてコンパイルします。 @@ -321,9 +321,9 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out 各結合テストファイルをそれ自身のクレートとして扱うと、 -エンドユーザが自分のクレートを使用するかのような個別のスコープを生成するのに役立ちます。 +エンドユーザが読者のクレートを使用するかのような個別のスコープを生成するのに役立ちます。 ですが、これは*tests*ディレクトリのファイルは、*src*のファイルとは同じ振る舞いを共有しないことを意味し、 -これについてはコードをモジュールとファイルに分ける方法について第7章で学びました。 +これについてはコードをモジュールとファイルに分ける方法に関して第7章で学びました。 @@ -336,7 +336,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out *tests*ディレクトリのファイルの異なる振る舞いは、複数の結合テストファイルで役に立ちそうなヘルパー関数ができ、 第7章の「モジュールを別のファイルに移動する」節の手順に従って共通モジュールに抽出しようとした時に最も気付きやすくなります。 例えば、*tests/common.rs*を作成し、そこに`setup`という名前の関数を配置したら、 -複数のテストファイルの複数のテスト関数から呼び出したい何らかのコードを`setup`に追加することができます: +複数のテストファイルの複数のテスト関数から呼び出したい`setup`に何らかのコードを追加することができます: @@ -403,7 +403,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out `common`がテスト出力に出現するのを防ぐには、*tests/common.rs*を作成する代わりに、 -*tests/common/mod.rs*を作成すればいいのです。第7章の「モジュールファイルシステムの規則」節において、 +*tests/common/mod.rs*を作成します。第7章の「モジュールファイルシステムの規則」節において、 *module_name/mod.rs*という命名規則をサブモジュールのあるモジュールのファイルに使用したので、 ここでは`common`にサブモジュールはありませんが、 このように命名することでコンパイラに`common`モジュールを結合テストファイルとして扱わないように指示します。 @@ -487,7 +487,7 @@ Rustのテスト機能は、変更を加えた後でさえ想定通りにコー コードが機能すべき方法を指定する手段を提供します。単体テストはライブラリの異なる部分を個別に用い、 非公開の実装詳細をテストすることができます。結合テストは、ライブラリのいろんな部分が共同で正常に動作することを確認し、 ライブラリの公開APIを使用して外部コードが使用するのと同じ方法でコードをテストします。 -Rustの型システムと所有権ルールにある種のバグは防がれるものの、それでもテストは、 +Rustの型システムと所有権ルールにより防がれるバグの種類もあるものの、それでもテストは、 コードの振る舞い方に関するロジックのバグを減らすのに重要なのです。 From 00fa7ee855f40eca2f7c2fc8a101a5ee1795cba5 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 13 Dec 2017 19:22:31 +0900 Subject: [PATCH 080/428] Fix some errors in the chapters 12-1, 12-2 and 12-3 --- ...h12-01-accepting-command-line-arguments.md | 6 +-- second-edition/src/ch12-02-reading-a-file.md | 8 +-- ...improving-error-handling-and-modularity.md | 50 ++++++++++--------- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/second-edition/src/ch12-01-accepting-command-line-arguments.md b/second-edition/src/ch12-01-accepting-command-line-arguments.md index 6d12b354d..c0fbd62af 100644 --- a/second-edition/src/ch12-01-accepting-command-line-arguments.md +++ b/second-edition/src/ch12-01-accepting-command-line-arguments.md @@ -37,7 +37,7 @@ $ cargo run searchstring example-filename.txt 今現在は、`cargo new`で生成されたプログラムは、与えた引数を処理できません。しかしながら、 [Crates.io](https://crates.io/)に存在するある既存のライブラリは、 コマンドライン引数を受け付けるプログラムを書く手助けをしてくれますが、ちょうどこの概念を学んでいる最中なので、 -この機能を自分で実装しましょう。 +この能力を自分で実装しましょう。 @@ -55,7 +55,7 @@ $ cargo run searchstring example-filename.txt `minigrep`が渡したコマンドライン引数の値を読み取れていると確認するために、Rustの標準ライブラリで提供されている関数が必要になり、 それは、`std::env::args`です。この関数は、`minigrep`に与えられたコマンドライン引数の*イテレータ*を返します。 イテレータについてはまだ議論していません(完全には第13章で解説します)が、とりあえずイテレータに関しては、 -2つの詳細のみ知っていればいいです: イテレータは一連の値を生成すること、イテレータに対して`collect`関数を呼び出し、 +2つの詳細のみ知っていればいいです: イテレータは一連の値を生成することと、イテレータに対して`collect`関数を呼び出し、 イテレータが生成する要素全部を含むベクタ型などのコレクションに変えられることです。 @@ -234,4 +234,4 @@ In file sample.txt 素晴らしい、プログラムは動作しています!必要な引数の値が、正しい変数に保存されています。後ほど、 何らかのエラー処理を加えて、特定の可能性のあるエラー状況に対処します。ユーザが引数を提供しなかった場合などです; -今は、そのような状況はないものとし、代わりにファイル読み取り機能を追加することに取り組みます。 +今は、そのような状況はないものとし、代わりにファイル読み取り能力を追加することに取り組みます。 diff --git a/second-edition/src/ch12-02-reading-a-file.md b/second-edition/src/ch12-02-reading-a-file.md index 020ad09c7..d73d785cc 100644 --- a/second-edition/src/ch12-02-reading-a-file.md +++ b/second-edition/src/ch12-02-reading-a-file.md @@ -33,7 +33,7 @@ To an admiring bog! 私は誰でもない!あなたは誰? あなたも誰でもないの? -なら、私たちは組みだね、何も言わないで! +なら、私たちは組だね、何も言わないで! あの人たちは、私たちを追放するでしょう。わかりますよね? 誰かでいるなんて侘しいじゃない! @@ -101,7 +101,7 @@ fn main() { 最初に、もう何個か`use`文を追記して、標準ライブラリの関係のある箇所を持ってきています: ファイルを扱うのに`std::fs::File`が必要ですし、 -`std::io::prelude::*`はファイル入出力を含む入出力処理をするのに有用なトレイトを多く含んでいます。 +`std::io::prelude::*`はファイル入出力を含む入出力処理をするのに有用なトレイトを色々含んでいます。 言語が一般的な初期化処理で特定の型や関数を自動的にスコープに導入するように、 `std::io`モジュールにはそれ独自の共通の型や関数の初期化処理があり、入出力を行う際に必要になるわけです。 標準の初期化処理とは異なり、`std::io`の初期化処理には明示的に`use`文を加えなければなりません。 @@ -113,8 +113,8 @@ fn main() { -`main`で3文を追記しました: 一つ目が、`File::open`関数を呼んでファイルへの可変なハンドルを得て、 -`filename`変数の値に渡す処理です。二つ目が、`contents`という名の変数を生成して、 +`main`で3文を追記しました: 一つ目が、`File::open`関数を呼んで`filename`変数の値に渡して、 +ファイルへの可変なハンドルを得る処理です。二つ目が、`contents`という名の変数を生成して、 可変で空の`String`を割り当てる処理です。この変数が、ファイル読み込み後に中身を保持します。 三つ目が、ファイルハンドルに対して`read_to_string`を呼び出し、引数として`contents`への可変参照を渡す処理です。 diff --git a/second-edition/src/ch12-03-improving-error-handling-and-modularity.md b/second-edition/src/ch12-03-improving-error-handling-and-modularity.md index 1749b928e..de5cd34d2 100644 --- a/second-edition/src/ch12-03-improving-error-handling-and-modularity.md +++ b/second-edition/src/ch12-03-improving-error-handling-and-modularity.md @@ -58,10 +58,10 @@ 4番目は、異なるエラーを処理するのに`expect`を繰り返し使用しているので、ユーザが十分な数の引数を渡さずにプログラムを起動した時に、 -問題を明確に説明しない「範囲外アクセス(index out of bounds)」というエラーがRustから送られることです。 +問題を明確に説明しない「範囲外アクセス(index out of bounds)」というエラーがRustから得られることです。 エラー処理のコードが全て1箇所に存在し、将来エラー処理ロジックが変更になった時に、 メンテナンス者が1箇所のコードのみを考慮すればいいようにするのが最善でしょう。 -エラー処理コードが1箇所にあれば、エンドユーザにとって意味のあるメッセージを出力していることを確認できることにもつながります。 +エラー処理コードが1箇所にあれば、エンドユーザにとって意味のあるメッセージを出力していることを確認することにもつながります。 @@ -69,7 +69,7 @@ -### バイナリプロジェクトで責任の分離 +### バイナリプロジェクトの責任の分離 @@ -180,8 +180,8 @@ fn parse_config(args: &[String]) -> (&str, &str) { このやり直しは、私たちの小規模なプログラムにはやりすぎに思えるかもしれませんが、 少しずつ段階的にリファクタリングしているのです。この変更後、プログラムを再度実行して、 -引数解析がまだ動作していることを確かめてください。頻繁に進捗を確認するのはいいことです。 -問題が発生した時に原因を特定しやすくなりますからね。 +引数解析がまだ動作していることを実証してください。頻繁に進捗を確認するのはいいことです。 +問題が発生した時に原因を特定する助けになりますからね。 @@ -206,7 +206,7 @@ fn parse_config(args: &[String]) -> (&str, &str) { まだ改善の余地があると示してくれる他のものは、`parse_config`の`config`の部分であり、 返却している二つの値は関係があり、一つの設定値の一部にどちらもなることを暗示しています。 -現状では、この意味を一つのタプルにまとめていること以外、データの構造に載せていません: +現状では、一つのタプルにまとめていること以外、この意味をデータの構造に載せていません: この二つの値を1構造体に置き換え、構造体のフィールドそれぞれに意味のある名前をつけることもできるでしょう。 そうすることで将来このコードのメンテナンス者が、異なる値が相互に関係する仕方や、目的を理解しやすくできるでしょう。 @@ -339,8 +339,8 @@ Rustの借用規則に違反してしまうことを意味します。 -ここまで、コマンドライン引数を解析するロジックを`main`から抽出し、`parse_config`関数に配置しました。 -これにより`query`と`filename`の値が関連し、その関係性がコードに載っていることを確認できました。 +ここまで、コマンドライン引数を解析する責任を負ったロジックを`main`から抽出し、`parse_config`関数に配置しました。 +これにより`query`と`filename`の値が関連し、その関係性がコードに載っていることを確認する助けになりました。 それから`Config`構造体を追加して`query`と`filename`の関係する目的を名前付けし、 構造体のフィールド名として`parse_config`関数からその値の名前を返すことができています。 @@ -356,7 +356,7 @@ Rustの借用規則に違反してしまうことを意味します。 したがって、今や`parse_config`関数の目的は`Config`インスタンスを生成することになったので、 `parse_config`をただの関数から`Config`構造体に紐付く`new`という関数に変えることができます。 この変更を行うことで、コードがより慣用的になります: `String`などの標準ライブラリの型のインスタンスを、 -`String::new`を呼び出すことで生成できるように、`parse_config`を`Config`に紐付く`new`関数に変えれば、 +`String::new`を呼び出すことで生成でき、`parse_config`を`Config`に紐付く`new`関数に変えれば、 `Config::new`を呼び出すことで`Config`のインスタンスを生成できるようになります。リスト12-7が、 行う必要のある変更を示しています: @@ -425,7 +425,7 @@ $ cargo run Running `target/debug/minigrep` thread 'main' panicked at 'index out of bounds: the len is 1 but the index is 1', src/main.rs:29:21 -(スレッド'main'は、「境界外アクセス: 長さは1なのに添字は1です」でパニックしました) +(スレッド'main'は、「境界外アクセス: 長さは1なのに添字も1です」でパニックしました) note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` @@ -445,7 +445,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. -リスト12-8で、`new`関数に添字`1`と`2`にアクセスする前にスライスが十分長いことを確認するチェックを追加しています。 +リスト12-8で、`new`関数に添字`1`と`2`にアクセスする前にスライスが十分長いことを実証するチェックを追加しています。 スライスの長さが十分でなければ、プログラムはパニックし、`境界外アクセス`よりもいいエラーメッセージを表示します。 @@ -477,8 +477,8 @@ fn new(args: &[String]) -> Config { このコードは、リスト9-9で記述した`value`引数が正常な値の範囲外だった時に`panic!`を呼び出した`Guess::new`関数と似ています。 ここでは、値の範囲を確かめる代わりに、`args`の長さが少なくとも`3`であることを確かめていて、 -関数の残りの部分は、この条件が満たされているという前提のもとで処理を行うことができます。 -`args`に3要素以下しかなければ、この条件は真になり、`panic!`マクロを呼び出して、即座にプログラムを終了させます。 +関数の残りの部分は、この条件が満たされているという仮定のもとで処理を行うことができます。 +`args`に2要素以下しかなければ、この条件は真になり、`panic!`マクロを呼び出して、即座にプログラムを終了させます。 @@ -507,7 +507,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. ユーザに与えたくない追加の情報も含まれてしまっています。おそらく、 ここではリスト9-9で使用したテクニックを使用するのは最善ではありません: `panic!`の呼び出しは、第9章で議論したように、使用の問題よりもプログラミング上の問題により適しています。 -代わりに、第9章で学んだ別のテクニックを使用することができます。成功か失敗かを示唆する`Result`を返すことです。 +代わりに、第9章で学んだもう一つのテクニックを使用することができます。成功か失敗かを示唆する`Result`を返すことです。 @@ -531,7 +531,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. リスト12-9は、`Config::new`の戻り値に必要な変更と`Result`を返すのに必要な関数の本体を示しています。 -`main`も更新するまで、これはコンパイルできないことに注意してください。こちらは次のリストで行います: +`main`も更新するまで、これはコンパイルできないことに注意してください。その更新は次のリストで行います: @@ -563,7 +563,7 @@ impl Config { `new`関数は、今や、成功時には`Config`インスタンスを、エラー時には`&'static str`を伴う`Result`を返すようになりました。 -第10章の「静的ライフタイム」から`&'static str`は文字列リテラルの型であることを思い出してください。 +第10章の「静的ライフタイム」節から`&'static str`は文字列リテラルの型であることを思い出してください。 これは、今はエラーメッセージの型になっています。 @@ -578,8 +578,8 @@ impl Config { -`Config::new`から`Err`値を返すことにより、`main`関数は、`new`関数から帰ってくる`Result`値を処理し、 -エラー時により明確にプロセスから抜け出すことができます。 +`Config::new`から`Err`値を返すことにより、`main`関数は、`new`関数から返ってくる`Result`値を処理し、 +エラー時により綺麗にプロセスから抜け出すことができます。 @@ -593,7 +593,7 @@ impl Config { エラーケースを処理し、ユーザフレンドリーなメッセージを出力するために、`main`を更新して、 -リスト12-10に示したように`Config::new`から返される`Result`を処理する必要があります。 +リスト12-10に示したように`Config::new`から返されている`Result`を処理する必要があります。 また、`panic!`からコマンドラインツールを0以外のエラーコードで抜け出す責任も奪い取り、 手作業でそれも実装します。0以外の終了コードは、 我々のプログラムを呼び出したプロセスにプログラムがエラー状態で終了したことを通知する慣習です。 @@ -635,11 +635,11 @@ fn main() { -このリストにおいて、以前には解説していないメソッドを使用しました: `unwrap_or_else`です。 +このリストにおいて、以前には講義していないメソッドを使用しました: `unwrap_or_else`です。 これは標準ライブラリで`Result`に定義されています。`unwrap_or_else`を使うことで、 `panic!`ではない何らか独自のエラー処理を定義できるのです。この`Result`が`Ok`値だったら、 このメソッドの振る舞いは`unwrap`に似ています: `Ok`が包んでいる中身の値を返すのです。 -しかし、値が`Err`値なら、このメソッドは、クロージャ内でコードを呼び出し、 +しかし、値が`Err`値なら、このメソッドは、*クロージャ*内でコードを呼び出し、 クロージャは定義し、引数として`unwrap_or_else`に渡す匿名関数です。クロージャについては第13章で詳しく解説します。 とりあえず、`unwrap_or_else`は、今回リスト12-9で追加した`not enough arguments`という静的文字列の`Err`の中身を、 縦棒の間に出現する`err`引数のクロージャに渡していることだけ知っておく必要があります。 @@ -683,7 +683,7 @@ Problem parsing arguments: not enough arguments ようやく設定解析のリファクタリングが終了したので、プログラムのロジックに目を向けましょう。 -ページXXの「バイナリプロジェクトの責任分離」で述べたように、 +ページXXの「バイナリプロジェクトの責任の分離」で述べたように、 現在`main`関数に存在する設定セットやエラー処理に関わらない全てのロジックを保持することになる`run`という関数を抽出します。 やり終わったら、`main`は簡潔かつ視察で確かめやすくなり、他のロジック全部に対してテストを書くことができるでしょう。 @@ -691,7 +691,7 @@ Problem parsing arguments: not enough arguments -リスト12-11は、抽出された`run`関数を示しています。今は少しずつ段階的に関数を抽出する改善を行っています。 +リスト12-11は、抜き出した`run`関数を示しています。今は少しずつ段階的に関数を抽出する改善を行っています。 それでも、*src/main.rs*に関数を定義していきます: @@ -737,6 +737,10 @@ fn run(config: Config) { #### `run`関数からエラーを返す + + + + From 3092bdc58eec565b31625bf129f9fb09dec96af6 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 13 Dec 2017 19:47:54 +0900 Subject: [PATCH 081/428] Fix errors in the chapter 12-4 and commit the missing modifications in the chapter 12-3 --- ...improving-error-handling-and-modularity.md | 4 +-- ...2-04-testing-the-librarys-functionality.md | 34 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/second-edition/src/ch12-03-improving-error-handling-and-modularity.md b/second-edition/src/ch12-03-improving-error-handling-and-modularity.md index de5cd34d2..3f6556324 100644 --- a/second-edition/src/ch12-03-improving-error-handling-and-modularity.md +++ b/second-edition/src/ch12-03-improving-error-handling-and-modularity.md @@ -800,7 +800,7 @@ fn run(config: Config) -> Result<(), Box> { エラー型については、*トレイトオブジェクト*の`Box`を使用しました(同時に冒頭で`use`文により、 `std::error::Error`をスコープに導入しています)。トレイトオブジェクトについては、第17章で講義します。 とりあえず、`Box`は、関数が`Error`トレイトを実装する型を返すことを意味しますが、 -戻り値の型を具体的に指定する必要はないことを知っておいてください。これにより、 +戻り値の型を具体的に指定しなくても良いことを知っておいてください。これにより、 エラーケースによって異なる型のエラー値を返す柔軟性を得ます。 @@ -828,7 +828,7 @@ fn run(config: Config) -> Result<(), Box> { ```text warning: unused `std::result::Result` which must be used -(警告: 使用されるはずの`std::result::Result`が未使用です) +(警告: 使用されなければならない`std::result::Result`が未使用です) --> src/main.rs:18:5 | 18 | run(config); diff --git a/second-edition/src/ch12-04-testing-the-librarys-functionality.md b/second-edition/src/ch12-04-testing-the-librarys-functionality.md index c24790a51..819b1016f 100644 --- a/second-edition/src/ch12-04-testing-the-librarys-functionality.md +++ b/second-edition/src/ch12-04-testing-the-librarys-functionality.md @@ -29,7 +29,7 @@ 1. 失敗するテストを書き、走らせて想定通りの理由で失敗することを確かめる。 -2. 十分な量のコードだけを書くか変更して新しいテストを通過するようにする。 +2. 十分な量のコードを書くか変更して新しいテストを通過するようにする。 3. 追加または変更したばかりのコードをリファクタリングし、テストが通り続けることを確認する 4. 手順1から繰り返す! @@ -82,7 +82,7 @@ mod test { fn one_result() { let query = "duct"; // Rustは - // 安全で早く生産性も高い。 + // 安全で速く生産性も高い。 // 3つ選んで。 let contents = "\ Rust: @@ -116,11 +116,11 @@ Pick three."; -このテストを走らせ、失敗するところを観察することはできません。このテストはコンパイルできないからです: +このテストを走らせ、失敗するところを観察することはできません。このテストはコンパイルもできないからです: まだ`search`関数が存在していません!ゆえに今度は、空のベクタを常に返す`search`関数の定義を追加することで、 テストをコンパイルし走らせるだけのコードを追記します。リスト12-16に示したようにね。そうすれば、 テストはコンパイルでき、失敗するはずです。なぜなら、空のベクタは、 -`"safe, fast, productive"`という行を含むベクタとは合致しないからです。 +`"safe, fast, productive."`という行を含むベクタとは合致しないからです。 @@ -137,6 +137,8 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { リスト12-16: テストがコンパイルできるのに十分なだけ`search`関数を定義する + + @@ -144,10 +146,10 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { -明示的なライフタイムの`'a`が`search`のシグニチャで定義され、`contents`引数と戻り値で使用されていることに注目してください。 +明示的なライフタイムの`'a`が`search`のシグニチャで定義され、`contents`引数と戻り値で使用されていることに気付いてください。 第10章からライフタイム仮引数は、どの実引数のライフタイムが戻り値のライフタイムに関連づけられているかを指定することを思い出してください。 この場合、返却されるベクタは、 -(`query`引数よりも)`contents`引数のスライスを参照する文字列スライスを含むべきと示唆しています。 +(`query`引数ではなく)`contents`引数のスライスを参照する文字列スライスを含むべきと示唆しています。 @@ -178,7 +180,7 @@ 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`から借用されたものであるかが示されていません) ``` @@ -188,7 +190,7 @@ parameter コンパイラには、二つの引数のどちらが必要なのか知る由がないので、教えてあげる必要があるのです。 -`contents`がテキストを全て含むテキストで、合致するそのテキストの一部を返したいので、 +`contents`がテキストを全て含む引数で、合致するそのテキストの一部を返したいので、 `contents`がライフタイム記法で戻り値に関連づくはずの引数であることをプログラマは知っています。 @@ -251,25 +253,25 @@ error: test failed, to rerun pass '--lib' -* 中身を各行ごとに見る。 +* 中身を各行ごとに繰り返す。 * 行にクエリ文字列が含まれるか確認する。 * するなら、それを返却する値のリストに追加する。 * しないなら、何もしない。 -* 合致する結果のリストを返す。 +* 一致する結果のリストを返す。 -各行を見る作業から、この手順に取り掛かりましょう。 +各行を繰り返す作業から、この手順に順に取り掛かりましょう。 -#### `lines`メソッドで各行を見る +#### `lines`メソッドで各行を繰り返す -Rustには、文字列を行ごとに繰り返す有用なメソッドがあり、利便性のために`lines`と名付けられ、 +Rustには、文字列を行ごとに繰り返す役立つメソッドがあり、利便性のために`lines`と名付けられ、 リスト12-17のように動作します。まだこれはコンパイルできないことに注意してください: @@ -309,7 +311,7 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { 次に現在の行がクエリ文字列を含むか確認します。幸運なことに、 -文字列にはこれを行ってくれる`contains`という有用なメソッドがあります!`search`関数に、 +文字列にはこれを行ってくれる`contains`という役に立つメソッドがあります!`search`関数に、 `contains`メソッドの呼び出しを追加してください。リスト12-18のようにね。 これもまだコンパイルできないことに注意してください: @@ -366,7 +368,7 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { -リスト12-19: 合致する行を保存したので、返すことができます +リスト12-19: 合致する行を保存したので、返すことができる @@ -385,7 +387,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -テストが通りました。動いていることがわかりました! +テストが通り、動いていることがわかりました! From 1a8efaf2687d2a27368738768d992f5d39b7da18 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 13 Dec 2017 20:14:50 +0900 Subject: [PATCH 082/428] Fix some errors and revise the chapter 12-5 --- .../ch12-05-working-with-environment-variables.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/second-edition/src/ch12-05-working-with-environment-variables.md b/second-edition/src/ch12-05-working-with-environment-variables.md index 7d5fa97f1..ec7e3d9ef 100644 --- a/second-edition/src/ch12-05-working-with-environment-variables.md +++ b/second-edition/src/ch12-05-working-with-environment-variables.md @@ -98,7 +98,8 @@ Trust me."; 大文字小文字を区別*しない*検索の新しいテストは、クエリに"rUsT"を使用しています。 -追加直前の`search_case_insensitive`関数では、"rUsT"というクエリは、大文字Rの"Rust:"を含む行と、 +追加直前の`search_case_insensitive`関数では、"rUsT"というクエリは、 +両方ともクエリとは大文字小文字が異なるのに、大文字Rの"Rust:"を含む行と、 "Trust me."という行にもマッチするはずです。これが失敗するテストであり、まだ`search_case_insensitive`関数を定義していないので、 コンパイルは失敗するでしょう。リスト12-16の`search`関数で行ったように空のベクタを常に返す実装の骨格を追加して、 ご自由にテストがコンパイルされ、失敗する様を確認してください。 @@ -163,6 +164,8 @@ fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { "rust"を含む新しい`String`のメモリを確保しなければならないのです。今、`contains`メソッドに引数として`query`を渡すと、 アンド記号を追加する必要があります。`contains`のシグニチャは、文字列スライスを取るよう定義されているからです。 + + @@ -271,7 +274,7 @@ pub fn run(config: Config) -> Result<(), Box>{ 最後に、環境変数を確認する必要があります。環境変数を扱う関数は、標準ライブラリの`env`モジュールにあるので、 -`use std::env;`行で*src/lib.rs*の冒頭でそのモジュールをスコープに持ってきたいです。そして、 +`use std::env;`行で*src/lib.rs*の冒頭でそのモジュールをスコープに持ってくる必要があります。そして、 `env`モジュールから`var`メソッドを使用して`CASE_INSENSITIVE`という環境変数のチェックを行います。 リスト12-23のようにね: @@ -333,7 +336,8 @@ impl Config { `Result`の`is_err`メソッドを使用して、エラーでありゆえに、セットされていないことを確認しています。 これは大文字小文字を区別する検索をす*べき*ことを意味します。`CASE_INSENSITIVE`環境変数が何かにセットされていれば、 `is_err`はfalseを返し、大文字小文字を区別しない検索を実行するでしょう。環境変数の値には興味がなく、 -セットされているかどうかだけ気にするので、`unwrap`や`expect`あるいは、他のここまで見かけた`Result`のメソッドはチェックしていません。 +セットされているかどうかだけ気にするので、`unwrap`や`expect`あるいは、他のここまで見かけた`Result`のメソッドではなく、 +`is_err`をチェックしています。 @@ -362,7 +366,7 @@ How dreary to be somebody! -まだそれは機能しているようです!では、`CASE_INSENSITIVE`を1にしつつ、同じクエリの"to"でプログラムを実行しましょう。 +まだ機能しているようです!では、`CASE_INSENSITIVE`を1にしつつ、同じクエリの"to"でプログラムを実行しましょう。 つまり、大文字も含む"to"を含有する行が得られるはずです。 ```text @@ -378,7 +382,7 @@ To an admiring bog! -PowerShellを使用していれば、1つではなく、2つのコマンドで環境変数をセットし、プログラムを走らせる必要があります: +PowerShellを使用していれば、1つではなく、2つのコマンドで環境変数をセットし、プログラムを走らせる必要があるでしょう: ```text $ $env.CASE_INSENSITIVE=1 From 075f3d85945c32d586269ecaf768b6df4b64ced4 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 13 Dec 2017 20:27:45 +0900 Subject: [PATCH 083/428] Revise the chapter 12-6 --- .../src/ch12-06-writing-to-stderr-instead-of-stdout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md b/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md index 8763ca7ec..82adcb482 100644 --- a/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md +++ b/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md @@ -185,4 +185,4 @@ How dreary to be somebody! -次に、関数型言語に影響されたRust機能の一部を探求します: クロージャとイテレータです。 +次は、関数型言語に影響されたRust機能を一部探求します: クロージャとイテレータです。 From 04f9f83b0b74b8f3bf7cb5b105da12ee96a2426a Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 13 Dec 2017 22:11:14 +0900 Subject: [PATCH 084/428] Fix an error in the chapter 13-0 --- second-edition/src/ch13-00-functional-features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch13-00-functional-features.md b/second-edition/src/ch13-00-functional-features.md index 251ae9808..239102f74 100644 --- a/second-edition/src/ch13-00-functional-features.md +++ b/second-edition/src/ch13-00-functional-features.md @@ -14,7 +14,7 @@ Rustの設計は、多くの既存の言語やテクニックにインスピレーションを得ていて、 その一つの大きな影響が*関数型プログラミング*です。関数型でのプログラミングには、しばしば、 引数で渡すことで関数を値として使用したり、関数から関数を返したり、関数を後ほど使用するために変数に代入することなどが含まれます。 -この章では、関数型プログラミングがどんなものであるかという問題については議論しませんが、 +この章では、関数型プログラミングがどんなものであったり、なかったりするかという問題については議論しませんが、 代わりに関数型とよく言及される多くの言語の機能に似たRustの機能の一部について議論しましょう。 From a6a4588e14327f4e002524b7220bb77d062fff22 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 13 Dec 2017 23:46:09 +0900 Subject: [PATCH 085/428] Fix some errors in the chapter 13-1 and revise it --- second-edition/src/ch13-01-closures.md | 40 +++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/second-edition/src/ch13-01-closures.md b/second-edition/src/ch13-01-closures.md index a7d931a5c..1bae85363 100644 --- a/second-edition/src/ch13-01-closures.md +++ b/second-edition/src/ch13-01-closures.md @@ -90,7 +90,7 @@ fn simulated_expensive_calculation(intensity: u32) -> u32 { * *ユーザの強弱値*、これはユーザがトレーニングを要求して、低強度のトレーニングか、 -高強度のトレーニングがしたいかを示します。 +高強度のトレーニングがしたいかを示したときに指定されます。 * *乱数*、これはトレーニングプランにバリエーションを起こします。 @@ -299,13 +299,13 @@ fn generate_workout(intensity: u32, random_number: u32) { この変更により`simulated_expensive_calculation`の呼び出しが単一化され、 -最初の`if`ブロックが無駄に関数を2回読んでいた問題を解消します。不幸なことに、これでは、 +最初の`if`ブロックが無駄に関数を2回呼んでいた問題を解消します。不幸なことに、これでは、 あらゆる場合にこの関数を呼び出し、その結果を待つことになり、結果値を全く使用しない内側の`if`ブロックでもそうしてしまいます。 -プログラムの1箇所でコードを定義したいですが、結果が本当に必要なコードだけを実行します。 +プログラムの1箇所でコードを定義したいですが、結果が本当に必要なところでコードを*実行*だけします。 これは、クロージャのユースケースです! @@ -320,7 +320,7 @@ fn generate_workout(intensity: u32, random_number: u32) { `if`ブロックの前にいつも`simulated_expensive_calculation`関数を呼び出す代わりに、 クロージャを定義し、結果を保存するのではなく、その*クロージャ*を変数に保存できます。リスト13-5のようにね。 -`simulated_expensive_calculation`の本体全体を実際に、ここで導入するクロージャ内に移すことができます: +`simulated_expensive_calculation`の本体全体を実際に、ここで導入しているクロージャ内に移すことができます: @@ -375,9 +375,11 @@ let expensive_closure = |num| { この`let`文は、`expensive_closure`が、匿名関数を呼び出した*結果の値*ではなく、 匿名関数の*定義*を含むことを意味することに注意してください。コードを定義して、 -1箇所で呼び出し、そのコードを保存し、後々、それを呼び出したくてクロージャを使用していることを思い出してください; +1箇所で呼び出し、そのコードを保存し、後々、それを呼び出したいためにクロージャを使用していることを思い出してください; 呼び出したいコードは、現在、`expensive_closure`に保存されています。 + + @@ -430,6 +432,8 @@ fn generate_workout(intensity: u32, random_number: u32) { リスト13-6: 定義した`expensive_closure`を呼び出す + + @@ -446,8 +450,10 @@ fn generate_workout(intensity: u32, random_number: u32) { ところが、リスト13-3の問題の一つを再浮上させてしまいました: それでも、最初の`if`ブロックでクロージャを2回呼んでいて、 そうすると、重いコードを2回呼び出し、必要な分の2倍ユーザを待たせてしまいます。その`if`ブロックのみに属する変数を生成して、 -クロージャの呼び出し結果を保持することでこの問題を解消することもできますが、クロージャは他の解決法も用意してくれます。 -その解決策については、もう少し先で語りましょう。でもまずは、クロージャ定義に型注釈がない理由とクロージャに関わるトレイトについて話しましょう。 +クロージャの呼び出し結果を保持するその`if`ブロックに固有の変数を生成することでこの問題を解消することもできますが、 +クロージャは他の解決法も用意してくれます。 +その解決策については、もう少し先で語りましょう。でもまずは、 +クロージャ定義に型注釈がない理由とクロージャに関わるトレイトについて話しましょう。 @@ -521,7 +527,7 @@ let expensive_closure = |num: u32| -> u32 { クロージャと関数の記法は、型注釈があると酷似して見えます。以下が、引数に1を加える関数の定義と、 同じ振る舞いをするクロージャの定義の記法を縦に比べたものです。 空白を追加して、関連のある部分を並べています。これにより、縦棒の使用と省略可能な記法の量を除いて、 -クロージャ記法が関数記法に似ているところが浮かび上がっています。 +クロージャ記法が関数記法に似ているところを具体化しています。 ```rust,ignore fn add_one_v1 (x: u32) -> u32 { x + 1 } @@ -553,7 +559,7 @@ let add_one_v4 = |x| x + 1 ; リスト13-8に引数として受け取った値を返すだけの短いクロージャの定義を示しました。 このクロージャは、この例での目的以外には有用ではありません。この定義には、 何も型注釈を加えていないことに注意してください: それから1回目に`String`を引数に、 -2回目に`u32`を引数に使用してクロージャを2回呼び出そうとしたら、エラーになります: +2回目に`u32`を引数に使用してこのクロージャを2回呼び出そうとしたら、エラーになります: @@ -607,7 +613,7 @@ error[E0308]: mismatched types -トレーニング生成アプリに戻りましょう。リスト13-6において、コードは必要以上の回数、重い計算のクロージャを呼んでいました。 +トレーニング生成アプリに戻りましょう。リスト13-6において、まだコードは必要以上の回数、重い計算のクロージャを呼んでいました。 この問題を解決する一つの選択肢は、重いクロージャの結果を再利用できるように変数に保存し、クロージャを再度呼ぶ代わりに、 結果が必要になる箇所それぞれで代わりにその変数を使用することです。しかしながら、この方法は同じコードの繰り返しになる可能性があります。 @@ -623,6 +629,8 @@ error[E0308]: mismatched types 結果を保存し、再利用する責任を負わなくて済むのです。このパターンは、*メモ化*(memoization)または、 *遅延実行*(lazy evaluation)として知っているかもしれません。 + + @@ -632,7 +640,7 @@ error[E0308]: mismatched types クロージャを保持する構造体を作成するために、クロージャの型を指定する必要があります。 構造体定義は、各フィールドの型を把握しておく必要がありますからね。各クロージャインスタンスには、 -独自の匿名の型があります: つまり、2つのクロージャが全く同じシグニチャでも、その型は違うものと考えられるということです。 +独自の匿名の型があります: つまり、2つのクロージャが全く同じシグニチャでも、その型はそれでも違うものと考えられるということです。 クロージャを使用する構造体、enum、関数引数を定義するには、第10章で議論したように、 ジェネリクスとトレイト境界を使用します。 @@ -682,8 +690,8 @@ struct Cacher -`Cacher`構造体には、ジェネリックな型の`T`の`calculation`フィールドがあります。`T`に関するトレイト境界は、 -`Fn`トレイトを使ったクロージャであると指定しています。`calculation`フィールドに保存したいクロージャは全て、 +`Cacher`構造体には、ジェネリックな型`T`の`calculation`フィールドがあります。`T`に関するトレイト境界は、 +`Fn`トレイトを使うことでクロージャであると指定しています。`calculation`フィールドに保存したいクロージャは全て、 1つの`u32`引数(`Fn`の後の括弧内で指定されている)を取り、`u32`(`->`の後に指定されている)を返さなければなりません。 @@ -893,7 +901,7 @@ fn generate_workout(intensity: u32, random_number: u32) { -値をキャッシュすることは、コードの他の部分でも異なるクロージャで行いたくなるかもしれない有用な振る舞いです。 +値をキャッシュすることは、コードの他の部分でも異なるクロージャで行いたくなるかもしれない一般的に有用な振る舞いです。 しかし、現在の`Cacher`の実装には、他の文脈で再利用することを困難にしてしまう問題が2つあります。 @@ -963,7 +971,7 @@ thread 'call_with_different_values' panicked at 'assertion failed: `(left == rig -現在の`Cacher`実装の2番目の問題は、引数の型に`u32`を取り、`u32`を返すクロージャしか受け付けないことです。 +現在の`Cacher`実装の2番目の問題は、引数の型に`u32`を一つ取り、`u32`を返すクロージャしか受け付けないことです。 例えば、文字列スライスを取り、`usize`を返すクロージャの結果をキャッシュしたくなるかもしれません。 この問題を解決するには、`Cacher`機能の柔軟性を向上させるためによりジェネリックな引数を導入してみてください。 @@ -1084,7 +1092,7 @@ error[E0434]: can't capture dynamic environment in a fn item; use the || { ... キャプチャした変数を消費するために、定義された際にクロージャはこれらの変数の所有権を奪い、 自身にムーブするのです。名前のうち、`Once`の部分は、 このクロージャは同じ変数の所有権を2回以上奪うことができないという事実を表しているので、1回しか呼ぶことができないのです。 -* `Fn`は、環境から値を不変で借用する。 +* `Fn`は、環境から値を不変で借用します。 * `FnMut`は、可変で値を借用するので、環境を変更することができます。 From 3fb168793e5d87f44caf83acc17787a9b56b1034 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 14 Dec 2017 19:11:23 +0900 Subject: [PATCH 086/428] Fix errors in the chapter 13-2 --- second-edition/src/ch13-02-iterators.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/second-edition/src/ch13-02-iterators.md b/second-edition/src/ch13-02-iterators.md index a78a22464..ad20453c6 100644 --- a/second-edition/src/ch13-02-iterators.md +++ b/second-edition/src/ch13-02-iterators.md @@ -296,7 +296,7 @@ and do nothing unless consumed -リスト13-17のコードは何もしません: 指定したクロージャは、決して呼ばれないのです。警告が理由に触れています: +リスト13-17のコードは何もしません; 指定したクロージャは、決して呼ばれないのです。警告が理由に触れています: イテレータアダプタは怠惰で、ここでイテレータを消費する必要があるのです。 @@ -337,7 +337,7 @@ assert_eq!(v2, vec![2, 3, 4]); -`map`はクロージャを取るので、各要素に対して行いどんな処理も指定することができます。 +`map`はクロージャを取るので、各要素に対して行いたいどんな処理も指定することができます。 これは、`Iterator`トレイトが提供する繰り返し動作を再利用しつつ、 クロージャによりある動作をカスタマイズできる好例になっています。 @@ -448,7 +448,7 @@ fn filters_by_size() { ベクタに対し、`iter`、`into_iter`、`iter_mut`を呼び出すことでイテレータを作成できることを示してきました。 ハッシュマップなどの標準ライブラリの他のコレクション型からもイテレータを作成できます。 -`Iterator`トレイトを自分で実装することで、したいことをどんなものでもするイテレータを作成することもできます。 +`Iterator`トレイトを自分で実装することで、したいことを何でもするイテレータを作成することもできます。 前述の通り、定義を提供する必要のある唯一のメソッドは、`next`メソッドなのです。一旦、そうしてしまえば、 `Iterator`トレイトが用意しているデフォルト実装のある他の全てのメソッドを使うことができるのです! @@ -457,7 +457,7 @@ fn filters_by_size() { -デモ用に、1から5をカウントするだけのイテレータを作成しましょう。まず、値を保持する構造体を生成し、 +デモ用に、1から5を絶対にカウントするだけのイテレータを作成しましょう。まず、値を保持する構造体を生成し、 `Iterator`トレイトを実装することでこの構造体をイテレータにし、その実装内の値を使用します。 @@ -607,8 +607,9 @@ fn calling_next_directly() { -このテストは、`counter`変数に新しい`Counter`インスタンスを生成し、それから`next`を繰り返し呼び出して、 -イテレータにほしい動作が実装し終わっていることを実証しています: 1から5の値を返すことです。 +このテストは、`counter`変数に新しい`Counter`インスタンスを生成し、 +それからイテレータにほしい動作が実装し終わっていることを実証しながら、`next`を繰り返し呼び出しています: +1から5の値を返すことです。 From 0684876d5734e3668b4a6c18039433c984cd1ee6 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 14 Dec 2017 20:09:08 +0900 Subject: [PATCH 087/428] Improve the chapter 13-3 --- .../src/ch13-03-improving-our-io-project.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/second-edition/src/ch13-03-improving-our-io-project.md b/second-edition/src/ch13-03-improving-our-io-project.md index 299e59a75..1be67c816 100644 --- a/second-edition/src/ch13-03-improving-our-io-project.md +++ b/second-edition/src/ch13-03-improving-our-io-project.md @@ -2,13 +2,16 @@ ## 入出力プロジェクトを改善する + + + -このイテレータに関する新しい知識があれば、第12章の入出力プロジェクトをイテレータを使用してコードのいろんな場所をより明確で簡潔にすることで、 -改善することができます。イテレータが`Config::new`関数と`search`関数の実装を改善する方法に目を向けましょう。 +このイテレータに関する新しい知識があれば、イテレータを使用してコードのいろんな場所をより明確で簡潔にすることで、 +第12章の入出力プロジェクトを改善することができます。イテレータが`Config::new`関数と`search`関数の実装を改善する方法に目を向けましょう。 @@ -61,10 +64,12 @@ impl Config { -引数に`args`に`String`要素のスライスがあるためにここで`clone`が必要だったのですが、 +引数`args`に`String`要素のスライスがあるためにここで`clone`が必要だったのですが、 `new`関数は`args`を所有していません。`Config`インスタンスの所有権を返すためには、 `Config`インスタンスがその値を所有できるように、`Config`の`query`と`filename`フィールドから値をクローンしなければなりませんでした。 + + @@ -150,7 +155,7 @@ fn main() { 次に、`Config::new`の定義を更新する必要があります。入出力プロジェクトの*src/lib.rs*ファイルで、 `Config::new`のシグニチャをリスト13-26のように変えましょう。関数本体を更新する必要があるので、 -これはそれでもコンパイルできません: +それでもコンパイルはできません: @@ -234,6 +239,8 @@ impl Config { リスト13-27: `Config::new`の本体をイテレータメソッドを使うように変更する + + @@ -291,8 +298,8 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { イテレータアダプタメソッドを使用して、このコードをもっと簡潔に書くことができます。そうすれば、 -可変な中間の`results`ベクタをなくすこともできます。関数型プログラミングスタイルは、可変な状態の量を最小化し、 -コードを明瞭化することを好みます。可変な状態を除去すると、検索を同時並行に行うという将来的な改善をするのが、 +可変な中間の`results`ベクタをなくすこともできます。関数型プログラミングスタイルは、可変な状態の量を最小化することを好み、 +コードを明瞭化します。可変な状態を除去すると、検索を同時並行に行うという将来的な改善をするのが、 簡単になるかもしれません。なぜなら、`results`ベクタへの同時アクセスを管理する必要がなくなるからです。 リスト13-29は、この変更を示しています: From 91072d2c00e76d6709cea62c0b2c76538175f34a Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 14 Dec 2017 20:21:15 +0900 Subject: [PATCH 088/428] Fix some errors in the chapter 13-4 --- second-edition/src/ch13-04-performance.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/second-edition/src/ch13-04-performance.md b/second-edition/src/ch13-04-performance.md index 04ae18028..0ef11d309 100644 --- a/second-edition/src/ch13-04-performance.md +++ b/second-edition/src/ch13-04-performance.md @@ -75,7 +75,7 @@ test bench_search_iter ... bench: 19,234,900 ns/iter (+/- 657,200) イテレータ連結をしてスコープにある3つの変数に計算を行っています: `buffer`というデータのスライス、 12の`coefficients`の配列、`qlp_shift`でデータをシフトする量です。この例の中で変数を宣言しましたが、 値は与えていません; このコードは、文脈の外では大して意味を持ちませんが、 -それでもRustが高レベルな概念を低レベルなコードに翻訳する簡潔で現実的な例になっています: +それでもRustが高レベルな考えを低レベルなコードに翻訳する簡潔で現実的な例になっています: ```rust,ignore let buffer: &mut [i32]; @@ -98,9 +98,9 @@ for i in 12..buffer.len() { -`prediction`の値を算出するには、このコードは、`coefficients`の12の値を繰り返し、`zip`メソッドを使用して、 -係数値を前の`buffer`の12の値と組にします。それから各組について、その値を足し合わせ、結果を全て合計し、 -合計のビットを`qlp_shift`分だけ右にシフトさせます。 +`prediction`の値を算出するために、このコードは、`coefficients`の12の値を繰り返し、`zip`メソッドを使用して、 +係数値を前の`buffer`の12の値と組にします。それから各組について、その値をかけ合わせ、結果を全て合計し、 +合計のビットを`qlp_shift`ビット分だけ右にシフトさせます。 @@ -129,7 +129,7 @@ for i in 12..buffer.len() { 係数は全てレジスタに保存されます。つまり、値に非常に高速にアクセスします。実行時に配列の境界チェックをすることもありません。 コンパイラが適用可能なこれらの最適化全てにより、結果のコードは究極的に効率化されます。このことがわかったので、 イテレータとクロージャを恐れなしに使用することができますね!それらのおかげでコードは、高レベルだけれども、 -そうすることに対して実行時のパフォーマンスを犠牲にしないようにします。 +そうすることに対して実行時のパフォーマンスを犠牲にしないようになります。 From 20925353592bd3f1c58955deafc434e0c649576f Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 8 Jan 2018 19:59:06 +0900 Subject: [PATCH 089/428] Made small changes in the chpaters 13-1 and 13-2 --- second-edition/src/ch13-01-closures.md | 2 +- second-edition/src/ch13-02-iterators.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/second-edition/src/ch13-01-closures.md b/second-edition/src/ch13-01-closures.md index 1bae85363..80b8c4ac5 100644 --- a/second-edition/src/ch13-01-closures.md +++ b/second-edition/src/ch13-01-closures.md @@ -305,7 +305,7 @@ fn generate_workout(intensity: u32, random_number: u32) { -プログラムの1箇所でコードを定義したいですが、結果が本当に必要なところでコードを*実行*だけします。 +プログラムの1箇所でコードを定義したいですが、結果が本当に必要なところでだけコードを*実行*します。 これは、クロージャのユースケースです! diff --git a/second-edition/src/ch13-02-iterators.md b/second-edition/src/ch13-02-iterators.md index ad20453c6..fa86f8065 100644 --- a/second-edition/src/ch13-02-iterators.md +++ b/second-edition/src/ch13-02-iterators.md @@ -303,7 +303,7 @@ and do nothing unless consumed -これを解消し、イテレータを消費するには、`collect`メソッドを使用し、これは第12章でちょっとだけ見かけました。 +これを解消し、イテレータを消費するには、`collect`メソッドを使用しますが、これは第12章でちょっとだけ見かけました。 このメソッドはイテレータを消費し、結果の値をコレクションデータ型に集結させます。 @@ -339,7 +339,7 @@ assert_eq!(v2, vec![2, 3, 4]); `map`はクロージャを取るので、各要素に対して行いたいどんな処理も指定することができます。 これは、`Iterator`トレイトが提供する繰り返し動作を再利用しつつ、 -クロージャによりある動作をカスタマイズできる好例になっています。 +クロージャにより一部の動作をカスタマイズできる好例になっています。 From 55f152bc424d2ccf1d2b2523b9658f495880c1ad Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 24 Jan 2018 23:09:39 +0900 Subject: [PATCH 090/428] First draft of the chapter 14-0 --- second-edition/src/SUMMARY.md | 19 ++++++--- .../src/ch14-00-more-about-cargo.md | 39 +++++++++++++------ 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index 04c704697..78b32034c 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -140,12 +140,19 @@ - [入出力プロジェクトを改善する](ch13-03-improving-our-io-project.md) - [パフォーマンス比較: ループVSイテレータ](ch13-04-performance.md) -- [More about Cargo and Crates.io](ch14-00-more-about-cargo.md) - - [Customizing Builds with Release Profiles](ch14-01-release-profiles.md) - - [Publishing a Crate to Crates.io](ch14-02-publishing-to-crates-io.md) - - [Cargo Workspaces](ch14-03-cargo-workspaces.md) - - [Installing Binaries from Crates.io with `cargo install`](ch14-04-installing-binaries.md) - - [Extending Cargo with Custom Commands](ch14-05-extending-cargo.md) + + + + + + + +- [CargoとCrates.ioについてより詳しく](ch14-00-more-about-cargo.md) + - [リリースプロファイルでビルドをカスタマイズする](ch14-01-release-profiles.md) + - [Crates.ioにクレートを公開する](ch14-02-publishing-to-crates-io.md) + - [Cargoのワークスペース](ch14-03-cargo-workspaces.md) + - [`cargo install`でCrates.ioからバイナリをインストールする](ch14-04-installing-binaries.md) + - [独自のコマンドでCargoで拡張する](ch14-05-extending-cargo.md) - [Smart Pointers](ch15-00-smart-pointers.md) - [`Box` Points to Data on the Heap and Has a Known Size](ch15-01-box.md) diff --git a/second-edition/src/ch14-00-more-about-cargo.md b/second-edition/src/ch14-00-more-about-cargo.md index c6e66ef12..6e21b8779 100644 --- a/second-edition/src/ch14-00-more-about-cargo.md +++ b/second-edition/src/ch14-00-more-about-cargo.md @@ -1,15 +1,30 @@ -# More About Cargo and Crates.io + -So far we’ve used only the most basic features of Cargo to build, run, and test -our code, but it can do a lot more. In this chapter, we’ll discuss some of its -other, more advanced features to show you how to: +# CargoとCrates.ioについてより詳しく -* Customize your build through release profiles -* Publish libraries on [crates.io](https://crates.io) -* Organize large projects with workspaces -* Install binaries from [crates.io](https://crates.io) -* Extend Cargo using custom commands + + + -Cargo can do even more than what we cover in this chapter, so for a full -explanation of all its features, see [its -documentation](https://doc.rust-lang.org/cargo/). +今までCargoのビルド、実行、コードのテストを行うという最も基礎的な機能のみを使ってきましたが、 +他にもできることはたくさんあります。この章では、そのような他のより高度な機能の一部を議論し、 +以下のことをする方法をお見せしましょう: + + + + + + + +* リリースプロファイルでビルドをカスタマイズする +* [crates.io](https://crates.io)でライブラリを公開する +* ワークスペースで巨大なプロジェクトを体系化する +* [crates.io](https://crates.io)からバイナリをインストールする +* 独自のコマンドを使用してCargoを拡張する + + + + + +また、Cargoはこの章で講義する以上のこともできるので、機能の全解説を見るには、 +[ドキュメンテーション](https://doc.rust-lang.org/cargo/)を参照されたし。 From be7f57addd2eae26145f9d2912c97b67957ebbd0 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Thu, 25 Jan 2018 21:48:51 +0900 Subject: [PATCH 091/428] First draft of the chapter 14-1 --- .../src/ch14-01-release-profiles.md | 118 ++++++++++++------ 1 file changed, 79 insertions(+), 39 deletions(-) diff --git a/second-edition/src/ch14-01-release-profiles.md b/second-edition/src/ch14-01-release-profiles.md index 4e4f4cd67..b7f95fba9 100644 --- a/second-edition/src/ch14-01-release-profiles.md +++ b/second-edition/src/ch14-01-release-profiles.md @@ -1,17 +1,29 @@ -## Customizing Builds with Release Profiles + -In Rust, *release profiles* are predefined and customizable profiles with -different configurations that allow a programmer to have more control over -various options for compiling code. Each profile is configured independently of -the others. +## リリースプロファイルでビルドをカスタマイズする -Cargo has two main profiles: the `dev` profile Cargo uses when you run `cargo -build` and the `release` profile Cargo uses when you run `cargo build ---release`. The `dev` profile is defined with good defaults for developing, and -the `release` profile has good defaults for release builds. + + + + -These profile names might be familiar from the output of your builds, which -shows the profile used in the build: +Rustにおいて、*リリースプロファイル*とは、プログラマがコードのコンパイルオプションについて制御可能な異なる設定を持つ、 +定義済みのカスタマイズ可能なプロファイルです。各プロファイルは、それぞれ個別で設定されます。 + + + + + + +Cargoには2つの主なプロファイルが存在します: `dev`プロファイルは、`cargo build`コマンドを実行したときに使用され、 +`release`プロファイルは、`cargo build --release`コマンドを実行したときに使用されます。 +`dev`プロファイルは、開発中に役に立つデフォルト設定がなされており、`release`プロファイルは、 +リリース用の設定がなされています。 + + + + +これらのプロファイル名は、ビルドの出力で馴染みのあるものかもしれず、この出力には、ビルドで使用されているプロファイルが表示されます: ```text $ cargo build @@ -20,16 +32,24 @@ $ cargo build --release Finished release [optimized] target(s) in 0.0 secs ``` -The `dev` and `release` shown in this build output indicate that the compiler -is using different profiles. + + + +このビルド出力で表示されている`dev`と`release`は、コンパイラが異なるプロファイルを使用していることを示しています。 + + + + + + -Cargo has default settings for each of the profiles that apply when there -aren’t any `[profile.*]` sections in the project’s *Cargo.toml* file. By adding -`[profile.*]` sections for any profile we want to customize, we can override -any subset of the default settings. For example, here are the default values -for the `opt-level` setting for the `dev` and `release` profiles: +プロジェクトの*Cargo.toml*ファイルに`[profile.*]`セクションが存在しない際に適用される各プロファイル用のデフォルト設定が、 +Cargoには存在します。カスタマイズしたいプロファイル用の`[profile.*]`セクションを追加することで、 +デフォルト設定の一部を上書きすることができます。例えば、こちらが`dev`と`release`プロファイルの`opt-level`設定のデフォルト値です: -Filename: Cargo.toml + + +ファイル名: Cargo.toml ```toml [profile.dev] @@ -39,32 +59,52 @@ opt-level = 0 opt-level = 3 ``` -The `opt-level` setting controls the number of optimizations Rust will apply to -your code with a range of zero to three. Applying more optimizations extends -compiling time, so if you’re in development and compiling your code often, you -want faster compiling even at the expense of the resulting code running slower. -That is the reason the default `opt-level` for `dev` is `0`. When you’re ready -to release your code, it’s best to spend more time compiling. You’ll only -compile in release mode once and run the compiled program many times, so -release mode trades longer compile time for code that runs faster. That is the -reason the default `opt-level` for the `release` profile is `3`. + + + + + + + + + + +`opt-level`設定は、0から3の範囲でコンパイラがコードに適用する最適化の度合いを制御します。 +最適化を多くかけると、コンパイル時間が延びるので、開発中に頻繁にコードをコンパイルするのなら、 +出力結果のコードの動作速度が遅くなるのと引き換えにでも早くコンパイルが済んでほしいですよね。 +これが、`dev`の`opt-level`のデフォルト設定が`0`になっている唯一の理由です。 +コードのリリース準備ができたら、より長い時間をコンパイルにかけるのが最善です。 +リリースモードでコンパイルするのはたった1回で、コンパイル結果のプログラムは何度も実行するので、 +リリースモードでは、長いコンパイル時間と引き換えに、生成したコードが速く動作します。 +これが`release`の`opt-level`のデフォルト設定が`3`になっている唯一の理由です。 + + + + + -We can override any default setting by adding a different value for it in -*Cargo.toml*. For example, if we want to use optimization level 1 in the -development profile, we can add these two lines to our project’s *Cargo.toml* -file: +デフォルト設定に対して`Cargo.toml`で異なる値を追加すれば、上書きすることができます。 +例として、開発用プロファイルで最適化レベル1を使用したければ、以下の2行をプロジェクトの*Cargo.toml*ファイルに追加できます: -Filename: Cargo.toml + + +ファイル名: Cargo.toml ```toml [profile.dev] opt-level = 1 ``` -This code overrides the default setting of `0`. Now when we run `cargo` -`build`, Cargo will use the defaults for the `dev` profile plus our -customization to `opt-level`. Because we set `opt-level` to `1`, Cargo will -apply more optimizations than the default, but not as many as a release build. + + + + + +このコードは、デフォルト設定の`0`を上書きします。こうすると、`cargo build`を実行したときに、 +`dev`プロファイル用のデフォルト設定に加えて、Cargoは`opt-level`の変更を適用します。 +`opt-level`を`1`に設定したので、Cargoはデフォルトよりは最適化を行いますが、リリースビルドほどではありません。 + + + -For the full list of configuration options and defaults for each profile, see -[Cargo’s documentation](https://doc.rust-lang.org/cargo/). +設定の選択肢と各プロファイルのデフォルト設定の一覧は、[Cargoのドキュメント](https://doc.rust-lang.org/cargo/)を参照されたし。 From cbadf236208c167cdee76ec0498afbf02cca1227 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 26 Jan 2018 20:00:45 +0900 Subject: [PATCH 092/428] First draft of the chapter 14-2 --- .../src/ch14-02-publishing-to-crates-io.md | 852 ++++++++++++------ 1 file changed, 574 insertions(+), 278 deletions(-) diff --git a/second-edition/src/ch14-02-publishing-to-crates-io.md b/second-edition/src/ch14-02-publishing-to-crates-io.md index 4a45ce076..0e8662edb 100644 --- a/second-edition/src/ch14-02-publishing-to-crates-io.md +++ b/second-edition/src/ch14-02-publishing-to-crates-io.md @@ -1,36 +1,62 @@ -## Publishing a Crate to Crates.io + -We’ve used packages from [crates.io](https://crates.io) as -dependencies of our project, but you can also share your code for other people -to use by publishing your own packages. The crate registry at -[crates.io](https://crates.io) distributes the source code of -your packages, so it primarily hosts code that is open source. +## Crates.ioにクレートを公開する -Rust and Cargo have features that help make your published package easier for -people to use and to find in the first place. We’ll talk about some of these -features next, and then explain how to publish a package. + + + + + -### Making Useful Documentation Comments +プロジェクトの依存ファイルとして[crates.io](https://crates.io)のパッケージを使用しましたが、 +自分のパッケージを公開することで他の人が使えるようにコードを共有することもできます。 +[crates.io](https://crates.io)のクレート登録所は、自分のパッケージのソースコードを配布するので、 +主にオープンソースのコードをホストします。 -Accurately documenting your packages will help other users know how and when to -use them, so it’s worth spending time writing documentation. In Chapter 3, we -discussed how to comment Rust code using `//`. Rust also has a particular kind -of comment for documentation, which is known conveniently as *documentation -comments*, that will generate HTML documentation. The HTML displays the -contents of documentation comments for public API items intended for -programmers interested in knowing how to *use* your crate as opposed to how -your crate is *implemented*. + + + -Documentation comments use `///` instead of `//` and support Markdown notation -for formatting the text if you want to use it. You place documentation comments -just before the item they’re documenting. Listing 14-1 shows documentation -comments for an `add_one` function in a crate named `my_crate`: +RustとCargoは、公開したパッケージを人が使用し、まず見つけやすくしてくれる機能を有しています。 +これらの機能の一部を次に語り、そして、パッケージの公開方法を説明します。 -Filename: src/lib.rs + + +### 役に立つドキュメンテーションコメントを行う + + + + + + + + + + +パッケージを正確にドキュメントすることで、他のユーザがパッケージを使用する方法や、いつ使用すべきかを理解する手助けをすることになるので、 +ドキュメンテーションを書くことに時間を費やす価値があります。第3章で、`//`でRustのコードにコメントをつける方法を議論しました。 +Rustには、ドキュメンテーション用のコメントも用意されていて、実質的に*ドキュメンテーションコメント*として知られ、 +HTMLドキュメントを生成します。クレートの*実装*法とは対照的にクレートの*使用*法を知ることに興味のあるプログラマ向けの、 +公開API用のドキュメンテーションコメントの中身をこのHTMLは表示します。 + + + + + + +ドキュメンテーションコメントは、`//`の代わりに`///`を使用し、使用する必要があれば、 +テキストを整形するMarkdown記法もサポートしています。ドキュメント対象の要素の直前にドキュメンテーションコメントを配置します。 +リスト14-1は、`my_crate`という名のクレートの`add_one`関数用のドキュメンテーションコメントを示しています: + + + +ファイル名: src/lib.rs ```rust,ignore /// Adds one to the number given. /// +/// 与えられた数値に1を足す。 +/// /// # Examples /// /// ``` @@ -43,58 +69,96 @@ pub fn add_one(x: i32) -> i32 { } ``` -Listing 14-1: A documentation comment for a -function - -Here, we give a description of what the `add_one` function does, start a -section with the heading `Examples`, and then provide code that demonstrates -how to use the `add_one` function. We can generate the HTML documentation from -this documentation comment by running `cargo doc`. This command runs the -`rustdoc` tool distributed with Rust and puts the generated HTML documentation -in the *target/doc* directory. - -For convenience, running `cargo doc --open` will build the HTML for your -current crate’s documentation (as well as the documentation for all of your -crate’s dependencies) and open the result in a web browser. Navigate to the -`add_one` function and you’ll see how the text in the documentation comments is -rendered, as shown in Figure 14-1: - -Rendered HTML documentation for the `add_one` function of `my_crate` - -Figure 14-1: HTML documentation for the `add_one` -function - -#### Commonly Used Sections - -We used the `# Examples` Markdown heading in Listing 14-1 to create a section -in the HTML with the title “Examples.” Some other sections that crate authors -commonly use in their documentation include: - -* **Panics**: The scenarios in which the function being documented could - `panic!`. Callers of the function who don’t want their programs to panic - should make sure they don’t call the function in these situations. -* **Errors**: If the function returns a `Result`, describing the kinds of - errors that might occur and what conditions might cause those errors to be - returned can be helpful to callers so they can write code to handle the - different kinds of errors in different ways. -* **Safety**: If the function is `unsafe` to call (we discuss unsafety in - Chapter 19), there should be a section explaining why the function is unsafe - and covering the invariants that the function expects callers to uphold. - -Most documentation comment sections don’t need all of these sections, but it’s -a good list to check to remind you of the aspects of your code that people -calling your code will be interested in knowing about. - -#### Documentation Comments as Tests - -Adding examples in code blocks in your documentation comments can clearly -demonstrate how to use your library, and doing so has an additional bonus: -running `cargo test` will run the code examples in your documentation as -tests! Nothing is better than documentation with examples. But nothing is worse -than examples that don’t work because the code has changed since the -documentation was written. Run `cargo test` with the documentation for the -`add_one` function from Listing 14-1; you should see a section in the test -results like this: + + + +リスト14-1: 関数のドキュメンテーションコメント + + + + + + + + +ここで、`add_one`関数がすることの説明を与え、`Examples`というタイトルでセクションを開始し、 +`add_one`関数の使用法を模擬するコードを提供しています。このドキュメンテーションコメントから`cargo doc`を実行することで、 +HTMLドキュメントを生成することができます。このコマンドはコンパイラとともに配布されている`rustdoc`ツールを実行し、 +生成されたHTMLドキュメントを*target/doc*ディレクトリに配置します。 + + + + + + + +利便性のために、`cargo doc --open`を走らせれば、現在のクレートのドキュメント用のHTML(と、 +自分のクレートの依存ファイル全てのドキュメント)を構築し、その結果をWebブラウザで開きます。 +`add_one`関数まで下り、図14-1に示したように、ドキュメンテーションコメントのテキストがどう描画されるかを確認しましょう: + + + +`my_crate`の`add_one`関数の描画済みのHTMLドキュメント + + + + +図14-1: `add_one`関数のHTMLドキュメント + + + +#### よく使われるセクション + + + + + +`# Examples`マークダウンのタイトルをリスト14-1で使用し、「例」というタイトルのセクションをHTMLに生成しました。 +これ以外にドキュメントでよく筆者が使用するセクションは: + + + + + + + + + + + + +* **Panics**: ドキュメント対象の関数が`panic!`する可能性のある筋書きです。プログラムをパニックさせたくない関数の使用者は、 +これらの状況で関数が呼ばれないことを確かめる必要があります。 +* **Errors**: 関数が`Result`を返すなら、起きうるエラーの種類とどんな条件がそれらのエラーを引き起こすのか解説すると、 +呼び出し側の役に立つので、いろんな方法で異なる種類のエラーを処理するコードを書くことができます。 +* **Safety**: 関数が呼び出すのに`unsafe`(非安全性については第19章で議論します)なら、 +関数が非安全な理由を説明し、関数が呼び出し元に保持していると期待する不変条件を講義するセクションがあるべきです。 + + + + + +多くのドキュメンテーションコメントのセクションでは、これら全てのセクションが必要になることはありませんが、 +自分のコードを呼び出している人が知りたいと思うコードの方向を思い出すときにチェックすべきいいリストになります。 + + + +#### テストとしてのドキュメンテーションコメント + + + + + + + + + + +ドキュメンテーションコメントのコードブロックに例を追加すると、ライブラリの使用方法がはっきりデモされ、 +おまけもついてきます: `cargo test`を走らせると、ドキュメントのコード例をテストとして実行するのです! +例付きのドキュメントに上回るものはありません。しかし、ドキュメントが書かれてからコードが変更されたがために、 +動かない例がついているよりも悪いものもありません。リスト14-1から`add_one`関数のドキュメンテーションとともに、 +`cargo test`を走らせてください; テスト結果に以下のような区域があるはずです: ```text Doc-tests my_crate @@ -105,24 +169,41 @@ test src/lib.rs - add_one (line 5) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Now change either the function or the example so the `assert_eq!` in the -example panics. Run `cargo test` again; you’ll see that the doc tests catch -that the example and the code are out of sync from one another! + + + + + + +さて、例の`assert_eq!`がパニックするように関数か例を変更してください。再度`cargo test`を実行してください; +docテストが例とコードがお互いに同期されていないことを捕捉するところを目撃するでしょう! + + + +#### 含まれている要素にコメントする -#### Commenting Contained Items + + + + + -Another style of doc comment, `//!`, adds documentation to the item that -contains the comments rather than adding documentation to the items following -the comments. We typically use these doc comments inside the crate root file -(*src/lib.rs* by convention) or inside a module to document the crate or the -module as a whole. +docコメントの別スタイル、`//!`は、コメントに続く要素にドキュメンテーションを付け加えるのではなく、 +コマンドを含む要素にドキュメンテーションを付け加えます。典型的には、クレートのルートファイル(規定では、*src/lib.rs*)内部や、 +モジュールの内部で使用して、クレートやモジュール全体にドキュメントをつけます。 -For example, if we want to add documentation that describes the purpose of the -`my_crate` crate that contains the `add_one` function, we can add documentation -comments that start with `//!` to the beginning of the *src/lib.rs* file, as -shown in Listing 14-2: + + + + -Filename: src/lib.rs +例えば、`add_one`関数を含む`my_crate`クレートの目的を解説するドキュメンテーションを追加したいのなら、 +`//!`で始まるドキュメンテーションコメントを*src/lib.rs*ファイルの先頭につけることができます。 +リスト14-2に示したようにね: + + + +ファイル名: src/lib.rs ```rust,ignore //! # My Crate @@ -130,71 +211,118 @@ shown in Listing 14-2: //! `my_crate` is a collection of utilities to make performing certain //! calculations more convenient. +//! #自分のクレート +//! +//! `my_crate`は、ユーティリティの集まりであり、特定の計算をより便利に行うことができます。 + /// Adds one to the number given. // --snip-- ``` -Listing 14-2: Documentation for the `my_crate` crate as a -whole + + + +リスト14-2: 全体として`my_crate`クレートにドキュメントをつける + + + + + + -Notice there isn’t any code after the last line that begins with `//!`. Because -we started the comments with `//!` instead of `///`, we’re documenting the item -that contains this comment rather than an item that follows this comment. In -this case, the item that contains this comment is the *src/lib.rs* file, which -is the crate root. These comments describe the entire crate. +`//!`で始まる最後の行以降には、コードが何もないことに気付いてください。`///`ではなく、`//!`でコメントを開始しているので、 +このコメントに続く要素ではなく、このコメントを含む要素にドキュメントをつけているわけです。 +今回の場合、このコメントを含む要素は*src/lib.rs*ファイルであり、クレートのルートです。 +これらのコメントは、クレート全体を解説しています。 -When we run `cargo doc --open`, these comments will display on the front -page of the documentation for `my_crate` above the list of public items in the -crate, as shown in Figure 14-2: + + + -Rendered HTML documentation with a comment for the crate as a whole +`cargo doc --open`を実行すると、これらのコメントは、`my_crate`のドキュメントの最初のページ、 +クレートの公開要素のリストの上部に表示されます。図14-2のようにね: -Figure 14-2: Rendered documentation for `my_crate` -including the comment describing the crate as a whole + -Documentation comments within items are useful for describing crates and -modules especially. Use them to explain the purpose of the container overall to -help your crate users understand your organization. +クレート全体のコメント付きの描画済みHTMLドキュメンテーション -### Exporting a Convenient Public API with `pub use` + + -In Chapter 7, we covered how to organize our code into modules using the `mod` -keyword, how to make items public using the `pub` keyword, and how to bring -items into a scope with the `use` keyword. However, the structure that makes -sense to you while you’re developing a crate might not be very convenient for -your users. You might want to organize your structs in a hierarchy containing -multiple levels, but people who want to use a type you’ve defined deep in the -hierarchy might have trouble finding out that those types exist. They might -also be annoyed at having to enter `use` -`my_crate::some_module::another_module::UsefulType;` rather than `use` -`my_crate::UsefulType;`. +図14-2: クレート全体を解説するコメントを含む`my_crate`の描画されたドキュメンテーション -The structure of your public API is a major consideration when publishing a -crate. People who use your crate are less familiar with the structure than you -are and might have difficulty finding the pieces they want to use if your crate -has a large module hierarchy. + + + -The good news is that if the structure *isn’t* convenient for others to use -from another library, you don’t have to rearrange your internal organization: -instead, you can re-export items to make a public structure that’s different -than your private structure by using `pub use`. Re-exporting takes a public -item in one location and makes it public in another location, as if it was -defined in the other location instead. +要素内のドキュメンテーションコメントは、特にクレートやモジュールを解説するのに有用です。 +コンテナ全体の目的を説明し、クレートの使用者が体系を理解する手助けをするのに使用してください。 -For example, say we made a library named `art` for modeling artistic concepts. -Within this library are two modules: a `kinds` module containing two enums -named `PrimaryColor` and `SecondaryColor`, and a `utils` module containing a -function named `mix`, as shown in Listing 14-3: + -Filename: src/lib.rs +### `pub use`で便利な公開APIをエクスポートする + + + + + + + + + + + + +第7章において、`mod`キーワードを使用してモジュールにコードを体系化する方法、`pub`キーワードで要素を公開にする方法、 +`use`キーワードで要素をスコープに導入する方法について講義しました。しかしながら、クレートの開発中に、 +自分にとって意味のある構造は、ユーザにはあまり便利ではない可能性があります。複数階層を含むヒエラルキーで、 +自分の構造体を体系化したくなるかもしれませんが、ヒエラルキーの深いところで定義した型を使用したい人は、 +それらの型が存在することを知るのに困難を伴う可能性もあります。また、そのような人は、 +`use my_crate::UsefulType`の代わりに`use my_crate::some_module::another_module::UsefulType;`と入力するのを煩わしく感じる可能性もあります。 + + + + + + +自分の公開APIの構造は、クレートを公開する際に考慮すべき点です。自分のクレートを使用したい人は、 +自分よりもその構造に馴染みがないですし、クレートのモジュール階層が大きければ、使用したい部分を見つけるのが困難になるかもしれません。 + + + + + + + + +嬉しいお知らせは、構造が他人が他のライブラリから使用するのに便利では*ない*場合、内部的な体系を再構築する必要はないということです: +代わりに、要素を再エクスポートし、`pub use`で自分の非公開構造とは異なる公開構造にできます。 +再エクスポートは、ある場所の公開要素を一つ取り、別の場所で定義されているかのように別の場所で公開します。 + + + + + + +例えば、芸術的な概念をモデル化するために`art`という名のライブラリを作ったとしましょう。 +このライブラリ内には、2つのモジュールがあります: `PrimaryColor`と`SecondaryColor`という名前の2つのeunmを含む、 +`kinds`モジュールと`mix`という関数を含む`utils`モジュールです。リスト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, @@ -202,6 +330,7 @@ pub mod kinds { } /// The secondary colors according to the RYB color model. + /// RYBカラーモデルによる副色 pub enum SecondaryColor { Orange, Green, @@ -214,33 +343,52 @@ 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-- } } ``` -Listing 14-3: An `art` library with items organized into -`kinds` and `utils` modules + + + +リスト14-3: `kinds`と`utils`モジュールに体系化される要素をふうむ`art`ライブラリ + + + -Figure 14-3 shows what the front page of the documentation for this crate -generated by `cargo doc` would look like: +図14-3は、`cargo doc`により生成されるこのクレートのドキュメンテーションの最初のページがどんな見た目になるか示しています: -Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules + -Figure 14-3: Front page of the documentation for `art` -that lists the `kinds` and `utils` modules +`kinds`と`utils`モジュールを列挙する`art`クレートの描画されたドキュメンテーション -Note that the `PrimaryColor` and `SecondaryColor` types aren’t listed on the -front page, nor is the `mix` function. We have to click `kinds` and `utils` to -see them. + + -Another crate that depends on this library would need `use` statements that -import the items from `art`, including specifying the module structure that’s -currently defined. Listing 14-4 shows an example of a crate that uses the -`PrimaryColor` and `mix` items from the `art` crate: +図14-3: `kinds`と`utils`モジュールを列挙する`art`のドキュメンテーションのトップページ -Filename: src/main.rs + + + + +`PrimaryColor`も`SecondaryColor`型も、`mix`関数もトップページには列挙されていないことに注意してください。 +`kinds`と`utils`をクリックすれば、参照することができます。 + + + + + + +このライブラリに依存する別のクレートは、現在定義されているモジュール構造を指定することも含めて、 +`art`の要素をインポートする`use`文が必要になるでしょう。リスト14-4は、 +`art`クレートから`PrimaryColor`と`mix`要素を使用するクレートの例を示しています: + + + + +ファイル名: src/main.rs ```rust,ignore extern crate art; @@ -255,25 +403,40 @@ fn main() { } ``` -Listing 14-4: A crate using the `art` crate’s items with -its internal structure exported + + + +リスト14-4: 内部構造もエクスポートされて`art`クレートの要素を使用するクレート -The author of the code in Listing 14-4, which uses the `art` crate, had to -figure out that `PrimaryColor` is in the `kinds` module and `mix` is in the -`utils` module. The module structure of the `art` crate is more relevant to -developers working on the `art` crate than developers using the `art` crate. -The internal structure that organizes parts of the crate into the `kinds` -module and the `utils` module doesn’t contain any useful information for -someone trying to understand how to use the `art` crate. Instead, the `art` -crate’s module structure causes confusion because developers have to figure out -where to look, and the structure is inconvenient because developers must -specify the module names in the `use` statements. + + + + + + + + + + -To remove the internal organization from the public API, we can modify the -`art` crate code in Listing 14-3 to add `pub use` statements to re-export the -items at the top level, as shown in Listing 14-5: +リスト14-4は`art`クレートを使用していますが、このコードの筆者は、`PrimaryColor`が`kinds`モジュールにあり、 +`mix`が`utils`モジュールにあることを割り出さなければなりませんでした。`art`クレートのモジュール構造は、 +`art`クレートの使用者よりも、`art`クレートに取り組む開発者などに関係が深いです。 +クレートの一部を`kinds`モジュールと`utils`モジュールに体系化する内部構造は、`art`クレートの使用方法を理解しようとする人には、 +何も役に立つ情報を含んでいません。代わりに、開発者がどこを見るべきか割り出す必要があるので、 +`art`クレートのモジュール構造は混乱を招き、また、開発者はモジュール名を`use`文で指定しなければならないので、 +この構造は不便です。 -Filename: src/lib.rs + + + + +公開APIから内部体系を除去するために、リスト14-3の`art`クレートコードを変更し、`pub use`文を追加して、 +最上位で要素を再エクスポートすることができます。リスト14-5みたいにね: + + + +ファイル名: src/lib.rs ```rust,ignore //! # Art @@ -293,23 +456,37 @@ pub mod utils { } ``` -Listing 14-5: Adding `pub use` statements to re-export -items + + + +リスト14-5: `pub use`文を追加して要素を再エクスポートする + + + + + +このクレートに対して`cargo doc`が生成するAPIドキュメンテーションは、これで図14-4のようにトップページに再エクスポートを列挙しリンクするので、 +`PrimaryColor`と`SecondaryColor`型と`mix`関数を見つけやすくしてくれます: -The API documentation that `cargo doc` generates for this crate will now list -and link re-exports on the front page, as shown in Figure 14-4, which makes the -`PrimaryColor` and `SecondaryColor` types and the `mix` function easier to find: + -Rendered documentation for the `art` crate with the re-exports on the front page +トップページに再エクスポートのある`art`クレートの描画されたドキュメンテーション -Figure 14-4: Front page of the documentation for `art` -that lists the re-exports + + -The `art` crate users can still see and use the internal structure from Listing -14-3 as demonstrated in Listing 14-4, or they can use the more convenient -structure in Listing 14-5, as shown in Listing 14-6: +図14-4: 再エクスポートを列挙する`art`のドキュメンテーションのトップページ -Filename: src/main.rs + + + + +`art`クレートのユーザは、それでも、リスト14-4にデモされているように、リスト14-3の内部構造を見て使用することもできますし、 +リスト14-5のより便利な構造を使用することもできます。リスト14-6に示したようにね: + + + +ファイル名: src/main.rs ```rust,ignore extern crate art; @@ -322,87 +499,143 @@ fn main() { } ``` -Listing 14-6: A program using the re-exported items from -the `art` crate + + + +リスト14-6: `art`クレートの再エクスポートされた要素を使用するプログラム + + + + + +ネストされたモジュールがたくさんあるような場合、最上位階層で`pub use`により型を再エクスポートすることは、 +クレートの使用者の経験に大きな違いを生みます。 + + + + + + + -In cases where there are many nested modules, re-exporting the types at the top -level with `pub use` can make a significant difference in the experience of -people who use the crate. +役に立つAPI構造を作ることは、科学というよりも芸術の領域であり、ユーザにとって何がベストのAPIなのか、 +探求するために繰り返してみることが出来ます。`pub use`は、内部的なクレート構造に柔軟性をもたらし、 +その内部構造とユーザに提示する構造を切り離してくれます。インストールしてある他のクレートを見て、 +内部構造が公開APIと異なっているか確認してみてください。 -Creating a useful public API structure is more of an art than a science, and -you can iterate to find the API that works best for your users. Choosing `pub` -`use` gives you flexibility in how you structure your crate internally and -decouples that internal structure with what you present to your users. Look at -some of the code of crates you’ve installed to see if their internal structure -differs from their public API. + -### Setting Up a Crates.io Account +### Crates.ioのアカウントをセットアップする -Before you can publish any crates, you need to create an account on -[crates.io](https://crates.io) and get an API token. To do so, -visit the home page at [crates.io](https://crates.io) and log in -via a GitHub account: the GitHub account is currently a requirement, but the -site might support other ways of creating an account in the future. Once you’re -logged in, visit your account settings at -[https://crates.io/me/](https://crates.io/me/) and retrieve your -API key. Then run the `cargo` `login` command with your API key, like this: + + + + + + + + + +クレートを公開する前に、[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 $ 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). + + + + + +このコマンドは、CargoにAPIトークンを知らせ、*~/.cargo/credentials*にローカルに保存します。 +このトークンは、*秘密*です: 他人とは共有しないでください。なんらかの理由で他人と共有してしまったら、 +古いものを破棄して[crates.io](https://crates.io)で新しいトークンを生成するべきです。 + + + +### 新しいクレートを公開する前に + + + + + +アカウントはできたので、公開したいクレートがあるとしましょう。公開前に、 +*Cargo.toml*ファイルの`[package]`セクションに追加することでクレートにメタデータを追加する必要があるでしょう。 -### Before Publishing a New Crate + + + + + + + -Now that you have an account, let’s say you have a crate you want to publish. -Before publishing, you’ll need to add some metadata to your crate by adding it -to the `[package]` section of the crate’s *Cargo.toml* file. +クレートには、独自の名前が必要でしょう。クレートをローカルで作成している間、 +クレートの名前はなんでもいい状態でした。ところが、[crates.io](https://crates.io)のクレート名は、 +最初に来たもの勝ちの精神で付与されていますので、一旦クレート名が取られてしまったら、 +その名前のクレートを他の人が公開することは絶対できません。もう使われているか、 +サイトで使いたい名前を検索してください。まだなら、*Cargo.toml*ファイルの`[package]`以下の名前を編集して、 +名前を公開用に使ってください。以下のように: -Your crate will need a unique name. While you’re working on a crate locally, -you can name a crate whatever you’d like. However, crate names on -[crates.io](https://crates.io) are allocated on a first-come, -first-served basis. Once a crate name is taken, no one else can publish a crate -with that name. Search for the name you want to use on the site to find out if -it has been used. If it hasn’t, edit the name in the *Cargo.toml* file under -`[package]` to use the name for publishing, like so: + -Filename: Cargo.toml +ファイル名: Cargo.toml ```toml [package] name = "guessing_game" ``` -Even if you’ve chosen a unique name, when you run `cargo publish` to publish -the crate at this point, you’ll get a warning and then an error: + + + +たとえ、独自の名前を選択していたとしても、この時点で`cargo publish`を実行すると、警告とエラーが出ます: ```text $ cargo publish Updating registry `https://github.com/rust-lang/crates.io-index` warning: manifest has no description, license, license-file, documentation, homepage or repository. +(警告: マニフェストに説明、ライセンス、ライセンスファイル、ドキュメンテーション、ホームページ、 +リポジトリのいずれかがありません) --snip-- error: api errors: missing or empty metadata fields: description, license. +(エラー: APIエラー: 存在しないメタデータフィールド: description, license) ``` -The reason is that you’re missing some crucial information: a description and -license are required so people will know what your crate does and under what -terms they can use it. To rectify this error, you need to include this -information in the *Cargo.toml* file. + + + + + +原因は、大事な情報を一部入れていないからです: 説明とライセンスは、 +他の人が自分のクレートは何をし、どんな条件の元で使っていいのかを知るために必要なのです。 +このエラーを解消するには、*Cargo.toml*ファイルにこの情報を入れ込む必要があります。 + + + + + + + + + -Add a description that is just a sentence or two, because it will appear with -your crate in search results. For the `license` field, you need to give a -*license identifier value*. The Linux Foundation’s Software Package Data -Exchange (SPDX) at *http://spdx.org/licenses/* lists the identifiers you can -use for this value. For example, to specify that you’ve licensed your crate -using the MIT License, add the `MIT` identifier: +1文か2文程度の説明をつけてください。これは、検索結果に表示されますからね。 +`license`フィールドには、*ライセンス識別子*を与える必要があります。 +*http://spdx.org/licenses/*のLinux団体のSoftware Package Data Exchange(SPDX)に、 +この値に使用できる識別子が列挙されています。例えば、自分のクレートをMITライセンスでライセンスするためには、 +`MIT`識別子を追加してください: -Filename: Cargo.toml + + +ファイル名: Cargo.toml ```toml [package] @@ -410,22 +643,36 @@ name = "guessing_game" license = "MIT" ``` -If you want to use a license that doesn’t appear in the SPDX, you need to place -the text of that license in a file, include the file in your project, and then -use `license-file` to specify the name of that file instead of using the -`license` key. + + + + + +SPDXに出現しないライセンスを使用したい場合、そのライセンスをファイルに配置し、 +プロジェクトにそのファイルを含め、それから`license`キーを使う代わりに、 +そのファイルの名前を指定するのに`license-file`を使う必要があります。 + + + + + + -Guidance on which license is appropriate for your project is beyond the scope -of this book. Many people in the Rust community license their projects in the -same way as Rust by using a dual license of `MIT OR Apache-2.0`, which -demonstrates that you can also specify multiple license identifiers separated -by `OR` to have multiple licenses for your project. +どのライセンスが自分のプロジェクトに()(さわ)しいというガイドは、 +この本の範疇を超えています。Rustコミュニティの多くの人間は、`MIT OR Apache-2.0`のデュアルライセンスを使用することで、 +Rust自体と同じようにプロジェクトをライセンスし、これは、`OR`で区切られる複数のライセンス識別子を指定して、 +プロジェクトに複数のライセンスを持たせることもできることを模擬しています。 -With a unique name, the version, the author details that `cargo new` added -when you created the crate, your description, and a license added, the -*Cargo.toml* file for a project that is ready to publish might look like this: + + + -Filename: Cargo.toml +独自の名前、バージョン、クレート作成時に`cargo new`が追加した筆者の詳細、説明、ライセンスが追加され、 +公開準備のできたプロジェクト用の`Cargo.toml`ファイルは以下のような見た目になっているかもしれません: + + + +ファイル名: Cargo.toml ```toml [package] @@ -433,31 +680,49 @@ name = "guessing_game" version = "0.1.0" authors = ["Your Name "] description = "A fun game where you guess what number the computer has chosen." + (コンピュータが選択した数字を言い当てる面白いゲーム) license = "MIT OR Apache-2.0" [dependencies] ``` -[Cargo’s documentation](https://doc.rust-lang.org/cargo/) describes other -metadata you can specify to ensure others can discover and use your crate more -easily! + + + + +[Cargoのドキュメンテーション](https://doc.rust-lang.org/cargo)には、 +指定して他人がより容易く発見しクレートを使用できる他のメタデータが解説されています。 + + + +### Crates.ioに公開する + + + + + -### Publishing to Crates.io +アカウントを作成し、APIトークンを保存し、クレートの名前を決め、必要なメタデータを指定したので、 +公開する準備が整いました!クレートを公開すると、特定のバージョンが、 +[crates.io](http://crates.io)に他の人が使用できるようにアップロードされます。 -Now that you’ve created an account, saved your API token, chosen a name for -your crate, and specified the required metadata, you’re ready to publish! -Publishing a crate uploads a specific version to -[crates.io](https://crates.io) for others to use. + + + + + + + -Be careful when publishing a crate because a publish is *permanent*. The -version can never be overwritten, and the code cannot be deleted. One major -goal of [crates.io](https://crates.io) is to act as a permanent -archive of code so that builds of all projects that depend on crates from -[crates.io](https://crates.io) will continue to work. Allowing -version deletions would make fulfilling that goal impossible. However, there is -no limit to the number of crate versions you can publish. +公開は*永久*なので、クレートの公開時には気をつけてください。バージョンは絶対に上書きできず、 +コードも削除できません。[crates.io](https://crates.io)の一つの主な目標が、 +[crates.io](https://crates.io)のクレートに依存している全てのプロジェクトのビルドが、 +動き続けるようにコードの永久アーカイブとして機能することなのです。バージョン削除を可能にしてしまうと、 +その目標を達成するのが不可能になってしまいます。ですが、公開できるクレートバージョンの数には制限はありません。 -Run the `cargo publish` command again. It should succeed now: + + +再度`cargo publish`コマンドを実行してください。今度は成功するはずです: ```text $ cargo publish @@ -470,46 +735,77 @@ Compiling guessing_game v0.1.0 Uploading guessing_game v0.1.0 (file:///projects/guessing_game) ``` -Congratulations! You’ve now shared your code with the Rust community, and -anyone can easily add your crate as a dependency of their project. + + + +おめでとうございます!Rustコミュニティとコードを共有し、誰でも自分のクレートを依存ファイルとして簡単に追加できます。 + + -### Publishing a New Version of an Existing Crate +### 既存のクレートの新バージョンを公開する -When you’ve made changes to your crate and are ready to release a new version, -you change the `version` value specified in your *Cargo.toml* file and -republish. Use the [Semantic Versioning rules][semver] to decide what an -appropriate next version number is based on the kinds of changes you’ve made. -Then run `cargo publish` to upload the new version. + + + + + + +クレートに変更を行い、新バージョンをリリースする準備ができたら、 +*Cargo.toml*ファイルに指定された`version`の値を変更し、再公開します。 +[意味論バージョンルール][semver]を使用して加えた変更の種類に基づいて次の適切なバージョン番号を決定してください。 +そして、`cargo publish`を実行し、新バージョンをアップロードします。 [semver]: http://semver.org/ -### Removing Versions from Crates.io with `cargo yank` + + +### `cargo yank`でCrates.ioからバージョンを削除する + + -Although you can’t remove previous versions of a crate, you can prevent any -future projects from adding them as a new dependency. This is useful when a -crate version is broken for one reason or another. In such situations, Cargo -supports *yanking* a crate version. + + + + -Yanking a version prevents new projects from starting to depend on that version -while allowing all existing projects that depend on it to continue to download -and depend on that version. Essentially, a yank means that all projects with a -*Cargo.lock* will not break, and any future *Cargo.lock* files generated will -not use the yanked version. +以前のバージョンのクレートを削除することはできないものの、新しい依存ファイルとして将来的にプロジェクトに追加することを防ぐことはできます。 +ある理由により、クレートバージョンが壊れている場合に有用です。そのような場面において、 +Cargoはクレートバージョンの*取り下げ*をサポートしています。 -To yank a version of a crate, run `cargo yank` and specify which version you -want to yank: + + + + + + + + +バージョンを取り下げると、他の既存のプロジェクトには、引き続きダウンロードし、そのバージョンに依存させ続けつつ、 +新規プロジェクトが新しくそのバージョンに依存しだすことを防ぎます。本質的に取り下げは、 +*Cargo.lock*が存在するプロジェクトは全て壊れず、将来的に*Cargo.lock*ファイルが生成されるものは、 +取り下げられたバージョンを使わないことを意味するのです。 + + + + +あるバージョンのクレートを取り下げるには、`cargo yank`を実行し、取り下げたいバージョンを指定します: ```text $ cargo yank --vers 1.0.1 ``` -By adding `--undo` to the command, you can also undo a yank and allow projects -to start depending on a version again: + + + +`--undo`をコマンドに付与することで、取り下げを取り消し、再度あるバージョンにプロジェクトを依存させ始めることもできます: ```text $ cargo yank --vers 1.0.1 --undo ``` -A yank *does not* delete any code. For example, the yank feature is not -intended for deleting accidentally uploaded secrets. If that happens, you must -reset those secrets immediately. + + + + +取り下げは、コードの削除は一切し*ません*。例として、取り下げ機能は、誤ってアップロードされた秘密鍵を削除するためのものではありません。 +もしそうなってしまったら、即座に秘密鍵をリセットしなければなりません。 From 5660955f3f4c68875e83792b8f49fbefa38fb075 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 26 Jan 2018 22:38:44 +0900 Subject: [PATCH 093/428] First draft of the chapter 14-3 --- .../src/ch14-03-cargo-workspaces.md | 373 ++++++++++++------ 1 file changed, 253 insertions(+), 120 deletions(-) diff --git a/second-edition/src/ch14-03-cargo-workspaces.md b/second-edition/src/ch14-03-cargo-workspaces.md index cc885e233..ad4ea8bb7 100644 --- a/second-edition/src/ch14-03-cargo-workspaces.md +++ b/second-edition/src/ch14-03-cargo-workspaces.md @@ -1,34 +1,54 @@ -## Cargo Workspaces - -In Chapter 12, we built a package that included a binary crate and a library -crate. As your project develops, you might find that the library crate -continues to get bigger and you want to split up your package further into -multiple library crates. In this situation, Cargo offers a feature called -*workspaces* that can help manage multiple related packages that are developed -in tandem. - -A *workspace* is a set of packages that share the same *Cargo.lock* and output -directory. Let’s make a project using a workspace and use trivial code so we -can concentrate on the structure of the workspace. There are multiple ways to -structure a workspace; we’re going to show a common way. We’ll have a workspace -containing a binary and two libraries. The binary will provide the main -functionality to be used as a command line tool, and it will depend on the two -libraries. One library will provide an `add_one` function, and a second library -will provide an `add_two` function. These three crates will be part of the same -workspace. We’ll start by creating a new directory for the workspace: + + +## Cargoのワークスペース + + + + + + + + +第12章で、バイナリクレートとライブラリクレートを含むパッケージを構築しました。プロジェクトの開発が進むにつれて、 +ライブラリクレートの肥大化が続き、さらに複数のライブラリクレートにパッケージを分割したくなります。 +この場面において、Cargoは*ワークスペース*という協調して開発された関連のある複数のパッケージを管理するのに役立つ機能を提供しています。 + + + + + + + + + + + +*ワークスペース*は、同じ*Cargo.lock*と出力ディレクトリを共有する一連のパッケージです。 +ワークスペースを使用したプロジェクトを作成し、ワークスペースの構造に集中できるよう、瑣末なコードを使用しましょう。 +ワークスペースを構築する方法は複数あります; 一般的な方法を提示しましょう。バイナリ1つとライブラリ2つを持つワークスペースを作ります。 +バイナリは、コマンドラインツールとして使用される主要な機能を提供し、2つのライブラリに依存しています。 +一方のライブラリは、`add_one`関数を提供し、2番目のライブラリは、`add_two`関数を提供します。 +これら3つのクレートが同じワークスペースの一部になります。ワークスペース用の新しいディレクトリを作ることから始めましょう: ```text $ mkdir add $ cd add ``` -In the *add* directory, create a *Cargo.toml* file. This is the *Cargo.toml* -file that configures the entire workspace. It won’t have a `[package]` section -or metadata we’ve seen in other *Cargo.toml* files. Instead, we’ll start with a -`[workspace]` section and add a member to the workspace by specifying the path -*adder*, which is where we’ll put our binary crate: + + + + + -Filename: Cargo.toml +*add*ディレクトリで*Cargo.toml*ファイルを作成してください。これがワークスペース全体を設定する*Cargo.toml*ファイルになります。 +他の*Cargo.toml*ファイルで見かけるような`[package]`セクションやメタデータはありません。 +代わりに`[workspace]`セクションを開始し、*adder*というパスを指定することでワークスペースのメンバを追加し、 +このディレクトリにバイナリクレートを配置します: + + + +ファイル名: Cargo.toml ```toml [workspace] @@ -38,16 +58,21 @@ members = [ ] ``` -Next, we’ll create the `adder` binary crate by running `cargo new` within the -*add* directory: + + + +次に、*add*ディレクトリ内で`cargo new`を実行することで`adder`バイナリクレートを作成しましょう: ```text $ cargo new --bin adder Created binary (application) `adder` project ``` -At this point, we can build the workspace by running `cargo build`. The files -in your *add* directory should look like this: + + + +この時点で、`cargo build`を走らせるとワークスペースを構築できます。*add*ディレクトリに存在するファイルは、 +以下のようになるはずです: ```text ├── Cargo.lock @@ -59,23 +84,38 @@ in your *add* directory should look like this: └── target ``` -The workspace has one *target* directory at the top level; the `adder` crate -doesn’t have its own *target* directory. Even if we go into the *adder* -directory and run `cargo build`, the compiled artifacts end up in -*add/target* rather than *add/adder/target*. The crates in a workspace are -meant to depend on each other. If each crate had its own *target* directory, -each crate in the workspace would have to recompile each of the other crates in -the workspace to have the artifacts in its own *target* directory. By sharing -one *target* directory, the crates in the workspace can avoid rebuilding the -other crates in the workspace more than necessary. + + + + + + + + + + +ワークスペースには、最上位に*ターゲット*のディレクトリがあります; `adder`クレートには*ターゲット*ディレクトリはありません。 +*adder*ディレクトリに潜って`cargo build`を走らせても、コンパイルされる生成物は、 +*add/adder/target*ではなく、*add/target*に生成されます。ワークスペースのクレートは、 +お互いに依存しあうことを意味します。各クレートが*ターゲット*ディレクトリを持っていたら、 +ワークスペースの各クレートがワークスペースの他のクレートを再コンパイルし、 +*ターゲット*ディレクトリに生成物がある状態にしなければならないでしょう。一つの*ターゲット*ディレクトリを共有することで、 +ワークスペースのクレートは必要以上にワークスペースの他のクレートを再構築することを回避できるのです。 -### Creating the Second Crate in the Workspace + -Next, let’s specify another member crate in the workspace. This crate will be -in the *add-one* directory, so change the top-level *Cargo.toml* to have the -*add-one* path as well: +### ワークスペース内に2番目のクレートを作成する -Filename: Cargo.toml + + + + +次に、ワークスペースに別のメンバクレートを指定しましょう。このクレートは*add-one*ディレクトリに存在することになるので、 +最上位の*Cargo.toml*を変更して、*add-one*パスも存在するようにします: + + + +ファイル名: Cargo.toml ```toml [workspace] @@ -86,14 +126,18 @@ members = [ ] ``` -Then generate a new library crate named `add-one`: + + +それから、`add-one`という名前のライブラリクレートを生成してください: ```text $ cargo new add-one Created library `add-one` project ``` -Your *add* directory should now have these directories and files: + + +これで*add*ディレクトリには、以下のディレクトリやファイルが存在するはずです: ```text ├── Cargo.lock @@ -109,9 +153,13 @@ Your *add* directory should now have these directories and files: └── target ``` -In the *add-one/src/lib.rs* file, let’s add an `add_one` function: + -Filename: add-one/src/lib.rs +*add-one/src/lib.rs*ファイルに`add_one`関数を追加しましょう: + + + +ファイル名: add-one/src/lib.rs ```rust pub fn add_one(x: i32) -> i32 { @@ -119,11 +167,16 @@ pub fn add_one(x: i32) -> i32 { } ``` -Now that we have a library crate in the workspace, let’s have the binary crate -`adder` depend on the library crate `add-one`. First, we’ll need to add a path -dependency on `add-one` to *adder/Cargo.toml*: + + + + +ワークスペースにライブラリクレートが存在するようになったので、バイナリクレート`adder`がライブラリクレートの`add-one`に依存するようにしましょう。 +まず、`add-one`へのパス依存を*adder/Cargo.toml*に追加する必要があります: -Filename: adder/Cargo.toml + + +ファイル名: adder/Cargo.toml ```toml [dependencies] @@ -131,30 +184,44 @@ dependency on `add-one` to *adder/Cargo.toml*: add-one = { path = "../add-one" } ``` -Crates in a workspace don’t have to depend on each other, so we still need to -be explicit about the dependency relationships between the crates in a -workspace. + + + + +ワークスペースのクレートは、お互いに依存している必要はないので、それでも、 +ワークスペースのクレート間の依存関係について明示する必要があります。 -Next, let’s use the `add_one` function from the `add-one` crate in the `adder` -crate. Open the *adder/src/main.rs* file and add an `extern crate` line at -the top to bring the new `add-one` library crate into scope. Then change the -`main` function to call the `add_one` function, as in Listing 14-7: + + + + -Filename: adder/src/main.rs +次に、`adder`クレートの`add-one`クレートから`add_one`関数を使用しましょう。*adder/src/main.rs*ファイルを開き、 +冒頭に`extern crate`行を追加して新しい`add-one`ライブラリクレートをスコープに導入してください。 +それから`main`関数を変更し、`add_one`関数を呼び出します。リスト14-7のようにね: + + + +ファイル名: adder/src/main.rs ```rust,ignore extern crate add_one; fn main() { let num = 10; + // こんにちは世界!{}+1は{}! println!("Hello, world! {} plus one is {}!", num, add_one::add_one(num)); } ``` -Listing 14-7: Using the `add-one` library crate from the -`adder` crate + + + +リスト14-7: `adder`クレートから`add-one`ライブラリクレートを使用する + + -Let’s build the workspace by running `cargo build` in the *add* directory! +*add*ディレクトリで`cargo build`を実行することでワークスペースをビルドしましょう! ```text $ cargo build @@ -163,9 +230,12 @@ $ cargo build Finished dev [unoptimized + debuginfo] target(s) in 0.68 secs ``` -To run the binary crate from the top-level *add* directory, we need to specify -which package in the workspace we want to use by using the `-p` argument and -the package name with `cargo run`: + + + + +最上位の*add*ディレクトリからバイナリクレートを実行するには、`-p`引数とパッケージ名を`cargo run`と共に使用して、 +使用したいワークスペースのパッケージを指定する必要があります: ```text $ cargo run -p adder @@ -174,22 +244,38 @@ $ cargo run -p adder Hello, world! 10 plus one is 11! ``` -This runs the code in *adder/src/main.rs*, which depends on the `add-one` crate. + + +これにより、*adder/src/main.rs*のコードが実行され、これは`add_one`クレートに依存しています。 + + + +#### ワークスペースの外部クレートに依存する + + + + + + + + + + + -#### Depending on an External Crate in a Workspace +ワークスペースには、各クレートのディレクトリそれぞれに*Cargo.lock*が存在するのではなく、 +ワークスペースの最上位階層にただ一つの*Cargo.lock*が存在するだけのことに注目してください。 +これにより、全クレートが全依存ファイルの同じバージョンを使用していることが確認されます。 +`rand`クレートを*adder/Cargo.toml*と*add-one/Cargo.toml*ファイルに追加すると、 +Cargoは両者をあるバージョンの`rand`に解決し、それを一つの*Cargo.lock*に記録します。 +ワークスペースの全クレートに同じ依存ファイルを使用させるということは、 +ワークスペースのクレートが相互に互換性を常に維持するということになります。 +*add-one/Cargo.toml*ファイルの`[dependencies]`セクションに`rand`クレートを追加して、 +`add-one`クレートで`rand`クレートを使用できます: -Notice that the workspace has only one *Cargo.lock* file at the top level of -the workspace rather than having a *Cargo.lock* in each crate’s directory. This -ensures that all crates are using the same version of all dependencies. If we -add the `rand` crate to the *adder/Cargo.toml* and *add-one/Cargo.toml* -files, Cargo will resolve both of those to one version of `rand` and record -that in the one *Cargo.lock*. Making all crates in the workspace use the same -dependencies means the crates in the workspace will always be compatible with -each other. Let’s add the `rand` crate to the `[dependencies]` section in the -*add-one/Cargo.toml* file to be able to use the `rand` crate in the `add-one` -crate: + -Filename: add-one/Cargo.toml +ファイル名: add-one/Cargo.toml ```toml [dependencies] @@ -197,9 +283,13 @@ crate: rand = "0.3.14" ``` -We can now add `extern crate rand;` to the *add-one/src/lib.rs* file, and -building the whole workspace by running `cargo build` in the *add* directory -will bring in and compile the `rand` crate: + + + + +これで、*add-one/src/lib.rs*ファイルに`extern crate rand;`を追加でき、 +*add*ディレクトリで`cargo build`を実行することでワークスペース全体をビルドすると、 +`rand`クレートを持ってきてコンパイルするでしょう: ```text $ cargo build @@ -212,38 +302,57 @@ $ cargo build Finished dev [unoptimized + debuginfo] target(s) in 10.18 secs ``` -The top-level *Cargo.lock* now contains information about the dependency of -`add-one` on `rand`. However, even though `rand` is used somewhere in the -workspace, we can’t use it in other crates in the workspace unless we add -`rand` to their *Cargo.toml* files as well. For example, if we add `extern -crate rand;` to the *adder/src/main.rs* file for the `adder` crate, we’ll get -an error: + + + + + + + +さて、最上位の*Cargo.lock*は、`rand`に対する`add-one`の依存の情報を含むようになりました。 +ですが、`rand`はワークスペースのどこかで使用されているにも関わらず、それぞれの*Cargo.toml*ファイルにも、 +`rand`を追加しない限り、ワークスペースの他のクレートでそれを使用することはできません。 +例えば、`adder`クレートの*adder/src/main.rs*ファイルに`extern crate rand;`を追加すると、 +エラーが出ます: ```text $ cargo build 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 | 1 | extern crate rand; ``` -To fix this, edit the *Cargo.toml* file for the `adder` crate and indicate that -`rand` is a dependency for that crate as well. Building the `adder` crate will -add `rand` to the list of dependencies for `adder` in *Cargo.lock*, but no -additional copies of `rand` will be downloaded. Cargo has ensured that any -crate in the workspace using the `rand` crate will be using the same version. -Using the same version of `rand` across the workspace saves space because we -won’t have multiple copies and ensures that the crates in the workspace will be -compatible with each other. + + + + + + + + + +これを修正するには、`adder`クレートの*Cargo.toml*ファイルを編集し、同様に`rand`がそのクレートの依存ファイルであることを示してください。 +`adder`クレートをビルドすると、`rand`を*Cargo.lock*の`adder`の依存ファイル一覧に追加しますが、 +`rand`のファイルが追加でダウンロードされることはありません。Cargoが、ワークスペースの`rand`を使用するどのクレートも、 +同じバージョンを使っていることを確かめてくれるのです。ワークスペース全体で`rand`の同じバージョンを使用することにより、 +複数のコピーが存在しないのでスペースを節約し、ワークスペースのクレートが相互に互換性を維持することを確かめます。 + + + +#### ワークスペースにテストを追加する -#### Adding a Test to a Workspace + + -For another enhancement, let’s add a test of the `add_one::add_one` function -within the `add_one` crate: +さらなる改善として、`add_one`クレート内に`add_one::add_one`関数のテストを追加しましょう: -Filename: add-one/src/lib.rs + + +ファイル名: add-one/src/lib.rs ```rust pub fn add_one(x: i32) -> i32 { @@ -261,7 +370,9 @@ mod tests { } ``` -Now run `cargo test` in the top-level *add* directory: + + +では、最上位の*add*ディレクトリで`cargo test`を実行してください: ```text $ cargo test @@ -288,15 +399,23 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -The first section of the output shows that the `it_works` test in the `add-one` -crate passed. The next section shows that 0 tests were found in the `adder` -crate, and then the last section shows 0 documentation tests were found in the -`add-one` crate. Running `cargo test` in a workspace structured like this one -will run the tests for all the crates in the workspace. + + + + + + +出力の最初の区域が、`add-one`クレートの`it_works`テストが通ったことを示しています。 +次の区域には、`adder`クレートにはテストが見つなかったことが示され、 +さらに最後の区域は、`add-one`クレートにドキュメンテーションテストは見つからなかったと表示されています。 +このような構造をしたワークスペースで`cargo test`を走らせると、ワークスペースの全クレートのテストを実行します。 -We can also run tests for one particular crate in a workspace from the -top-level directory by using the `-p` flag and specifying the name of the crate -we want to test: + + + + +`-p`フラグを使用し、テストしたいクレートの名前を指定することで最上位ディレクトリから、 +ワークスペースのある特定のクレート用のテストを実行することもできます: ```text $ cargo test -p add-one @@ -315,19 +434,33 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -This output shows `cargo test` only ran the tests for the `add-one` crate and -didn’t run the `adder` crate tests. + + + +この出力は、`cargo test`が`add-one`クレートのテストのみを実行し、`adder`クレートのテストは実行しなかったことを示しています。 + + + + + + + + + +ワークスペースのクレートを*https://crates.io/*に公開したら、ワークスペースのクレートは個別に公開される必要があります。 +`cargo publish`コマンドには`--all`フラグや`-p`フラグはないので、各クレートのディレクトリに移動して、 +ワークスペースの各クレートを`cargo publish`して、公開しなければなりません。 + + + -If you publish the crates in the workspace to *https://crates.io/*, each crate -in the workspace will need to be published separately. The `cargo publish` -command does not have an `--all` flag or a `-p` flag, so you must change to -each crate’s directory and run `cargo publish` on each crate in the workspace -to publish them. +鍛錬を積むために、`add-one`クレートと同様の方法でワークスペースに`add-two`クレートを追加してください! -For additional practice, add an `add-two` crate to this workspace in a similar -way as the `add-one` crate! + + + + -As your project grows, consider using a workspace: it’s easier to understand -smaller, individual components than one big blob of code. Keeping the crates in -a workspace can make coordination between them easier if they are often changed -at the same time. +プロジェクトが肥大化してきたら、ワークスペースの使用を考えてみてください: 大きな一つのコードの塊よりも、 +微細で個別のコンポーネントの方が理解しやすいです。ワークスペースにクレートを保持することは、 +同時に変更されることが多いのなら、協調しやすくなることにも繋がります。 From 6326235f797e483c91efaa3394872c26df31d79d Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 26 Jan 2018 22:56:07 +0900 Subject: [PATCH 094/428] First draft of the chapter 14-4 --- .../src/ch14-04-installing-binaries.md | 73 ++++++++++++------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/second-edition/src/ch14-04-installing-binaries.md b/second-edition/src/ch14-04-installing-binaries.md index 7e6814755..7f96bd999 100644 --- a/second-edition/src/ch14-04-installing-binaries.md +++ b/second-edition/src/ch14-04-installing-binaries.md @@ -1,25 +1,42 @@ -## Installing Binaries from Crates.io with `cargo install` - -The `cargo install` command allows you to install and use binary crates -locally. This isn’t intended to replace system packages; it’s meant to be a -convenient way for Rust developers to install tools that others have shared on -[crates.io](https://crates.io). You can only install packages -that have binary targets. A binary target is the runnable program that is -created if the crate has a *src/main.rs* file or another file specified as a -binary, as opposed to a library target that isn’t runnable on its own but is -suitable for including within other programs. Usually, crates have information -in the *README* file about whether a crate is a library, has a binary target, -or both. - -All binaries installed with `cargo install` are stored in the installation -root’s *bin* folder. If you installed Rust using *rustup.rs* and don’t have any -custom configurations, this directory will be *$HOME/.cargo/bin*. Ensure that -directory is in your `$PATH` to be able to run programs you’ve installed with -`cargo install`. - -For example, in Chapter 12 we mentioned that there’s a Rust implementation of -the `grep` tool called `ripgrep` for searching files. If we want to install -`ripgrep`, we can run the following: + + +## `cargo install`でCrates.ioからバイナリをインストールする + + + + + + + + + + + + +`cargo install`コマンドにより、バイナリクレートをローカルにインストールし、使用することができます。 +これは、システムパッケージを置き換えることを意図したものではありません。(すなわ)ち、 +Rustの開発者が、他人が[crates.io](https://crates.io)に共有したツールをインストールするのに便利な方法を意味するのです。 +バイナリターゲットを持つパッケージのみインストールできます。バイナリターゲットとは、 +クレートが*src/main.rs*ファイルやバイナリとして指定された他のファイルを持つ場合に生成される実行可能なプログラムのことであり、 +単独では実行不可能なものの、他のプログラムに含むのには適しているライブラリターゲットとは一線を画します。 +通常、クレートには、*README*ファイルに、クレートがライブラリかバイナリターゲットか、両方をもつかという情報があります。 + + + + + + + +`cargo install`でインストールされるバイナリは全て、インストールのルートの*bin*フォルダに保持されます。 +Rustを*rustup.rs*を使用し、独自の設定を何も行なっていなければ、このディレクトは、*$HOME/.cargo/bin*になります。 +`cargo install`でインストールしたプログラムを実行できるようにするためには、そのディレクトリが`$PATH`に含まれていることを確かめてください。 + + + + + +例えば、第12章で、ファイルを検索する`ripgrep`という`grep`ツールのRust版があることに触れました。 +`ripgrep`をインストールしたかったら、以下を実行することができます: ```text $ cargo install ripgrep @@ -31,7 +48,11 @@ Updating registry `https://github.com/rust-lang/crates.io-index` Installing ~/.cargo/bin/rg ``` -The last line of the output shows the location and the name of the installed -binary, which in the case of `ripgrep` is `rg`. As long as the installation -directory is in your `$PATH`, as mentioned previously, you can then run `rg` -`--help` and start using a faster, rustier tool for searching files! + + + + + +出力の最後の行が、インストールされたバイナリの位置と名前を示していて、`ripgrep`の場合、`rg`です。 +インストールディレクトリが`$PATH`に存在する限り、前述したように、`rg --help`を走らせて、 +より高速でRustらしいファイル検索ツールを使用し始めることができます! From d1d9fb97ecf957d480ea90a8b764d877a9848281 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 26 Jan 2018 23:05:02 +0900 Subject: [PATCH 095/428] First draft of the chapter 14-5 --- second-edition/src/ch14-05-extending-cargo.md | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/second-edition/src/ch14-05-extending-cargo.md b/second-edition/src/ch14-05-extending-cargo.md index ba5ade832..2abafd8fb 100644 --- a/second-edition/src/ch14-05-extending-cargo.md +++ b/second-edition/src/ch14-05-extending-cargo.md @@ -1,17 +1,33 @@ -## Extending Cargo with Custom Commands + -Cargo is designed so you can extend it with new subcommands without having to -modify Cargo. If a binary in your `$PATH` is named `cargo-something`, you can -run it as if it was a Cargo subcommand by running `cargo something`. Custom -commands like this are also listed when you run `cargo --list`. Being able to -use `cargo install` to install extensions and then run them just like the -built-in Cargo tools is a super convenient benefit of Cargo’s design! +## 独自のコマンドでCargoを拡張する -## Summary + + + + + + -Sharing code with Cargo and [crates.io](https://crates.io) is -part of what makes the Rust ecosystem useful for many different tasks. Rust’s -standard library is small and stable, but crates are easy to share, use, and -improve on a timeline different from the language. Don’t be shy about sharing -code that’s useful to you on [crates.io](https://crates.io); -it’s likely that it will be useful to someone else as well! +Cargoは変更する必要なく、新しいサブコマンドで拡張できるように設計されています。 +`$PATH`にあるバイナリが`cargo-something`という名前なら、`cargo something`を実行することで、 +Cargoのサブコマンドであるかのように実行することができます。このような独自のコマンドは、 +`cargo --list`を実行すると、列挙もされます。`cargo install`を使用して拡張をインストールし、 +それから組み込みのCargoツール同様に実行できることは、Cargoの設計上の非常に便利な恩恵です! + + + +## まとめ + + + + + + + + +Cargoで[crates.io](https://crates.io)とコードを共有することは、 +Rustのエコシステムを多くの異なる作業に有用にするものの一部です。Rustの標準ライブラリは、 +小さく安定的ですが、クレートは共有および使用しやすく、言語とは異なるタイムラインで進化します。 +積極的に[crates.io](https://crates.io)で自分にとって有用なコードを共有してください; +他の誰かにとっても、役に立つものであることでしょう! From 50e5e7e7fb3797e160c4990b3764760d6103f844 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 27 Jan 2018 18:34:02 +0900 Subject: [PATCH 096/428] First draft of the chapter 16-0 --- second-edition/src/SUMMARY.md | 16 ++- second-edition/src/ch16-00-concurrency.md | 136 ++++++++++++++-------- 2 files changed, 98 insertions(+), 54 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index 78b32034c..e639064af 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -162,11 +162,17 @@ - [`RefCell` and the Interior Mutability Pattern](ch15-05-interior-mutability.md) - [Creating Reference Cycles and Leaking Memory is Safe](ch15-06-reference-cycles.md) -- [Fearless Concurrency](ch16-00-concurrency.md) - - [Threads](ch16-01-threads.md) - - [Message Passing](ch16-02-message-passing.md) - - [Shared State](ch16-03-shared-state.md) - - [Extensible Concurrency: `Sync` and `Send`](ch16-04-extensible-concurrency-sync-and-send.md) + + + + + + +- [恐れるな!非同期処理](ch16-00-concurrency.md) + - [スレッド](ch16-01-threads.md) + - [メッセージ受け渡し](ch16-02-message-passing.md) + - [状態共有](ch16-03-shared-state.md) + - [さらなる非同期処理: `Sync`と`Send`](ch16-04-extensible-concurrency-sync-and-send.md) - [Is Rust an Object-Oriented Programming Language?](ch17-00-oop.md) - [What Does Object-Oriented Mean?](ch17-01-what-is-oo.md) diff --git a/second-edition/src/ch16-00-concurrency.md b/second-edition/src/ch16-00-concurrency.md index 8e7d728af..c0a287dfa 100644 --- a/second-edition/src/ch16-00-concurrency.md +++ b/second-edition/src/ch16-00-concurrency.md @@ -1,49 +1,87 @@ -# Fearless Concurrency - -Handling concurrent programming safely and efficiently is another of Rust’s -major goals. *Concurrent programming*, where different parts of a program -execute independently, and *parallel programming*, where different parts of a -program execute at the same time, are becoming increasingly important as more -computers take advantage of their multiple processors. Historically, -programming in these contexts has been difficult and error prone: Rust hopes to -change that. - -Initially, the Rust team thought that ensuring memory safety and preventing -concurrency problems were two separate challenges to be solved with different -methods. Over time, the team discovered that the ownership and type systems are -a powerful set of tools to help manage memory safety *and* concurrency -problems! By leveraging ownership and type checking, many concurrency errors -are *compile time* errors in Rust rather than runtime errors. Therefore, rather -than you spending lots of time trying to reproduce the exact circumstances -under which a runtime concurrency bug occurs, incorrect code will refuse to -compile and present an error explaining the problem. As a result, you can fix -your code while you’re working on it rather than potentially after it has been -shipped to production. We’ve nicknamed this aspect of Rust *fearless* -*concurrency*. Fearless concurrency allows you to write code that is free of -subtle bugs and is easy to refactor without introducing new bugs. - -> Note: For simplicity’s sake, we’ll refer to many of the problems as -> concurrent rather than being more precise by saying concurrent and/or -> parallel. If this book was specifically about concurrency and/or parallelism, -> we’d be more. specific. For this chapter, please mentally substitute -> concurrent and/or parallel whenever we use concurrent. - -Many languages are dogmatic about the solutions they offer for handling -concurrent problems. For example, Erlang has elegant functionality for message -passing concurrency but has only obscure ways to share state between threads. -Supporting only a subset of possible solutions is a reasonable strategy for -higher-level languages, because a higher-level language promises benefits from -giving up some control to gain abstractions. However, lower-level languages are -expected to provide the solution with the best performance in any given -situation and have fewer abstractions over the hardware. Therefore, Rust offers -a variety of tools for modeling problems in whatever way is appropriate for -your situation and requirements. - -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 -* The `Sync` and `Send` traits, which extend Rust’s concurrency guarantees to - user-defined types as well as types provided by the standard library + + +# 恐れるな!非同期処理 + + + + + + + + + +非同期処理を安全かつ効率的に扱うことは、Rustの別の主な目標です。非同期処理プログラミングは、プログラムの異なる部分が個別に実行することであり、 +並行プログラミングはプログラムの異なる部分が同時に実行することですが、多くのコンピュータが複数のプロセッサの利点を生かすようになるにつれ、 +重要度を増しています。歴史的に、これらの文脈で行うプログラミングは困難で、エラーが起きやすいものでした: +Rustはこれを変えると期待されています。 + + + + + + + + + + + + + + + + + +当初、Rustチームは、メモリ安全性を期することと、非同期処理問題を回避することは、 +異なる方法で解決すべき2つの個別の挑戦だと考えていました。時間とともに、チームは、所有権と型システムは、 +メモリ安全性*と*非同期処理問題を管理する役に立つ一連の強力な道具であることを発見しました。 +所有権と型チェックに影響させることで、多くの非同期処理エラーは、実行時エラーではなく*コンパイル*エラーになります。 +故に、実行時に非同期処理のバグが起きた状況と全く同じ状況を再現しようと時間を浪費するよりも、 +不正なコードはコンパイルを拒み、問題を説明するエラーを提示するでしょう。結果として、 +プロダクトになってから可能性があるというよりも、コードに取り組んでいる間に修正できます。 +Rustのこの方向性を*恐れるな!非同期処理*とニックネーム付けしました。これにより、潜在的なバグがなく、 +新しいバグを導入することなく簡単にリファクタリングできるコードを書くことができます。 + + + + + + + +> 注釈: 簡潔性のため、非同期または並行と述べることで正確を期するのではなく、 +> 多くの問題を非同期と割り切ってしまいます。この本がもし非同期あるいは並行性に特化した本ならば、 +> もっと特定していたでしょう。この章に対しては、非同期を使ったら、 +> 脳内で非同期または並行と置き換えてください。 + + + + + + + + + + + + +多くの言語は、自分が提供する非同期処理問題を扱う解決策について独断的です。例えば、Erlangには、 +メッセージ受け渡しの非同期処理に関する素晴らしい機能がありますが、スレッド間で状態を共有することに関しては、 +曖昧な方法しかありません。可能な解決策の一部のみをサポートすることは、高級言語にとっては合理的な施策です。 +なぜなら、高級言語は一部の制御を失う代わりに抽象化することから恩恵を受けるからです。ところが、 +低級言語は、どんな場面でも最高のパフォーマンスで解決策を提供すると想定され、ハードウェアに関してほとんど抽象化はしません。 +そのため、Rustは、自分の状況と必要性に適した方法で問題をモデル化するためのいろんな道具を備えています。 + + + +こちらが、この章で講義する話題です: + + + + + + + + +* スレッドを生成して、複数のコードを同時に走らせる方法 +* チャンネルがスレッド間でメッセージを送る*メッセージ受け渡し*非同期処理 +* 複数のスレッドが何らかのデータにアクセスする*状態共有*非同期処理 +* Rustの非同期処理保証をユーザ定義型と標準ライブラリが提供する型にも及ばせる`Sync`と`Send`トレイト From 3cc31769e5f7bbe5f042e7bfa0408bbda6cf9f31 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 27 Jan 2018 22:08:16 +0900 Subject: [PATCH 097/428] First draft of the chapter 16-1 --- second-edition/src/ch16-01-threads.md | 529 +++++++++++++++++--------- 1 file changed, 350 insertions(+), 179 deletions(-) diff --git a/second-edition/src/ch16-01-threads.md b/second-edition/src/ch16-01-threads.md index 38a7b2a86..88f27493b 100644 --- a/second-edition/src/ch16-01-threads.md +++ b/second-edition/src/ch16-01-threads.md @@ -1,72 +1,122 @@ -## Using Threads to Run Code Simultaneously - -In most current operating systems, an executed program’s code is run in a -*process*, and the operating system manages multiple processes at once. Within -your program, you can also have independent parts that run simultaneously. The -feature that runs these independent parts is called *threads*. - -Splitting the computation in your program into multiple threads can improve -performance because the program does multiple tasks at the same time, but it -also adds complexity. Because threads can run simultaneously, there’s no -inherent guarantee about the order in which parts of your code on different -threads will run. This can lead to problems, such as: - -* Race conditions, where threads are accessing data or resources in an - inconsistent order -* Deadlocks, where two threads are waiting for each other to finish using a - resource the other thread has, preventing both threads from continuing -* Bugs that only happen in certain situations and are hard to reproduce and fix - reliably - -Rust attempts to mitigate the negative effects of using threads. Programming in -a multithreaded context still takes careful thought and requires a code -structure that is different from programs that run in a single thread. - -Programming languages implement threads in a few different ways. Many operating -systems provide an API for creating new threads. This model where a language -calls the operating system APIs to create threads is sometimes called *1:1*, -one operating system thread per one language thread. - -Many programming languages provide their own special implementation of threads. -Programming language-provided threads are known as *green* threads, and -languages that use these green threads will execute them in the context of a -different number of operating system threads. For this reason, the green -threaded model is called the *M:N* model: `M` green threads per `N` operating -system threads, where `M` and `N` are not necessarily the same number. - -Each model has its own advantages and trade-offs, and the trade-off most -important to Rust is runtime support. Runtime is a confusing term and can have -different meanings in different contexts. - -In this context, by *runtime* we mean code that is included by the language in -every binary. This code can be large or small depending on the language, but -every non-assembly language will have some amount of runtime code. For that -reason, colloquially when people say a language has “no runtime,” they often -mean “small runtime.” Smaller runtimes have fewer features but have the -advantage of resulting in smaller binaries, which make it easier to combine the -language with other languages in more contexts. Although many languages are -okay with increasing the runtime size in exchange for more features, Rust needs -to have nearly no runtime and cannot compromise on being able to call into C to -maintain performance. - -The green threading M:N model requires a larger language runtime to manage -threads. As such, the Rust standard library only provides an implementation of -1:1 threading. Because Rust is such a low-level language, there are crates that -implement M:N threading if you would rather trade overhead for aspects such as -more control over which threads run when and lower costs of context switching, -for example. - -Now that we’ve defined threads in Rust, let’s explore how to use the -thread-related API provided by the standard library. - -### Creating a New Thread with `spawn` - -To create a new thread, we call the `thread::spawn` function and pass it a -closure (we talked about closures in Chapter 13) containing the code we want to -run in the new thread. The example in Listing 16-1 prints some text from a main -thread and other text from a new thread: - -Filename: src/main.rs + + +## スレッドを使用してコードを同時に走らせる + + + + + + +多くの現代のOSでは、実行中のプログラムのコードは*プロセス*で走り、OSは同時に複数のプロセスを管理します。 +自分のプログラム内で、同時に実行する部分を作ることもできます。これらの個別の部分を走らせる機能を*スレッド*と呼びます。 + + + + + + + +プログラム内の計算を複数のスレッドに分けると、パフォーマンスが改善します。プログラムが同時に複数の作業をするからですが、 +複雑度も増します。スレッドは同時に走らせることができるので、異なるスレッドのコードが走る順番に関して、 +本来の保証はありません。これは問題を招きます。例えば: + + + + + + + + +* スレッドがデータやリソースに不安定な順番でアクセスする競合状態 +* 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の使用法を探求しましょう。 + + + +### `spawn`で新規スレッドを生成する + + + + + + +新規スレッドを立ち上げるには、`thread::spawn`関数を呼び出し、 +新規スレッドで走らせたいコードを含むクロージャ(クロージャについては第13章で語りました)を渡します。 +リスト16-1の例は、メインスレッドと新規スレッドからテキストを出力します: + + + +ファイル名: src/main.rs ```rust use std::thread; @@ -75,25 +125,32 @@ 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)); } } ``` -Listing 16-1: Creating a new thread to print one thing -while the main thread prints something else + + -Note that with this function, the new thread will be stopped when the main -thread ends, whether or not it has finished running. The output from this -program might be a little different every time, but it will look similar to the -following: +リスト16-1: メインスレッドが別のものを出力する間に新規スレッドを生成して何かを出力する + + + + + + +この関数では、実行が終わったかどうかにかかわらず、新しいスレッドは、メインスレッドが終了したら停止することに注意してください。 +このプログラムからの出力は毎回少々異なる可能性がありますが、だいたい以下のような感じでしょう: ```text hi number 1 from the main thread! @@ -107,34 +164,55 @@ hi number 4 from the spawned thread! hi number 5 from the spawned thread! ``` -The calls to `thread::sleep` force a thread to stop its execution for a short -duration, which allows a different thread to run. The threads will probably -take turns, but that isn’t guaranteed: it depends on how your operating system -schedules the threads. In this run, the main thread printed first, even though -the print statement from the spawned thread appears first in the code. And even -though we told the spawned thread to print until `i` is 9, it only got to 5 -before the main thread shut down. + + + + + + + + +`thread::sleep`を呼び出すと、少々の間、スレッドの実行を止め、違うスレッドを走らせることができます。 +スレッドは順番待ちをしますが、保証はありません: OSがスレッドのスケジュールを行う方法によります。 +この実行では、立ち上げられたスレッドのprint文がコードでは先に出現しているのに、メインスレッドがまず出力しています。 +立ち上げたスレッドには`i`が9になるまで出力するよう指示しているのに、メインスレッドが終了する前の5までしか到達していません。 + + + + + +このコードを実行してメインスレッドの出力しか目の当たりにできなかったり、オーバーラップがなければ、 +範囲の値を増やしてOSがスレッド切り替えを行う機会を増やしてみてください。 -If you run this code and only see output from the main thread, or don’t see any -overlap, try increasing the numbers in the ranges to create more opportunities -for the operating system to switch between the threads. + -### Waiting for All Threads to Finish Using `join` Handles +### `join`ハンドルで全スレッドの終了を待つ -The code in Listing 16-1 not only stops the spawned thread prematurely most of -the time due to the main thread ending, but there is no guarantee that the -spawned thread will get to run at all. The reason is that there is no guarantee -on the order in which threads run! + + + + -We can fix the problem of the spawned thread not getting to run, or not getting -to run completely, by saving the return value of `thread::spawn` in a variable. -The return type of `thread::spawn` is `JoinHandle`. A `JoinHandle` is an owned -value that, when we call the `join` method on it, will wait for its thread to -finish. Listing 16-2 shows how to use the `JoinHandle` of the thread we created -in Listing 16-1 and call `join` to make sure the spawned thread finishes before -`main` exits: +リスト16-1のコードは、メインスレッドが終了するためにほとんどの場合、新規スレッドが未完で終わるだけでなく、 +新規スレッドが実行されるかどうかの保証もありません。原因は、スレッドの実行順に保証がないからです。 -Filename: src/main.rs + + + + + + + + +`thread::spawn`の戻り値を変数に保存することで、立ち上げたスレッドが実行されなかったり、 +完全に実行されなかったりする問題を修正することができます。`thread:spawn`の戻り値の型は`JoinHandle`です。 +`JoinHandle`は、`join`メソッドを呼び出したときにスレッドの実行を待つ所有された値です。 +リスト16-2は、リスト16-1で生成したスレッドの`JoinHandle`を使用し、`join`を呼び出して、 +立ち上げたスレッドが、`main`が終了する前に完了することを確認する方法を示しています: + + + +ファイル名: src/main.rs ```rust use std::thread; @@ -157,14 +235,21 @@ fn main() { } ``` -Listing 16-2: Saving a `JoinHandle` from `thread::spawn` -to guarantee the thread is run to completion + + + +リスト16-2: `thread::spawn`の`JoinHandle`を保存してスレッドが完了するのを保証する -Calling `join` on the handle blocks the thread currently running until the -thread represented by the handle terminates. *Blocking* a thread means that -thread is prevented from performing work or exiting. Because we’ve put the call -to `join` after the main thread’s `for` loop, running Listing 16-2 should -produce output similar to this: + + + + + + +ハンドルに対して`join`を呼び出すと、現在実行中のスレッドをハンドルが表すスレッドが停止するまでブロックします。 +スレッドを*ブロック*するとは、そのスレッドが作業をしたり、終了することを防ぐことです。 +`join`の呼び出しをメインスレッドの`for`ループの後に配置したので、リスト16-2を実行すると、 +以下のような出力が出るはずです: ```text hi number 1 from the main thread! @@ -182,13 +267,20 @@ hi number 8 from the spawned thread! hi number 9 from the spawned thread! ``` -The two threads continue alternating, but the main thread waits because of the -call to `handle.join()` and does not end until the spawned thread is finished. + + + +2つのスレッドが代わる代わる実行されていますが、`handle.join()`呼び出しのためにメインスレッドは待機し、 +立ち上げたスレッドが終了するまで終わりません。 + + + + +ですが、代わりに`handle.join()`を`for`ループの前に移動したらどうなるのか確認しましょう。こんな感じに: -But let’s see what happens when we instead move `handle.join()` before the -`for` loop in `main`, like this: + -Filename: src/main.rs +ファイル名: src/main.rs ```rust use std::thread; @@ -211,8 +303,11 @@ fn main() { } ``` -The main thread will wait for the spawned thread to finish and then run its -`for` loop, so the output won’t be interleaved anymore, as shown here: + + + +メインスレッドが、立ち上げたスレッドが終了するまで待ち、それから`for`ループを実行するので、 +以下のように出力はもう混じりません: ```text hi number 1 from the spawned thread! @@ -230,31 +325,52 @@ hi number 3 from the main thread! hi number 4 from the main thread! ``` -Thinking about such a small detail as where to call `join` can affect whether -or not your threads run at the same time. + + + +どこで`join`を呼ぶかのような小さな詳細について考慮することが、スレッドが同時に走るかどうかに影響するのです。 + + + +### スレッドで`move`クロージャを使用する -### Using `move` Closures with Threads + + + -The `move` closure, which we mentioned briefly in Chapter 13, is often used -alongside `thread::spawn` because it allows us to use data from one thread in -another thread. +`move`クロージャについては、第13章でちらっとだけ触れましたが、`thread::spawn`とともによく使用されます。 +あるスレッドから別のスレッドにデータを使用させてくれるからです。 -In Chapter 13, we said that “If we want to force the closure to take ownership -of the values it uses in the environment, we can use the `move` keyword before -the parameter list. This technique is mostly useful when passing a closure to a -new thread to move the data so it’s owned by the new thread.” + + + + -Now that we’re creating new threads, we’ll talk about capturing values in -closures. +第13章で、「環境で使用している値の所有権を奪うことをクロージャに強制したいのなら、 +引数リストの前に`move`キーワードを使用でき、このテクニックは、クロージャを新しいスレッドに渡して、 +新しいスレッドが所有するようにデータをムーブするときにだいたい有用です」と述べました。 -Notice in Listing 16-1 that the closure we pass to `thread::spawn` takes no -arguments: we’re not using any data from the main thread in the spawned -thread’s code. To do so, the spawned thread’s closure must capture the values -it needs. Listing 16-3 shows an attempt to create a vector in the main thread -and use it in the spawned thread. However, this won’t yet work, as you’ll see -in a moment: + + -Filename: src/main.rs +新規スレッドを立ち上げているので、クロージャに値をキャプチャすることについて語りましょう。 + + + + + + + + +リスト16-1において、`thread::spawn`に渡したクロージャには引数がなかったことに気付いてください: +立ち上げたスレッドのコードでメインスレッドからのデータは何も使用していないのです。そうするには、 +立ち上げるスレッドのクロージャは、必要な値をキャプチャしなければなりません。 +リスト16-3は、メインスレッドでベクタを生成し、立ち上げたスレッドで使用する試みを示しています。 +しかしながら、すぐにわかるように、これはまだ動きません: + + + +ファイル名: src/main.rs ```rust,ignore use std::thread; @@ -263,6 +379,7 @@ fn main() { let v = vec![1, 2, 3]; let handle = thread::spawn(|| { + // こちらがベクタ: {:?} println!("Here's a vector: {:?}", v); }); @@ -270,17 +387,26 @@ fn main() { } ``` -Listing 16-3: Attempting to use a vector created by the -main thread in another thread + + -The closure uses `v`, so it will capture `v` and make it part of the closure’s -environment. Because `thread::spawn` runs this closure in a new thread, we -should be able to access `v` inside that new thread. But when we compile this -example, we get the following error: +リスト16-3: 別のスレッドでメインスレッドが生成したベクタを使用しようとする + + + + + + +クロージャは`v`を使用しているので、`v`をキャプチャし、環境の一部にしています。 +`thread::spawn`はこのクロージャを新しいスレッドで走らせるので、 +その新しいスレッド内で`v`にアクセスできるはずです。しかし、このコードをコンパイルすると、 +以下のようなエラーが出ます: ```text 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(|| { @@ -290,20 +416,29 @@ which is owned by the current function | 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 || { | ^^^^^^^ ``` -Rust *infers* how to capture `v`, and because `println!` only needs a reference -to `v`, the closure tries to borrow `v`. However, there’s a problem: Rust can’t -tell how long the spawned thread will run, so it doesn’t know if the reference -to `v` will always be valid. + + + + + +Rustは`v`のキャプチャ方法を*推論*し、`println!`は`v`への参照のみを必要とするので、クロージャは、 +`v`を借用しようとします。ですが、問題があります: コンパイラには、立ち上げたスレッドがどのくらい走るのかわからないので、 +`v`への参照が常に有効であるか把握できないのです。 + + + -Listing 16-4 provides a scenario that’s more likely to have a reference to `v` -that won’t be valid: +リスト16-4は、`v`への参照がより有効でなさそうな筋書きです: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust,ignore use std::thread; @@ -315,24 +450,34 @@ fn main() { println!("Here's a vector: {:?}", v); }); + // いや〜! drop(v); // oh no! handle.join().unwrap(); } ``` -Listing 16-4: A thread with a closure that attempts to -capture a reference to `v` from a main thread that drops `v` + + + +リスト16-4: `v`をドロップするメインスレッドから`v`への参照をキャプチャしようとするクロージャとスレッド + + + + + + + + +このコードを実行することが叶うのなら、立ち上げたスレッドが実行されることなく即座にバックグラウンドに置かれる可能性があります。 +立ち上げたスレッドは内部に`v`への参照を保持していますが、メインスレッドは、第15章で議論した`drop`関数を使用して、 +即座に`v`をドロップしています。そして、立ち上げたスレッドが実行を開始する時には、`v`はもう有効ではなく、 +参照も不正になるのです。あちゃー! -If we were allowed to run this code, there’s a possibility the spawned thread -will be immediately put in the background without running at all. The spawned -thread has a reference to `v` inside, but the main thread immediately drops -`v`, using the `drop` function we discussed in Chapter 15. Then, when the -spawned thread starts to execute, `v` is no longer valid, so a reference to it -is also invalid. Oh no! + + -To fix the compiler error in Listing 16-3, we can use the error message’s -advice: +リスト16-3のコンパイルエラーを修正するには、エラーメッセージのアドバイスを活用できます: ```text help: to force the closure to take ownership of `v` (and any other referenced @@ -342,12 +487,18 @@ variables), use the `move` keyword | ^^^^^^^ ``` -By adding the `move` keyword before the closure, we force the closure to take -ownership of the values it’s using rather than allowing Rust to infer that it -should borrow the values. The modification to Listing 16-3 shown in Listing -16-5 will compile and run as we intend: + + + + -Filename: src/main.rs +クロージャの前に`move`キーワードを付することで、コンパイラに値を借用すべきと推論させるのではなく、 +クロージャに使用している値の所有権を強制的に奪わせます。リスト16-4に示したリスト16-3に対する変更は、 +コンパイルでき、意図通りに動きます: + + + +ファイル名: src/main.rs ```rust use std::thread; @@ -363,18 +514,26 @@ fn main() { } ``` -Listing 16-5: Using the `move` keyword to force a closure -to take ownership of the values it uses + + + +リスト16-5: `move`キーワードを使用してクロージャに使用している値の所有権を強制的に奪わせる + + + + + + + -What would happen to the code in Listing 16-4 where the main thread called -`drop` if we use a `move` closure? Would `move` fix that case? Unfortunately, -no; we would get a different error because what Listing 16-4 is trying to do -isn’t allowed for a different reason. If we add `move` to the closure, we would -move `v` into the closure’s environment, and we could no longer call `drop` on -it in the main thread. We would get this compiler error instead: +`move`クロージャを使用していたら、メインスレッドが`drop`を呼び出すリスト16-4のコードはどうなるのでしょうか? +`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 || { @@ -385,17 +544,29 @@ error[E0382]: use of moved value: `v` | = note: move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait + (注釈: `v`の型が`std::vec::Vec`のためムーブが起きました。この型は、`Copy`トレイトを実装していません) ``` -Rust’s ownership rules have saved us again! We got an error from the code in -Listing 16-3 because Rust was being conservative and only borrowing `v` for the -thread, which meant the main thread could theoretically invalidate the spawned -thread’s reference. By telling Rust to move ownership of `v` to the spawned -thread, we’re guaranteeing Rust that the main thread won’t use `v` anymore. If -we change Listing 16-4 in the same way, we’re then violating the ownership -rules when we try to use `v` in the main thread. The `move` keyword overrides -Rust’s conservative default of borrowing; it doesn’t let us violate the -ownership rules. - -With a basic understanding of threads and the thread API, let’s look at what we -can *do* with threads. + + + + + + + + + + +再三Rustの所有権ルールが救ってくれました!リスト16-3のコードはエラーになりました。 +コンパイラが一時的に保守的になり、スレッドに対して`v`を借用しただけだったからで、 +これは、メインスレッドは理論上、立ち上げたスレッドの参照を不正化する可能性があることを意味します。 +`v`の所有権を立ち上げたスレッドに移動するとコンパイラに指示することで、 +メインスレッドはもう`v`を使用しないとコンパイラに保証しているのです。リスト16-4も同様に変更したら、 +メインスレッドで`v`を使用しようとする際に所有権ルールを侵害することになります。 +`move`キーワードにより、デフォルトで借用するというRustの保守性が上書きされるのです; +所有権ルールを侵害させてはくれないのです。 + + + + +スレッドとスレッドAPIの基礎知識が入ったので、スレッドでできることを見ていきましょう。 From bc3f883ad78752e2efc9a8c3795aed9342672c21 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 28 Jan 2018 19:23:23 +0900 Subject: [PATCH 098/428] First draft of the chapter 16-2 --- second-edition/src/ch16-02-message-passing.md | 469 ++++++++++++------ 1 file changed, 314 insertions(+), 155 deletions(-) diff --git a/second-edition/src/ch16-02-message-passing.md b/second-edition/src/ch16-02-message-passing.md index 3c4e1c2a2..151a1e76c 100644 --- a/second-edition/src/ch16-02-message-passing.md +++ b/second-edition/src/ch16-02-message-passing.md @@ -1,41 +1,72 @@ -## Message Passing to Transfer Data Between Threads + -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: +## スレッド間でデータを転送するメッセージ受け渡し -> Do not communicate by sharing memory; instead, share memory by -> communicating. + + + + +人気度を増してきている安全な非同期処理を保証する一つのアプローチが*メッセージ受け渡し*で、 +スレッドやアクターがデータを含むメッセージを相互に送り合うことでやり取りします。 +こちらが、Go言語のドキュメンテーションのスローガンにある考えです: + + + + + + +> メモリを共有することでやり取りするな; 代わりにやり取りすることでメモリを共有しろ。 > > --[Effective Go](http://golang.org/doc/effective_go.html) -One major tool Rust has for accomplishing message sending concurrency is the -*channel*, a programming concept that Rust’s standard library provides an -implementation of. You can imagine a channel in programming like a channel of -water, such as a stream or a river. If you put something like a rubber duck or -a boat into a stream, it will travel downstream to the end of the river. - -A channel in programming has two halves: a transmitter and a receiver. The -transmitter half is the upstream location where we put rubber ducks into the -river, and the receiver half is where the rubber duck ends up downstream. One -part of our code calls methods on the transmitter with the data we want to -send, and another part checks the receiving end for arriving messages. A -channel is said to be *closed* if either the transmitter or receiver half is -dropped. - -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. - -First, in Listing 16-6, we’ll create a channel but not do anything with it. -Note that this won’t compile yet because Rust can’t tell what type of values we -want to send over the channel: - -Filename: src/main.rs + + + + + + +メッセージ送信非同期処理を達成するためにRustに存在する一つの主な道具は、*チャンネル*で、 +Rustの標準ライブラリが実装を提供しているプログラミング概念です。プログラミングのチャンネルは、 +水の流れのように考えることができます。小川とか川ですね。アヒルのおもちゃやボートみたいなものを小川に置いたら、 +川の終端まで下流に流れていきます。 + + + + + + + + + +プログラミングにおけるチャンネルは、2分割できます: 転送機と受信機です。転送機はアヒルのおもちゃを川に置く上流になり、 +受信機は、アヒルのおもちゃが行き着く下流になります。コードのある箇所が送信したいデータとともに転送機のメソッドを呼び出し、 +別の部分がメッセージが到着していないか受信側を調べます。転送機と受信機のどちらかがドロップされると、 +チャンネルは*閉じられた*と言います。 + + + + + + + + + +ここで、1つのスレッドが値を生成し、それをチャンネルに送信し、別のスレッドがその値を受け取り、 +出力するプログラムに取り掛かります。チャンネルを使用してスレッド間に単純な値を送り、 +機能の具体化を行います。一旦、そのテクニックに慣れてしまえば、チャンネルを使用してチャットシステムや、 +多くのスレッドが計算の一部を担い、結果をまとめる1つのスレッドにその部分を送るようなシステムを実装できるでしょう。 + + + + + +まず、リスト16-6において、チャンネルを生成するものの、何もしません。 +チャンネルを通してどんな型の値を送りたいのかコンパイラがわからないため、 +これはまだコンパイルできないことに注意してください: + + + +ファイル名: src/main.rs ```rust use std::sync::mpsc; @@ -46,35 +77,56 @@ fn main() { } ``` -Listing 16-6: Creating a channel and assigning the two -halves to `tx` and `rx` + + -We create a new channel using the `mpsc::channel` function; `mpsc` stands for -*multiple producer, single consumer*. In short, the way Rust’s standard library -implements channels means a channel can have multiple *sending* ends that -produce values but only one *receiving* end that consumes those values. Imagine -multiple rivers and streams flowing together into one big river: everything -sent down any of the streams will end up in one river at the end. We’ll start -with a single producer for now, but we’ll add multiple producers when we get -this example working. +リスト16-6: チャンネルを生成し、2つの部品を`tx`と`rx`に代入する + + + + + + + + + + +`mpsc::channel`関数で新しいチャンネルを生成しています; `mpsc`は*multiple producer, single consumer*を表しています。 +簡潔に言えば、Rustの標準ライブラリがチャンネルを実装している方法は、1つのチャンネルが値を生成する複数の*送信*側と、 +その値を消費するたった1つの*受信*側を持つことができるということを意味します。 +複数の川と小川が互いに合わさって1つの大きな川になるところを想像してください: +どの川を通っても、送られたものは最終的に1つの川に行き着きます。今は、1つの生成機から始めますが、 +この例が動作するようになったら、複数の生成機を追加します。 -The `mpsc::channel` function returns a tuple, the first element of which is the -sending end and the second element is the receiving end. The abbreviations `tx` -and `rx` are traditionally used in many fields for *transmitter* and *receiver* -respectively, so we name our variables as such to indicate each end. We’re -using a `let` statement with a pattern that destructures the tuples; we’ll -discuss the use of patterns in `let` statements and destructuring in -Chapter 18. Using a `let` statement this way is a convenient approach to -extract the pieces of the tuple returned by `mpsc::channel`. + + + + + + + + + +`mpsc::channel`関数はタプルを返し、1つ目の要素は、送信側、2つ目の要素は受信側になります。 +`tx`と`rx`という略称は、多くの分野で伝統的に*転送機*と*受信機*にそれぞれ使用されているので、 +変数をそのように名付けて、各終端を示します。タプルを分解するパターンを伴う`let`文を使用しています; +`let`文でパターンを使用することと分解については、第18章で議論しましょう。このように`let`文を使うと、 +`mpsc::channel`で返ってくるタプルの部品を抽出するのが便利になります。 -Let’s move the transmitting end into a spawned thread and have it send one -string so the spawned thread is communicating with the main thread, as shown in -Listing 16-7. This is like putting a rubber duck in the river upstream or -sending a chat message from one thread to another: + + + + -Filename: src/main.rs +立ち上げたスレッドがメインスレッドとやり取りするように、転送機を立ち上げたスレッドに移動し、 +1文字列を送らせましょう。リスト16-7のようにね。川の上流にアヒルのおもちゃを置いたり、 +チャットのメッセージをあるスレッドから別のスレッドに送るみたいですね: + + + +ファイル名: src/main.rs ```rust use std::thread; @@ -90,26 +142,42 @@ fn main() { } ``` -Listing 16-7: Moving `tx` to a spawned thread and sending -“hi” + + + +リスト16-7: `tx`を立ち上げたスレッドに移動し、「やあ」を送る + + + + + + +今回も、`thread::spawn`を使用して新しいスレッドを生成し、それから`move`を使用して、 +立ち上げたスレッドが`tx`を所有するようにクロージャに`tx`をムーブしています。立ち上げたスレッドは、 +メッセージをチャンネルを通して送信できるようにチャンネルの送信側を所有する必要があります。 -Again, we’re using `thread::spawn` to create a new thread and then using `move` -to move `tx` into the closure so the spawned thread owns `tx`. The spawned -thread needs to own the transmitting end of the channel to be able to send -messages through the channel. + + + + + + -The transmitting end has a `send` method that takes the value we want to send. -The `send` method returns a `Result` type, so if the receiving end has -already been dropped and there’s nowhere to send a value, the send operation -will return an error. In this example, we’re calling `unwrap` to panic in case -of an error. But in a real application, we would handle it properly: return to -Chapter 9 to review strategies for proper error handling. +転送側には、送信したい値を取る`send`メソッドがあります。`send`メソッドは`Result`型を返すので、 +すでに受信側がドロップされ、値を送信する場所がなければ、送信処理はエラーを返します。 +この例では、エラーの場合には、パニックするように`unwrap`を呼び出しています。ですが、実際のアプリケーションでは、 +ちゃんと扱うでしょう: 第9章に戻ってちゃんとしたエラー処理の方法を再確認してください。 -In Listing 16-8, we’ll get the value from the receiving end of the channel in -the main thread. This is like retrieving the rubber duck from the water at the -end of the river or like getting a chat message: + + + -Filename: src/main.rs +リスト16-8において、メインスレッドのチャンネルの受信側から値を得ます。 +アヒルのおもちゃを川の終端で水から取り上げたり、チャットメッセージを取得するみたいですね: + + + +ファイル名: src/main.rs ```rust use std::thread; @@ -124,52 +192,82 @@ fn main() { }); let received = rx.recv().unwrap(); + // 値は{}です println!("Got: {}", received); } ``` -Listing 16-8: Receiving the value “hi” in the main thread -and printing it + + + +リスト16-8: 「やあ」の値をメインスレッドで受け取り、出力する + + + + + + + + +チャンネルの受信側には有用なメソッドが2つあります: `recv`と`try_recv`です。 +*receive*の省略形である`recv`を使っていて、これは、メインスレッドの実行をブロックし、 +値がチャンネルを流れてくるまで待機します。一旦値が送信されたら、`recv`はそれを`Result`に含んで返します。 +チャンネルの送信側が閉じたら、`recv`はエラーを返し、もう値は来ないと通知します。 -The receiving end of a channel has two useful methods: `recv` and `try_recv`. -We’re using `recv`, short for *receive*, which will block the main thread’s -execution and wait until a value is sent down the channel. Once a value is -sent, `recv` will return it in a `Result`. When the sending end of the -channel closes, `recv` will return an error to signal that no more values will -be coming. + + + + + + + -The `try_recv` method doesn’t block, but will instead return a `Result` -immediately: an `Ok` value holding a message if one is available and an `Err` -value if there aren’t any messages this time. Using `try_recv` is useful if -this thread has other work to do while waiting for messages: we could write a -loop that calls `try_recv` every so often, handles a message if one is -available, and otherwise does other work for a little while until checking -again. +`try_recv`メソッドはブロックせず、代わりに即座に`Result`を返します: +メッセージがあったら、それを含む`Ok`値、今回は何もメッセージがなければ、`Err`値です。 +メッセージを待つ間にこのスレッドにすることが他にあれば、`try_recv`は有用です: +`try_recv`を頻繁に呼び出し、メッセージがあったら処理し、それ以外の場合は、 +再度チェックするまでちょっとの間他の作業をするループを書くことができるでしょう。 -We’ve used `recv` in this example for simplicity; we don’t have any other work -for the main thread to do other than wait for messages, so blocking the main -thread is appropriate. + + + -When we run the code in Listing 16-8, we’ll see the value printed from the main -thread: +この例では、簡潔性のために`recv`を使用しました; メッセージを待つこと以外にメインスレッドがすべき作業はないので、 +メインスレッドをブロックするのは適切です。 + + + + +リスト16-8のコードを実行したら、メインスレッドから値が出力されます: ```text Got: hi ``` -Perfect! + + +完璧です! + + + +### チャンネルと所有権の転送 -### Channels and Ownership Transference + + + + + + + -The ownership rules play a vital role in message sending because they help us -write safe, concurrent code. Preventing errors in concurrent programming is the -advantage we get by making the trade-off of having to think about ownership -throughout our Rust programs. Let’s do an experiment to show how channels and -ownership work together to prevent problems: we’ll try to use a `val` value in -the spawned thread *after* we’ve sent it down the channel. Try compiling the -code in Listing 16-9: +安全な非同期コードを書く手助けをしてくれるので、所有権ルールは、メッセージ送信で重要な役割を担っています。 +非同期プログラミングでエラーを回避することは、Rustプログラム全体で所有権について考えなければいけないという代償をすることで、 +得られる利点です。実験をしてチャンネルと所有権がともに動いてどう問題を回避するかをお見せしましょう: +`val`値を立ち上げたスレッドで、チャンネルに送った*後*に使用を試みます。リスト16-9のコードのコンパイルを試みてください: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust,ignore use std::thread; @@ -181,6 +279,7 @@ fn main() { thread::spawn(move || { let val = String::from("hi"); tx.send(val).unwrap(); + // valは{} println!("val is {}", val); }); @@ -189,15 +288,23 @@ fn main() { } ``` -Listing 16-9: Attempting to use `val` after we’ve sent it -down the channel + + + +リスト16-9: チャンネルに送信後に`val`の使用を試みる + + + + + + + -Here, we try to print `val` after we’ve sent it down the channel via `tx.send`. -Allowing this would be a bad idea: once the value has been sent to another -thread, that thread could modify or drop it before we try to use the value -again. Potentially, the other thread's modifications could cause errors or -unexpected results due to inconsistent or nonexistent data. However, Rust gives -us an error if we try to compile the code in Listing 16-9: +ここで、`tx.send`経由でチャンネルに送信後に`val`を出力しようとしています。これを許可するのは、悪い考えです: +一旦、値が他のスレッドに送信されたら、そのスレッドが再度値を使用しようとする前に変更したりドロップできてしまいます。 +可能性として、その別のスレッドの変更により、矛盾していたり存在しないデータのせいでエラーが発生したり、 +予期しない結果になる可能性があります。ですが、リスト16-9のコードのコンパイルを試みると、 +Rustはエラーを返します: ```text error[E0382]: use of moved value: `val` @@ -212,20 +319,32 @@ error[E0382]: use of moved value: `val` not implement the `Copy` trait ``` -Our concurrency mistake has caused a compile time error. The `send` function -takes ownership of its parameter, and when the value is moved, the receiver -takes ownership of it. This stops us from accidentally using the value again -after sending it; the ownership system checks that everything is okay. + + + + + +非同期処理のミスがコンパイルエラーを招きました。`send`関数は引数の所有権を奪い、 +値がムーブされると、受信側が所有権を得るのです。これにより、送信後に誤って再度値を使用するのを防いでくれます; +所有権システムが、万事問題ないことを確認してくれます。 + + -### Sending Multiple Values and Seeing the Receiver Waiting +### 複数の値を送信し、受信側が待機するのを確かめる -The code in Listing 16-8 compiled and ran, but it didn’t clearly show us that -two separate threads were talking to each other over the channel. In Listing -16-10 we’ve made some modifications that will prove the code in Listing 16-8 is -running concurrently: the spawned thread will now send multiple messages and -pause for a second between each message: + + + + + -Filename: src/main.rs +リスト16-8のコードはコンパイルでき、動きましたが、2つの個別のスレッドがお互いにチャンネル越しに会話していることは、 +明瞭に示されませんでした。リスト16-10において、リスト16-8のコードが非同期で動いていることを証明する変更を行いました: +立ち上げたスレッドは、複数のメッセージを送信し、各メッセージ間で、1秒待機します: + + + +ファイル名: src/main.rs ```rust use std::thread; @@ -236,6 +355,7 @@ fn main() { let (tx, rx) = mpsc::channel(); thread::spawn(move || { + // スレッドからやあ let vals = vec![ String::from("hi"), String::from("from"), @@ -255,20 +375,32 @@ fn main() { } ``` -Listing 16-10: Sending multiple messages and pausing -between each one + + + +リスト16-10: 複数のメッセージを送信し、メッセージ間で停止する + + + + + + +今回は、メインスレッドに送信したい文字列のベクタを立ち上げたスレッドが持っています。 +それらをイテレートし、各々個別に送信し、`Duration`の値1秒とともに`thread::sleep`関数を呼び出すことで、 +メッセージ間で停止します。 -This time, the spawned thread has a vector of strings that we want to send to -the main thread. We iterate over them, sending each individually, and pause -between each by calling the `thread::sleep` function with a `Duration` value of -one second. + + + -In the main thread, we’re not calling the `recv` function explicitly anymore: -instead, we’re treating `rx` as an iterator. For each value received, we’re -printing it. When the channel is closed, iteration will end. +メインスレッドにおいて、最早`recv`関数を明示的に呼んではいません: 代わりに、 +`rx`をイテレータとして扱っています。受信した値それぞれを出力します。 +チャンネルが閉じられると、繰り返しも終わります。 -When running the code in Listing 16-10, you should see the following output -with a one second pause in between each line: + + + +リスト16-10のコードを走らせると、各行の間に1秒の待機をしつつ、以下のような出力を目の当たりにするはずです: ```text Got: hi @@ -277,18 +409,29 @@ Got: the Got: thread ``` -Because we don’t have any code that pauses or delays in the `for` loop in the -main thread, we can tell that the main thread is waiting to receive values from -the spawned thread. + + + + +メインスレッドの`for`ループには停止したり、遅れたりするコードは何もないので、 +メインスレッドが立ち上げたスレッドから値を受け取るのを待機していることがわかります。 + + + +### 転送機をクローンして複数の生成機を作成する + + + + + -### Creating Multiple Producers by Cloning the Transmitter +`mpsc`は、*mutiple* *producer, single consumer*の頭字語であると前述しました。 +`mpsc`を使用に移し、リスト16-10のコードを拡張して全てが値を同じ受信機に送信する複数のスレッドを生成しましょう。 +チャンネルの転送の片割れをクローンすることでそうすることができます。リスト16-11のようにね: -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: + -Filename: src/main.rs +ファイル名: src/main.rs ```rust # use std::thread; @@ -316,6 +459,7 @@ thread::spawn(move || { }); thread::spawn(move || { + // 君のためにもっとメッセージを let vals = vec![ String::from("more"), String::from("messages"), @@ -337,16 +481,25 @@ for received in rx { # } ``` -Listing 16-11: Sending multiple messages from multiple -producers + + -This time, before we create the first spawned thread, we call `clone` on the -sending end of the channel. This will give us a new sending handle we can pass -to the first spawned thread. We pass the original sending end of the channel to -a second spawned thread. This gives us two threads, each sending different -messages to the receiving end of the channel. +リスト16-11: 複数の生成機から複数のメッセージを送信する -When you run the code, you’ll *probably* see output like this: + + + + + + +今回、最初のスレッドを立ち上げる前に、チャンネルの送信側に対して`clone`を呼び出しています。 +これにより、最初に立ち上げたスレッドに渡せる新しい送信ハンドルが得られます。 +元のチャンネルの送信側は、2番目に立ち上げたスレッドに渡します。これにより2つスレッドが得られ、 +それぞれチャンネルの受信側に異なるメッセージを送信します。 + + + +コードを実行すると、*恐らく*以下のような出力を目の当たりにするでしょう: ```text Got: hi @@ -359,10 +512,16 @@ Got: thread Got: you ``` -You might see the values in another order; it depends on your system. This is -what makes concurrency interesting as well as difficult. If you experiment with -`thread::sleep`, giving it various values in the different threads, each run -will be more non-deterministic and create different output each time. + + + + + +別の順番で値が出る可能性もあります; システム次第です。非同期処理が面白いと同時に難しい部分でもあります。 +異なるスレッドで色々な値を与えて`thread::sleep`で実験をしたら、走らせるたびにより非決定的になり、 +毎回異なる出力をするでしょう。 + + + -Now that we’ve looked at how channels work, let’s look at a different method of -concurrency. +チャンネルの動作方法を見たので、他の非同期処理に目を向けましょう。 From d0b4d8e4cfc2d1b0288924eaace08c8b262fff16 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 28 Jan 2018 22:58:39 +0900 Subject: [PATCH 099/428] First draft of the chapter 16-3 --- second-edition/src/ch16-03-shared-state.md | 569 ++++++++++++++------- 1 file changed, 381 insertions(+), 188 deletions(-) diff --git a/second-edition/src/ch16-03-shared-state.md b/second-edition/src/ch16-03-shared-state.md index 90e6d12ef..f36b008d9 100644 --- a/second-edition/src/ch16-03-shared-state.md +++ b/second-edition/src/ch16-03-shared-state.md @@ -1,57 +1,104 @@ -## Shared State Concurrency + -Message passing is a fine way of handling concurrency, but it’s not the only -one. Consider this part of the slogan from the Go language documentation again: -“communicate by sharing memory.” +## 状態共有非同期処理 -What would communicating by sharing memory look like? In addition, why would -message passing enthusiasts not use it and do the opposite instead? + + + -In a way, channels in any programming language are similar to single ownership, -because once you transfer a value down a channel, you should no longer use that -value. Shared memory concurrency is like multiple ownership: multiple threads -can access the same memory location at the same time. As you saw in Chapter 15 -where smart pointers made multiple ownership possible, multiple ownership can -add additional complexity because these different owners need managing. Rust’s -type system and ownership rules greatly assist in getting this management -correct. For an example, let’s look at mutexes, one of the more common -concurrency primitives for shared memory. +メッセージ受け渡しは、非同期処理を扱う素晴らしい方法ですが、唯一の方法ではありません。 +Go言語ドキュメンテーションのスローガンのこの部分を再び考えてください: +「メモリを共有することでやり取りする。」 -### Mutexes Allow Access to Data from One Thread at a Time + + -A *mutex* is an abbreviation for “mutual exclusion,” as in, it only allows one -thread to access some data at any given time. To access the data in a mutex, a -thread must first signal that it wants access by asking to acquire the mutex’s -*lock*. The lock is a data structure that is part of the mutex that keeps track -of who currently has exclusive access to the data. Therefore, we describe the -mutex as *guarding* the data it holds via the locking system. +メモリを共有することでやり取りするとはどんな感じなのでしょうか?さらに、 +なぜメッセージ受け渡しに熱狂的な人は、それを使わず、代わりに全く反対のことをするのでしょうか? -Mutexes have a reputation for being difficult to use because you have to -remember two rules: + + + + + + + + + -1. You must attempt to acquire the lock before using the data. -2. When you’re done with the data that the mutex guards, you must unlock the - data so other threads can acquire the lock. +ある意味では、どんなプログラミング言語のチャンネルも単独の所有権に類似しています。 +一旦チャンネルに値を転送したら、その値は最早使用することがないからです。 +メモリ共有非同期処理は、複数の所有権に似ています: 複数のスレッドが同時に同じメモリ位置にアクセスできるのです。 +第15章でスマートポインタが複数の所有権を可能にするのを目の当たりにしたように、 +異なる所有者を管理する必要があるので、複数の所有権は複雑度を増させます。 +Rustの型システムと所有権ルールにより、この管理を正当に行う非常に大きな助けになります。 +例を挙げれば、メモリ共有を行うより一般的な非同期処理の基礎の一つであるミューテックスを見ましょう。 -For a real-world metaphor of a mutex, imagine a panel discussion at a -conference with only one microphone. Before a panelist can speak, they have to -ask or signal that they want to use the microphone. When they get the -microphone, they can talk for as long as they want to and then hand the -microphone to the next panelist who requests to speak. If a panelist forgets to -hand the microphone off when they’re finished with it, no one else is able to -speak. If management of the shared microphone goes wrong, the panel wouldn’t -work as planned! + -Management of mutexes can be incredibly tricky to get right, which is why so -many people are enthusiastic about channels. However, thanks to Rust’s type -system and ownership rules, we can’t get locking and unlocking wrong. +### ミューテックスは、一度に1つのスレッドからデータにアクセスすることを許可する -#### The API of `Mutex` + + + + + + -As an example of how to use a mutex, let’s start by using a mutex in a -single-threaded context, as shown in Listing 16-12: +ミューテックスは、どんな時も1つのスレッドにしかなんらかのデータへのアクセスを許可しないというように、 +"mutual exclusion"(相互排他)の省略形です。ミューテックスにあるデータにアクセスするには、 +ミューテックスのロックを所望することでアクセスしたいことをまず、スレッドは通知しなければなりません。 +ロックとは、現在誰がデータへの排他的アクセスを行なっているかを追跡するミューテックの一部をなすデータ構造です。 +故に、ミューテックスをロックシステム経由で保持しているデータを*死守する*(guarding)と解説します。 -Filename: src/main.rs + + + +ミューテックスは、2つの規則を覚えておく必要があるため、難しいという評判があります: + + + + + +1. データを使用する前にロックの獲得を試みなければならない。 +2. ミューテックスが死守しているデータの使用が終わったら、他のスレッドがロックを獲得できるように、 + データをアンロックしなければならない。 + + + + + + + + + + +ミューテックスを現実世界の物で例えるなら、マイクが1つしかない会議のパネルディスカッションを思い浮かべてください。 +パネリストが発言できる前に、マイクを使用したいと申し出たり、通知しなければなりません。マイクを受け取ったら、 +話したいだけ話し、それから次に発言を申し出たパネリストにマイクを手渡します。パネリストが発言し終わった時に、 +マイクを手渡すのを忘れていたら、誰も他の人は発言できません。共有されているマイクの管理がうまくいかなければ、 +パネルは予定通りに動かないでしょう! + + + + + +ミューテックスの管理は、正しく行うのに著しく巧妙なことがあるので、多くの人がチャンネルに熱狂的になるわけです。 +しかしながら、Rustの型システムと所有権ルールのおかげで、ロックとアンロックを間違えることはありません。 + + + +#### `Mutex`のAPI + + + + +ミューテックスの使用方法の例として、ミューテックスをシングルスレッドの文脈で使うことから始めましょう。 +リスト16-12のようにね: + + + +ファイル名: src/main.rs ```rust use std::sync::Mutex; @@ -68,46 +115,79 @@ fn main() { } ``` -Listing 16-12: Exploring the API of `Mutex` in a -single-threaded context for simplicity + + + +リスト16-12: 簡潔性のために`Mutex`のAPIをシングルスレッドの文脈で探求する + + + + + + +多くの型同様、`new`という関連関数を使用して`Mutex`を生成します。ミューテックス内部のデータにアクセスするには、 +`lock`メソッドを使用してロックを獲得します。この呼び出しは、現在のスレッドをブロックするので、 +ロックを得られる順番が来るまで何も作業はできません。 + + + + + +ロックを保持している他のスレッドがパニックしたら、`lock`の呼び出しは失敗するでしょう。その場合、 +誰もロックを取得することは叶わないので、`unwrap`すると決定し、そのような状況になったら、 +このスレッドをパニックさせます。 + + + + + + -As with many types, we create a `Mutex` using the associated function `new`. -To access the data inside the mutex, we use the `lock` method to acquire the -lock. This call will block the current thread so it can’t do any work until -it’s our turn to have the lock. +ロックを獲得した後、今回の場合、`num`と名付けられていますが、戻り値を中に入っているデータへの可変参照として扱うことができます。 +型システムにより、`m`の値を使用する前にロックを獲得していることが確認されます: `Mutex`は`i32`ではないので、 +`i32`を使用できるようにするには、ロックを獲得し*なければならない*のです。忘れることはあり得ません; +型システムにより、それ以外の場合に内部の`i32`にアクセスすることは許されません。 -The call to `lock` would fail if another thread holding the lock panicked. In -that case, no one would ever be able to get the lock, so we’ve chosen to -`unwrap` and have this thread panic if we’re in that situation. + + + + + + + + -After we’ve acquired the lock, we can treat the return value, named `num` in -this case, as a mutable reference to the data inside. The type system ensures -that we acquire a lock before using the value in `m`: `Mutex` is not an -`i32`, so we *must* acquire the lock to be able to use the `i32` value. We -can’t forget; the type system won’t let us access the inner `i32` otherwise. +疑っているかもしれませんが、`Mutex`はスマートポインタです。より正確を期すなら、 +`lock`の呼び出しが`MutexGuard`というスマートポインタを*返却*します。このスマートポインタが、 +内部のデータを指す`Deref`を実装しています; このスマートポインタはさらに`MutexGuard`がスコープを外れた時に、 +自動的にロックを解除する`Drop`実装もしていて、これがリスト16-12の内部スコープの終わりで発生します。 +結果として、ロックの解除を忘れ、ロックの解除が自動的に行われるので、 +ミューテックスが他のスレッドで使用されるのを阻害するリスクを負いません。 -As you might suspect, `Mutex` is a smart pointer. More accurately, the call -to `lock` *returns* a smart pointer called `MutexGuard`. This smart pointer -implements `Deref` to point at our inner data; the smart pointer also has a -`Drop` implementation that releases the lock automatically when a `MutexGuard` -goes out of scope, which happens at the end of the inner scope in Listing -16-12. As a result, we don’t risk forgetting to release the lock and blocking -the mutex from being used by other threads because the lock release happens -automatically. + + -After dropping the lock, we can print the mutex value and see that we were able -to change the inner `i32` to 6. +ロックをドロップした後、ミューテックスの値を出力し、内部の`i32`の値を6に変更できたことが確かめられるのです。 -#### Sharing a `Mutex` Between Multiple Threads + -Now, let’s try to share a value between multiple threads using `Mutex`. -We’ll spin up 10 threads and have them each increment a counter value by 1, so -the counter goes from 0 to 10. Note that the next few examples will have -compiler errors, and we’ll use those errors to learn more about using -`Mutex` and how Rust helps us use it correctly. Listing 16-13 has our -starting example: +#### 複数のスレッド間で`Mutex`を共有する -Filename: src/main.rs + + + + + + + +さて、`Mutex`を使って複数のスレッド間で値を共有してみましょう。10個のスレッドを立ち上げ、 +各々カウンタの値を1ずつインクリメントさせるので、カウンタは0から10まで上がります。 +以下の数例は、コンパイルエラーになることに注意し、そのエラーを使用して`Mutex`の使用法と、 +コンパイラがそれを正しく扱う手助けをしてくれる方法について学びます。リスト16-13が最初の例です: + + + +ファイル名: src/main.rs ```rust,ignore use std::sync::Mutex; @@ -134,26 +214,41 @@ fn main() { } ``` -Listing 16-13: Ten threads each increment a counter -guarded by a `Mutex` + + + +リスト16-13: `Mutex`により死守されているカウンタを10個のスレッドがそれぞれインクリメントする + + + + + + + + -We’re creating a `counter` variable to hold an `i32` inside a `Mutex`, as we -did in Listing 16-12. Next, we’re creating 10 threads by mapping over a range -of numbers. We use `thread::spawn` and give all the threads the same closure, -one that moves the counter into the thread, acquires a lock on the `Mutex` -by calling the `lock` method, and then adds 1 to the value in the mutex. When a -thread finishes running its closure, `num` will go out of scope and release the -lock so another thread can acquire it. +リスト16-12のように、`counter`変数を生成して`Mutex`の内部に`i32`を保持しています。 +次に、数値の範囲をマッピングして10個のスレッドを生成しています。`thread::spawn`を使用して、 +全スレッドに同じクロージャを与えています。このクロージャは、スレッド内にカウンタをムーブし、 +`lock`メソッドを呼ぶことで`Mutex`のロックを獲得し、それからミューテックスの値に1を足します。 +スレッドがクロージャを実行し終わったら、`num`はスコープ外に出てロックを解除するので、 +他のスレッドが獲得できるわけです。 -In the main thread, we collect all the join handles, as we did in Listing 16-2, -and then call `join` on each to make sure all the threads finish. At that -point, the main thread will acquire the lock and print the result of this -program. + + + + -We hinted that this example won’t compile, now let’s find out why! +メインスレッドでリスト16-2のように全てのjoinハンドルを収集し、それから各々に対して`join`を呼び出し、 +全スレッドが終了するのを確かめています。その時点で、メインスレッドはロックを獲得し、このプログラムの結果を出力します。 + + + +この例はコンパイルできないと仄めかしたので、では、理由を探りましょう! ```text error[E0382]: capture of moved value: `counter` +(エラー: ムーブされた値をキャプチャしています: `counter`) --> src/main.rs:10:27 | 9 | let handle = thread::spawn(move || { @@ -177,15 +272,23 @@ error[E0382]: use of moved value: `counter` which does not implement the `Copy` trait error: aborting due to 2 previous errors +(エラー: 前述の2つのエラーによりアボート) ``` -The error message states that the `counter` value is moved into the closure and -then is captured when we call `lock`. That description sounds like what we -wanted, but it’s not allowed! + + + + +エラーメッセージは、`counter`値はクロージャにムーブされ、それから`lock`を呼び出したときにキャプチャされていると述べています。 +その説明は、所望した動作のように聞こえますが、許可されていないのです! + + + + -Let’s figure this out by simplifying the program. Instead of making 10 threads -in a `for` loop, let’s just make two threads without a loop and see what -happens. Replace the first `for` loop in Listing 16-13 with this code instead: +プログラムを単純化してこれを理解しましょう。`for`ループで10個スレッドを生成する代わりに、 +ループなしで2つのスレッドを作るだけにしてどうなるか確認しましょう。 +リスト16-13の最初の`for`ループを代わりにこのコードと置き換えてください: ```rust,ignore let handle = thread::spawn(move || { @@ -203,9 +306,12 @@ let handle2 = thread::spawn(move || { handles.push(handle2); ``` -We make two threads and change the variable names used with the second thread -to `handle2` and `num2`. When we run the code this time, compiling gives us the -following: + + + + +2つのスレッドを生成し、2番目のスレッドの変数名を`handle2`と`num2`に変更しています。 +今回このコードを走らせると、コンパイラは以下の出力をします: ```text error[E0382]: capture of moved value: `counter` @@ -235,25 +341,40 @@ error[E0382]: use of moved value: `counter` error: aborting due to 2 previous errors ``` -Aha! The first error message indicates that `counter` is moved into the closure -for the thread associated with `handle`. That move is preventing us from -capturing `counter` when we try to call `lock` on it and store the result in -`num2` in the second thread! So Rust is telling us that we can’t move ownership -of `counter` into multiple threads. This was hard to see earlier because our -threads were in a loop, and Rust can’t point to different threads in different -iterations of the loop. Let’s fix the compiler error with a multiple-ownership -method we discussed in Chapter 15. + + + + + + + + + +なるほど!最初のメッセージは、`handle`に紐付けられたスレッドのクロージャに`counter`がムーブされていることを示唆しています。 +そのムーブにより、それに対して`lock`を呼び出し、結果を2番目のスレッドの`num2`に保持しようとした時に、 +`counter`をキャプチャすることを妨げています。これは、以前では確認しづらかったことです。 +なぜなら、スレッドはループの中にあり、ループの違う繰り返しにある違うスレッドをコンパイラは指し示せないからです。 +第15章で議論した複数所有権メソッドによりコンパイルエラーを修正しましょう。 + + + +#### 複数のスレッドで複数の所有権 + + + + + + + -#### Multiple Ownership with Multiple Threads +第15章で、スマートポインタの`Rc`を使用して参照カウントの値を作ることで、1つの値に複数の所有者を与えました。 +同じことをここでもして、どうなるか見ましょう。リスト16-14で`Rc`に`Mutex`を包含し、 +所有権をスレッドに移す前に`Rc`をクローンします。今やエラーを確認したので、 +`for`ループの使用に立ち戻り、クロージャに`move`キーワードを使用し続けます: -In Chapter 15, we gave a value multiple owners by using the smart pointer -`Rc` to create a reference-counted value. Let’s do the same here and see -what happens. We’ll wrap the `Mutex` in `Rc` in Listing 16-14 and clone -the `Rc` before moving ownership to the thread. Now that we’ve seen the -errors, we’ll also switch back to using the `for` loop, and we’ll keep the -`move` keyword with the closure: + -Filename: src/main.rs +ファイル名: src/main.rs ```rust,ignore use std::rc::Rc; @@ -282,71 +403,114 @@ fn main() { } ``` -Listing 16-14: Attempting to use `Rc` to allow -multiple threads to own the `Mutex` + + -Once again, we compile and get... different errors! The compiler is teaching us -a lot. +リスト16-14: `Rc`を使用して複数のスレッドに`Mutex`を所有させようとする + + + + +再三、コンパイルし……別のエラーが出ました!コンパイラはいろんなことを教えてくれています。 ```text error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `[closure@src/main.rs:11:36: 15:10 counter:std::rc::Rc>]` +(エラー: トレイト境界`std::rc::Rc>: +std::marker::Send`は`[closure@src/main.rs:11:36:15:10 +counter:std::rc::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`により必要とされています) ``` -Wow, that error message is very wordy! Here are some important parts to focus -on: the first inline error says `` `std::rc::Rc>` cannot -be sent between threads safely ``. The reason for this is in the next important -part to focus on, the error message. The distilled error message says `` the -trait bound `Send` is not satisfied ``. We’ll talk about `Send` in the next -section: it’s one of the traits that ensures the types we use with threads are -meant for use in concurrent situations. - -Unfortunately, `Rc` is not safe to share across threads. When `Rc` -manages the reference count, it adds to the count for each call to `clone` and -subtracts from the count when each clone is dropped. But it doesn’t use any -concurrency primitives to make sure that changes to the count can’t be -interrupted by another thread. This could lead to wrong counts—subtle bugs that -could in turn lead to memory leaks or a value being dropped before we’re done -with it. What we need is a type exactly like `Rc` but one that makes changes -to the reference count in a thread-safe way. - -#### Atomic Reference Counting with `Arc` - -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. - -You might then wonder why all primitive types aren’t atomic and why standard -library types aren’t implemented to use `Arc` by default. The reason is that -thread safety comes with a performance penalty that you only want to pay when -you really need to. If you’re just performing operations on values within a -single thread, your code can run faster if it doesn’t have to enforce the -guarantees atomics provide. - -Let’s return to our example: `Arc` and `Rc` have the same API, so we fix -our program by changing the `use` line and the call to `new`. The code in -Listing 16-15 will finally compile and run: - -Filename: src/main.rs + + + + + + + + +おお、このエラーメッセージはとても長ったらしいですね!こちらが、注目すべき重要な部分です: +最初のインラインエラーは`` `std::rc::Rc>` cannot be sent +between threads safely``と述べています。蒸留されたエラーメッセージは、`` the trait bound +`Send` is not satisfied``と述べています。`Send`については、次の節で語ります: +スレッドとともに使用している型が非同期処理の場面で使われることを意図したものであることを保証するトレイトの1つです。 + + + + + + + + + + +残念ながら、`Rc`はスレッド間で共有するには安全ではないのです。`Rc`が参照カウントを管理する際、 +`clone`が呼び出されるたびにカウントを追加し、クローンがドロップされるたびにカウントを差し引きます。 +しかし、非同期基本型を使用してカウントの変更が別のスレッドに妨害されないことを確認していないのです。 +これは間違ったカウントにつながる可能性があり、今度はメモリリークや、使用し終わる前に値がドロップされることにつながる可能性のある潜在的なバグです。 +必要なのは、全く`Rc`のようだけれども、参照カウントへの変更をスレッドセーフに行うものです。 + + + +#### `Arc`で原子的な参照カウント + + + + + + + + + +幸いなことに、`Arc`は`Rc`のような非同期処理の状況で安全に使用できる型*です*。 +'a'は*atomic*を表し、原子的に参照カウントする型を意味します。アトミックは、 +ここでは詳しく講義しない非同期処理の別の基本型です: 詳細は、 +`std::sync::atomic`の標準ライブラリドキュメンテーションを参照されたし。現時点では、 +アトミックは、基本型のように動くけれども、スレッド間で共有しても安全なことだけ知っていればいいです。 + + + + + + + + +そうしたら、なぜ全ての基本型がアトミックでなく、標準ライブラリの型も標準で`Arc`を使って実装されていないのか疑問に思う可能性があります。 +その理由は、本当に必要な時だけ支払いたいパフォーマンスの犠牲とともにスレッド安全性が得られるものだからです。 +シングルスレッドで値に処理を施すだけなら、アトミックが提供する保証を強制する必要がなければコードはより速く走るのです。 + + + + + +例に回帰しましょう: `Arc`と`Rc`のAPIは同じなので、`use`行と`new`の呼び出しを変更して、 +プログラムを修正します。リスト16-15は、ようやくコンパイルでき、動作します: + + + +ファイル名: src/main.rs ```rust use std::sync::{Mutex, Arc}; @@ -374,41 +538,70 @@ fn main() { } ``` -Listing 16-15: Using an `Arc` to wrap the `Mutex` -to be able to share ownership across multiple threads + + + +リスト16-15: `Arc`を使用して`Mutex`をラップし、所有権を複数のスレッド間で共有できるようにする + + -This code will print the following: +このコードは、以下のように出力します: ```text Result: 10 ``` -We did it! We counted from 0 to 10, which may not seem very impressive, but it -did teach us a lot about `Mutex` and thread safety. You could also use this -program’s structure to do more complicated operations than just incrementing a -counter. Using this strategy, you can divide a calculation into independent -parts, split those parts across threads, then use a `Mutex` to have each -thread update the final result with its part. - -### Similarities Between `RefCell`/`Rc` and `Mutex`/`Arc` - -You might have noticed that `counter` is immutable, but we could get a mutable -reference to the value inside it; this means `Mutex` provides interior -mutability, like the `Cell` family does. In the same way we used `RefCell` -in Chapter 15 to allow us to mutate contents inside an `Rc`, we use -`Mutex` to mutate contents inside an `Arc`. - -Another detail to note is that Rust can’t protect us from all kinds of logic -errors when we use `Mutex`. Recall in Chapter 15 that using `Rc` came -with the risk of creating reference cycles, where two `Rc` values refer to -each other, causing memory leaks. Similarly, `Mutex` comes with the risk of -creating *deadlocks*. These occur when an operation needs to lock two resources -and two threads have each acquired one of the locks, causing them to wait for -each other forever. If you’re interested in deadlocks, try creating a Rust -program that has a deadlock; then research deadlock mitigation strategies for -mutexes in any language and have a go at implementing them in Rust. The -standard library API documentation for `Mutex` and `MutexGuard` offers -useful information. - -We’ll round out this chapter by talking about the `Send` and `Sync` traits, and -how we can use them with custom types. + + + + + + + +やりました!0から10まで数え上げました。これは、あまり印象的ではないように思えるかもしれませんが、 +本当に`Mutex`とスレッド安全性についていろんなことを教えてくれました。このプログラムの構造を使用して、 +カウンタをインクリメントする以上の複雑な処理を行うこともできるでしょう。この手法を使えば、 +計算を独立した部分に小分けにし、その部分をスレッドに分割し、それから`Mutex`を使用して、 +各スレッドに最終結果を更新させることができます。 + + + +### `RefCell`/`Rc`と`Mutex`/`Arc`の類似性 + + + + + + + +`counter`は不変なのに、その内部にある値への可変参照を得ることができたことに気付いたでしょうか; +つまり、`Mutex`は、`Cell`系のように内部可変性(interior mutability)を提供するわけです。 +第15章で`RefCell`を使用して`Rc`の内部の内容を可変化できるようにしたのと同様に、 +`Mutex`を使用して`Arc`の内部の内容を可変化しているのです。 + + + + + + + + + + + + + +また、気付いておくべき別の詳細は、`Mutex`を使用する際にあらゆる種類のロジックエラーからは、 +コンパイラは保護してくれないということです。第15章で`Rc`は、循環参照を生成してしまうリスクを伴い、 +2つの`Rc`の値がお互いを参照し合い、メモリリークを引き起こしてしまうことを思い出してください。 +同様に、`Mutex`は*デッドロック*を生成するリスクを伴っています。これは、処理が2つのリソースをロックする必要があり、 +2つのスレッドがそれぞれにロックを1つ獲得して永久にお互いを待ちあってしまうときに起こります。 +デッドロックに興味があるのなら、デッドロックのあるRustプログラムを組んでみてください; +それからどんな言語でもいいので、ミューテックスに対してデッドロックを緩和する方法を調べて、 +Rustでそれを実装してみてください。`Mutex`と`MutexGuard`に関する標準ライブラリのAPIドキュメンテーションは、 +役に立つ情報を提供してくれます。 + + + + +`Send`と`Sync`トレイトと、それらを独自の型で使用する方法について語って、この章を締めくくります。 From ff8f0796a4219df41bf501d9148705b9097751c7 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 29 Jan 2018 19:09:14 +0900 Subject: [PATCH 100/428] First draft of the chapter 16-4 --- ...04-extensible-concurrency-sync-and-send.md | 239 ++++++++++++------ 1 file changed, 155 insertions(+), 84 deletions(-) diff --git a/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md b/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md index cddad071f..fb867771b 100644 --- a/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md +++ b/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md @@ -1,88 +1,159 @@ -## Extensible Concurrency with the `Sync` and `Send` Traits - -Interestingly, the Rust language has *very* few concurrency features. Almost -every concurrency feature we’ve talked about so far in this chapter has been -part of the standard library, not the language. Our options for handling -concurrency are not limited to the language or the standard library; we can -write our own concurrency features or use those written by others. - -However, two concurrency concepts are embedded in the language: the -`std::marker` traits `Sync` and `Send`. - -### Allowing Transference of Ownership Between Threads with `Send` - -The `Send` marker trait indicates that ownership of the type implementing -`Send` can be transferred between threads. Almost every Rust type is `Send`, -but there are some exceptions, including `Rc`: this cannot be `Send` because -if we cloned an `Rc` value and tried to transfer ownership of the clone to -another thread, both threads might update the reference count at the same time. -For this reason, `Rc` is implemented for use in single-threaded situations -where you don’t want to pay the thread-safe performance penalty. - -Therefore, Rust’s type system and trait bounds ensure that we can never -accidentally send an `Rc` value across threads unsafely. When we tried to do -this in Listing 16-14, we got the error `the trait Send is not implemented for -Rc>`. When we switched to `Arc`, which is `Send`, the code -compiled. - -Any type composed entirely of `Send` types is automatically marked as `Send` as -well. Almost all primitive types are `Send`, aside from raw pointers, which -we’ll discuss in Chapter 19. - -### Allowing Access from Multiple Threads with `Sync` - -The `Sync` marker trait indicates that it is safe for the type implementing -`Sync` to be referenced from multiple threads. In other words, any type `T` is -`Sync` if `&T` (a reference to `T`) is `Send`, meaning the reference can be -sent safely to another thread. Similar to `Send`, primitive types are `Sync` -and types composed entirely of types that are `Sync` are also `Sync`. - -The smart pointer `Rc` is also not `Sync` for the same reasons that it’s not -`Send`. The `RefCell` type (which we talked about in Chapter 15) and the -family of related `Cell` types are not `Sync`. The implementation of borrow -checking that `RefCell` does at runtime is not thread-safe. The smart -pointer `Mutex` is `Sync` and can be used to share access with multiple -threads, as you saw in the “Sharing a `Mutex` Between Multiple Threads” -section. - -### Implementing `Send` and `Sync` Manually Is Unsafe - -Because types that are made up of `Send` and `Sync` traits are automatically -also `Send` and `Sync`, we don’t have to implement those traits manually. As -marker traits, they don’t even have any methods to implement. They’re just -useful for enforcing invariants related to concurrency. - -Manually implementing these traits involves implementing unsafe Rust code. -We’ll talk about using unsafe Rust code in Chapter 19; for now, the important -information is that building new concurrent types not made up of `Send` and -`Sync` parts requires careful thought to uphold the safety guarantees. [The -Rustonomicon] has more information about these guarantees and how to uphold -them. + + +## `Sync`と`Send`トレイトで拡張可能な非同期処理 + + + + + + + +面白いことに、Rust言語には、*寡*少な非同期機能があります。この章でここまでに語った非同期処理のほとんどは、 +標準ライブラリの一部であり、言語ではありません。非同期を扱う選択肢は、言語や標準ライブラリに制限されません; +独自の非同期処理機能を書いたり、他人が書いたものを利用したりできるのです。 + + + + +ですが、2つの非同期処理概念が言語に埋め込まれています: `std::marker`トレイトの`Sync`と`Send`です。 + + + +### `Send`でスレッド間の所有権の転送を許可する + + + + + + + + + + + +`Send`マーカートレイトは、`Send`を実装した型の所有権をスレッド間で転送できることを示唆します。 +Rustのほとんどの型は`Send`ですが、`Rc`を含めて一部例外があります: この型は、`Rc`の値をクローンし、 +クローンしたものの所有権を別のスレッドに転送しようとしたら、両方のスレッドが同時に参照カウントを更新できてしまうので、 +`Send`になり得ません。このため、`Rc`はスレッド安全性のためのパフォーマンスの犠牲を支払わなくても済む、 +シングルスレッド環境で使用するために実装されているわけです。 + + + + + + + +故に、Rustの型システムとトレイト境界により、`Rc`の値を不安全にスレッド間で誤って送信することが絶対ないよう保証してくれるのです。 +リスト16-14でこれを試みた時には、`the trait Send is not implemented for Rc>`というエラーが出ました。 +`Send`の`Arc`に切り替えたら、コードはコンパイルできたわけです。 + + + + + +完全に`Send`の型からなる型も全て自動的に`Send`と印付けされます。生ポインタを除くほとんどの基本型も`Send`で、 +生ポインタについては第19章で議論します。 + + + +### `Sync`で複数のスレッドからのアクセスを許可する + + + + + + + +`Sync`マーカートレイトは、`Sync`を実装した型は、複数のスレッドから参照されても安全であることを示唆します。 +言い換えると、`&T`(`T`への参照)が`Send`なら、型`T`は`Sync`であり、参照が他のスレッドに安全に送信できることを意味します。 +`Send`同様、基本型は`Sync`であり、`Sync`の型からのみ構成される型もまた`Sync`です。 + + + + + + + + + +`Send`ではなかったのと同じ理由で、スマートポインタの`Rc`もまた`Sync`ではありません。 +`RefCell`型(これについては第15章で話しました)と`Cell`系についても`Sync`ではありません。 +`RefCell`が実行時に行う借用チェックの実装は、スレッド安全ではないのです。 +スマートポインタの`Mutex`は`Sync`で、「複数のスレッド間で`Mutex`を共有する」節で見たように、 +複数のスレッドでアクセスを共有するのに使用することができます。 + + + +### `Send`と`Sync`を手動で実装するのは非安全である + + + + + + +`Send`と`Sync`トレイトから構成される型は自動的に`Send`と`Sync`にもなるので、 +それらのトレイトを手動で実装する必要はありません。マーカートレイトとして、 +実装すべきメソッドさえも何もありません。非同期処理に関連する不変条件を強制することに有効なだけなのです。 + + + + + + + + +これらのトレイトを手動で実装すると、unsafeなRustコードを実装することが関わってきます。 +unsafeなRustコードを使用することについては第19章で語ります; とりあえず、重要な情報は、 +`Send`と`Sync`ではない部品からなる新しい非同期型を構成するには、安全性保証を保持するために、 +注意深い思考が必要になるということです。[The Rustonomicon]には、 +これらの保証とそれを保持する方法についての情報がより多くあります。 [The Rustonomicon]: https://doc.rust-lang.org/stable/nomicon/ -## Summary - -This isn’t the last you’ll see of concurrency in this book: the project in -Chapter 20 will use the concepts examined in this chapter in a more realistic -situation than the smaller examples discussed here. - -As mentioned earlier, because very little of how Rust handles concurrency is -part of the language, many concurrency solutions are implemented as crates. -These evolve more quickly than the standard library, so be sure to search -online for the current, state-of-the-art crates to use in multithreaded -situations. - -The Rust standard library provides channels for message passing and smart -pointer types, such as `Mutex` and `Arc`, that are safe to use in -concurrent contexts. The type system and the borrow checker ensure that the -code using these solutions won’t end up with data races or invalid references. -Once we get our code to compile, we can rest assured that it will happily run -on multiple threads without the kinds of hard-to-track-down bugs common in -other languages. Concurrent programming is no longer a concept to be afraid of: -go forth and make your programs concurrent, fearlessly! - -Next, we’ll talk about idiomatic ways to model problems and structure solutions -as your Rust programs get bigger. In addition, we’ll discuss how Rust’s idioms -relate to those you might be familiar with from object oriented programming. + + +## まとめ + + + + + +この本において非同期処理を見かけるのは、これで最後ではありません: 第20章のプロジェクトでは、 +この章で調査した概念をここで議論した微小な例よりもより現実的な場面で使用するでしょう。 + + + + + + + + + +前述のように、Rustが非同期処理を扱うごく一部が言語の一部なので、多くの非同期処理解決策は、 +クレートとして実装されています。これらは標準ライブラリよりも迅速に進化するので、 +確実にオンラインでマルチスレッド環境で使用する現在の最先端のクレートを検索してください。 + + + + + + + + + + +Rustの標準ライブラリは、メッセージ受け渡しにチャンネルを、非同期処理の文脈で安全に使用できる、 +`Mutex`や`Arc`などのスマートポインタ型を提供しています。型システムと借用精査機により、 +これらの解決策を使用するコードがデータ競合や無効な参照に行き着かないことを保証してくれます。 +一旦コードをコンパイルすることができたら、他の言語ではありふれている追跡困難なバグなしに、 +複数のスレッドでも喜んで動くので安心できます。非同期プログラミングは、もはや恐れるべき概念ではありません: +進んでプログラムを非同期にして恐れないでください! + + + + + + +次は、Rustプログラムが肥大化するにつれて問題をモデル化し、解決策を構造化する慣例的な方法について話します。 +さらに、Rustのイディオムがオブジェクト指向プログラミングで馴染み深いかもしれないイディオムに関連する方法についても議論します。 From 2d78373e6dbadc18d02ddd611b9ff98281871485 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 29 Jan 2018 22:06:51 +0900 Subject: [PATCH 101/428] Add a statement on README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ffe0d1489..14a6eba26 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ some of the peopleも(一部の人々)などと訳し、[`いくつか`]は`a fe * 逆にyou, your, we, ourなどの英語の文法上仕方なく出てくる人称代名詞は日本語には訳さない方が自然なことが多いので無理に訳に出さない。 特に、一般論を語る時のyouは 訳してはならない 参考 【雑談】"あなた"と訳さない"you" ~ einzelzelle * (こんな訳し方はしないので、大丈夫です) * このような代名詞に関しては、訳出しないと不自然な場合のみ、訳します +* 「している」「していく」を「してる」「してく」と訳さないこと。後者は会話などの口語では一般的ですが、あくまでもこれは公式の文書なので、似つかわしくありません。 [translation-table]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/TranslationTable.md [contributing]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/CONTRIBUTING.md From c5c7e289f0ee2a6bc6d9f5e5bc8b8b5a0d80cc82 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 29 Jan 2018 22:26:47 +0900 Subject: [PATCH 102/428] Add a statement on README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 14a6eba26..49795eebc 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ some of the peopleも(一部の人々)などと訳し、[`いくつか`]は`a fe * (こんな訳し方はしないので、大丈夫です) * このような代名詞に関しては、訳出しないと不自然な場合のみ、訳します * 「している」「していく」を「してる」「してく」と訳さないこと。後者は会話などの口語では一般的ですが、あくまでもこれは公式の文書なので、似つかわしくありません。 +* doの強調用法(I do appreciate it!)は、「実は」「本当に」「実際に」などと訳出します。 [translation-table]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/TranslationTable.md [contributing]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/CONTRIBUTING.md From 4cf11a567616736494abd096e5a01d764a9fbe61 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 29 Jan 2018 22:41:24 +0900 Subject: [PATCH 103/428] Add several statements on README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 49795eebc..dbbb6e936 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,11 @@ some of the peopleも(一部の人々)などと訳し、[`いくつか`]は`a fe * このような代名詞に関しては、訳出しないと不自然な場合のみ、訳します * 「している」「していく」を「してる」「してく」と訳さないこと。後者は会話などの口語では一般的ですが、あくまでもこれは公式の文書なので、似つかわしくありません。 * doの強調用法(I do appreciate it!)は、「実は」「本当に」「実際に」などと訳出します。 +* 元来、日本語は無生物主語を嫌う言語なので、主語位置にある無生物は、「により」「によって」「のおかげで」などと訳出し、無生物主語を避けます。 +* 基本動詞のhaveですが、上記の方針により、基本的に「AにBがある」「AにBが存在する」などと訳し、「持つ」という訳語を極力避けます。 + +### PRのマージについて +* PRをマージする際にレビューしていただいた部分について、議論が必要そうと感じた部分については、「TODO:」コメントを付します。これを目安に議論する際には、検索をかけてください [translation-table]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/TranslationTable.md [contributing]: https://github.com/rust-lang-ja/the-rust-programming-language-ja/blob/master/CONTRIBUTING.md From 2d296cf20e2d95542610c1edeafea3063bddfe5b Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 29 Jan 2018 23:00:13 +0900 Subject: [PATCH 104/428] Add another statement on README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dbbb6e936..e9c1f53ae 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ some of the peopleも(一部の人々)などと訳し、[`いくつか`]は`a fe * doの強調用法(I do appreciate it!)は、「実は」「本当に」「実際に」などと訳出します。 * 元来、日本語は無生物主語を嫌う言語なので、主語位置にある無生物は、「により」「によって」「のおかげで」などと訳出し、無生物主語を避けます。 * 基本動詞のhaveですが、上記の方針により、基本的に「AにBがある」「AにBが存在する」などと訳し、「持つ」という訳語を極力避けます。 +* 命令文は、基本的に「〜してください」と訳します。 ### PRのマージについて * PRをマージする際にレビューしていただいた部分について、議論が必要そうと感じた部分については、「TODO:」コメントを付します。これを目安に議論する際には、検索をかけてください From 463bbb2e83a203ef97db3931147692a53e7c31db Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 30 Jan 2018 18:54:21 +0900 Subject: [PATCH 105/428] Add sevaral rules on README.md --- README.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e9c1f53ae..ee1688d03 100644 --- a/README.md +++ b/README.md @@ -56,11 +56,24 @@ some of the peopleも(一部の人々)などと訳し、[`いくつか`]は`a fe * 逆にyou, your, we, ourなどの英語の文法上仕方なく出てくる人称代名詞は日本語には訳さない方が自然なことが多いので無理に訳に出さない。 特に、一般論を語る時のyouは 訳してはならない 参考 【雑談】"あなた"と訳さない"you" ~ einzelzelle * (こんな訳し方はしないので、大丈夫です) * このような代名詞に関しては、訳出しないと不自然な場合のみ、訳します -* 「している」「していく」を「してる」「してく」と訳さないこと。後者は会話などの口語では一般的ですが、あくまでもこれは公式の文書なので、似つかわしくありません。 +* 「している」「していく」を「*してる*」「*してく*」と訳さないこと。後者は会話などの口語では一般的ですが、あくまでもこれは公式の文書なので、似つかわしくありません。 * doの強調用法(I do appreciate it!)は、「実は」「本当に」「実際に」などと訳出します。 * 元来、日本語は無生物主語を嫌う言語なので、主語位置にある無生物は、「により」「によって」「のおかげで」などと訳出し、無生物主語を避けます。 -* 基本動詞のhaveですが、上記の方針により、基本的に「AにBがある」「AにBが存在する」などと訳し、「持つ」という訳語を極力避けます。 +* 基本動詞のhaveですが、上記の方針により、基本的に「AにBがある」「AにBが存在する」などと訳し、「持つ」という訳語を極力避けます(Rust have several wonderful features.のような文がよく出てくるので)。 * 命令文は、基本的に「〜してください」と訳します。 +* 時制について。日本語の時制は、英語ほど厳密ではなく、曖昧なことが多いため、あまり気にする必要はないと考えています。 + * 完了形は基本的に本来のイメージに近い「〜してきました」と訳していますが、単純に「〜しました」「〜しています」のように訳している箇所もあります。 + * 現在形を「〜しています」と訳している箇所もあります。 + * あと、文意から考えて、過去形を過去で訳していない箇所もあったようななかったような・・・ +* 助動詞について。助動詞の過去形についてですが、助動詞が過去を表すのは時制の一致を受けているときぐらいであり、普通助動詞を使いつつ過去の意味を表したい場合、助動詞の後を完了形にするので、その代わりに意味を弱めて訳しています(If I were(was) there, I could've done it.)。一部、意味を弱めていない場合もあります。 + * `will`(でしょう) ↔︎ `would`(でしょう): `would`は日本語に訳すなら(かもなぁ)ぐらいの意味ですが、敬体で表すことができないため、同じにしています。 + * `can`(できます) ↔︎ `could`(できるでしょう) + * `may`(かもしれません) ↔︎ `might`(可能性があります) + * `should`の現在形は`shall`ですが、現代英語ではほぼ使用されないため、除外します。`should`は訳すなら、「べき」「はず」と訳します。 + * `must`に過去形はありません(辞書には、過去形は`had to`と書いてありましたが)。 + * 助動詞っぽいですが、`have to`は例外です。`had to`で普通、過去の意味を表します。 + * あと、`ought to`という表現もありますが、あまり見かけたことはありません。 +* 漢字について。常用外の漢字について、特に難読と思われるものについては`ruby`タグでルビを振ります。常用漢字であっても、常用外の読みの場合には、ルビを振るよう心がけます。 ### PRのマージについて * PRをマージする際にレビューしていただいた部分について、議論が必要そうと感じた部分については、「TODO:」コメントを付します。これを目安に議論する際には、検索をかけてください From b150b4ed6ee39d00d898d7168ae8d3494a630b8f Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Wed, 31 Jan 2018 20:02:06 +0900 Subject: [PATCH 106/428] Fix mistakes in the chapter 14 --- .../src/ch14-01-release-profiles.md | 4 +- .../src/ch14-02-publishing-to-crates-io.md | 40 +++++++++---------- .../src/ch14-03-cargo-workspaces.md | 16 ++++---- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/second-edition/src/ch14-01-release-profiles.md b/second-edition/src/ch14-01-release-profiles.md index b7f95fba9..5a6b0303b 100644 --- a/second-edition/src/ch14-01-release-profiles.md +++ b/second-edition/src/ch14-01-release-profiles.md @@ -73,7 +73,7 @@ opt-level = 3 最適化を多くかけると、コンパイル時間が延びるので、開発中に頻繁にコードをコンパイルするのなら、 出力結果のコードの動作速度が遅くなるのと引き換えにでも早くコンパイルが済んでほしいですよね。 これが、`dev`の`opt-level`のデフォルト設定が`0`になっている唯一の理由です。 -コードのリリース準備ができたら、より長い時間をコンパイルにかけるのが最善です。 +コードのリリース準備ができたら、より長い時間をコンパイルにかけるのが最善の策です。 リリースモードでコンパイルするのはたった1回で、コンパイル結果のプログラムは何度も実行するので、 リリースモードでは、長いコンパイル時間と引き換えに、生成したコードが速く動作します。 これが`release`の`opt-level`のデフォルト設定が`3`になっている唯一の理由です。 @@ -107,4 +107,4 @@ opt-level = 1 -設定の選択肢と各プロファイルのデフォルト設定の一覧は、[Cargoのドキュメント](https://doc.rust-lang.org/cargo/)を参照されたし。 +設定の選択肢と各プロファイルのデフォルト設定の一覧は、[Cargoのドキュメンテーション](https://doc.rust-lang.org/cargo/)を参照されたし。 diff --git a/second-edition/src/ch14-02-publishing-to-crates-io.md b/second-edition/src/ch14-02-publishing-to-crates-io.md index 0e8662edb..3075991a9 100644 --- a/second-edition/src/ch14-02-publishing-to-crates-io.md +++ b/second-edition/src/ch14-02-publishing-to-crates-io.md @@ -8,7 +8,7 @@ -プロジェクトの依存ファイルとして[crates.io](https://crates.io)のパッケージを使用しましたが、 +プロジェクトの依存として[crates.io](https://crates.io)のパッケージを使用しましたが、 自分のパッケージを公開することで他の人が使えるようにコードを共有することもできます。 [crates.io](https://crates.io)のクレート登録所は、自分のパッケージのソースコードを配布するので、 主にオープンソースのコードをホストします。 @@ -93,7 +93,7 @@ HTMLドキュメントを生成することができます。このコマンド 利便性のために、`cargo doc --open`を走らせれば、現在のクレートのドキュメント用のHTML(と、 -自分のクレートの依存ファイル全てのドキュメント)を構築し、その結果をWebブラウザで開きます。 +自分のクレートが依存している全てのドキュメント)を構築し、その結果をWebブラウザで開きます。 `add_one`関数まで下り、図14-1に示したように、ドキュメンテーションコメントのテキストがどう描画されるかを確認しましょう: @@ -114,7 +114,7 @@ HTMLドキュメントを生成することができます。このコマンド `# Examples`マークダウンのタイトルをリスト14-1で使用し、「例」というタイトルのセクションをHTMLに生成しました。 -これ以外にドキュメントでよく筆者が使用するセクションは: +これ以外にドキュメントでよくクレート筆者が使用するセクションは: @@ -129,17 +129,17 @@ HTMLドキュメントを生成することができます。このコマンド * **Panics**: ドキュメント対象の関数が`panic!`する可能性のある筋書きです。プログラムをパニックさせたくない関数の使用者は、 これらの状況で関数が呼ばれないことを確かめる必要があります。 -* **Errors**: 関数が`Result`を返すなら、起きうるエラーの種類とどんな条件がそれらのエラーを引き起こすのか解説すると、 +* **Errors**: 関数が`Result`を返すなら、起きうるエラーの種類とどんな条件がそれらのエラーを引き起こす可能性があるのか解説すると、 呼び出し側の役に立つので、いろんな方法で異なる種類のエラーを処理するコードを書くことができます。 -* **Safety**: 関数が呼び出すのに`unsafe`(非安全性については第19章で議論します)なら、 -関数が非安全な理由を説明し、関数が呼び出し元に保持していると期待する不変条件を講義するセクションがあるべきです。 +* **Safety**: 関数が呼び出すのに`unsafe`(unsafeについては第19章で議論します)なら、 +関数がunsafeな理由を説明し、関数が呼び出し元に保持していると期待する不変条件を講義するセクションがあるべきです。 多くのドキュメンテーションコメントのセクションでは、これら全てのセクションが必要になることはありませんが、 -自分のコードを呼び出している人が知りたいと思うコードの方向を思い出すときにチェックすべきいいリストになります。 +自分のコードを呼び出している人が知りたいと思うコードの方向性を思い出すときにチェックすべきいいリストになります。 @@ -175,8 +175,8 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -さて、例の`assert_eq!`がパニックするように関数か例を変更してください。再度`cargo test`を実行してください; -docテストが例とコードがお互いに同期されていないことを捕捉するところを目撃するでしょう! +さて、例の`assert_eq!`がパニックするように、関数か例を変更してください。再度`cargo test`を実行してください; +docテストが、例とコードがお互いに同期されていないことを捕捉するところを目撃するでしょう! @@ -286,7 +286,7 @@ docコメントの別スタイル、`//!`は、コメントに続く要素にド 自分の公開APIの構造は、クレートを公開する際に考慮すべき点です。自分のクレートを使用したい人は、 -自分よりもその構造に馴染みがないですし、クレートのモジュール階層が大きければ、使用したい部分を見つけるのが困難になるかもしれません。 +自分よりもその構造に馴染みがないですし、クレートのモジュール階層が大きければ、使用したい部分を見つけるのが困難になる可能性があります。 @@ -353,7 +353,7 @@ pub mod utils { -リスト14-3: `kinds`と`utils`モジュールに体系化される要素をふうむ`art`ライブラリ +リスト14-3: `kinds`と`utils`モジュールに体系化される要素を含む`art`ライブラリ @@ -374,7 +374,7 @@ pub mod utils { `PrimaryColor`も`SecondaryColor`型も、`mix`関数もトップページには列挙されていないことに注意してください。 -`kinds`と`utils`をクリックすれば、参照することができます。 +`kinds`と`utils`をクリックしなければ、参照することができません。 @@ -518,8 +518,8 @@ fn main() { -役に立つAPI構造を作ることは、科学というよりも芸術の領域であり、ユーザにとって何がベストのAPIなのか、 -探求するために繰り返してみることが出来ます。`pub use`は、内部的なクレート構造に柔軟性をもたらし、 +役に立つAPI構造を作ることは、科学というよりも芸術の領域であり、ユーザにとって何が最善のAPIなのか、 +探求するために繰り返してみることができます。`pub use`は、内部的なクレート構造に柔軟性をもたらし、 その内部構造とユーザに提示する構造を切り離してくれます。インストールしてある他のクレートを見て、 内部構造が公開APIと異なっているか確認してみてください。 @@ -618,7 +618,7 @@ error: api errors: missing or empty metadata fields: description, license. 他の人が自分のクレートは何をし、どんな条件の元で使っていいのかを知るために必要なのです。 このエラーを解消するには、*Cargo.toml*ファイルにこの情報を入れ込む必要があります。 - + @@ -668,7 +668,7 @@ Rust自体と同じようにプロジェクトをライセンスし、これは 独自の名前、バージョン、クレート作成時に`cargo new`が追加した筆者の詳細、説明、ライセンスが追加され、 -公開準備のできたプロジェクト用の`Cargo.toml`ファイルは以下のような見た目になっているかもしれません: +公開準備のできたプロジェクト用の`Cargo.toml`ファイルは以下のような見た目になっていることでしょう: @@ -691,7 +691,7 @@ license = "MIT OR Apache-2.0" [Cargoのドキュメンテーション](https://doc.rust-lang.org/cargo)には、 -指定して他人がより容易く発見しクレートを使用できる他のメタデータが解説されています。 +指定して他人が発見しより容易くクレートを使用できることを保証する他のメタデータが解説されています。 @@ -738,7 +738,7 @@ Uploading guessing_game v0.1.0 (file:///projects/guessing_game) -おめでとうございます!Rustコミュニティとコードを共有し、誰でも自分のクレートを依存ファイルとして簡単に追加できます。 +おめでとうございます!Rustコミュニティとコードを共有し、誰でも自分のクレートを依存として簡単に追加できます。 @@ -752,7 +752,7 @@ Uploading guessing_game v0.1.0 (file:///projects/guessing_game) クレートに変更を行い、新バージョンをリリースする準備ができたら、 *Cargo.toml*ファイルに指定された`version`の値を変更し、再公開します。 -[意味論バージョンルール][semver]を使用して加えた変更の種類に基づいて次の適切なバージョン番号を決定してください。 +[セマンティックバージョンルール][semver]を使用して加えた変更の種類に基づいて次の適切なバージョン番号を決定してください。 そして、`cargo publish`を実行し、新バージョンをアップロードします。 [semver]: http://semver.org/ @@ -768,7 +768,7 @@ Uploading guessing_game v0.1.0 (file:///projects/guessing_game) -以前のバージョンのクレートを削除することはできないものの、新しい依存ファイルとして将来的にプロジェクトに追加することを防ぐことはできます。 +以前のバージョンのクレートを削除することはできないものの、新しい依存として将来的にプロジェクトに追加することを防ぐことはできます。 ある理由により、クレートバージョンが壊れている場合に有用です。そのような場面において、 Cargoはクレートバージョンの*取り下げ*をサポートしています。 diff --git a/second-edition/src/ch14-03-cargo-workspaces.md b/second-edition/src/ch14-03-cargo-workspaces.md index ad4ea8bb7..018b4e384 100644 --- a/second-edition/src/ch14-03-cargo-workspaces.md +++ b/second-edition/src/ch14-03-cargo-workspaces.md @@ -10,7 +10,7 @@ 第12章で、バイナリクレートとライブラリクレートを含むパッケージを構築しました。プロジェクトの開発が進むにつれて、 -ライブラリクレートの肥大化が続き、さらに複数のライブラリクレートにパッケージを分割したくなります。 +ライブラリクレートの肥大化が続き、さらに複数のライブラリクレートにパッケージを分割したくなることでしょう。 この場面において、Cargoは*ワークスペース*という協調して開発された関連のある複数のパッケージを管理するのに役立つ機能を提供しています。 @@ -25,7 +25,7 @@ *ワークスペース*は、同じ*Cargo.lock*と出力ディレクトリを共有する一連のパッケージです。 ワークスペースを使用したプロジェクトを作成し、ワークスペースの構造に集中できるよう、瑣末なコードを使用しましょう。 -ワークスペースを構築する方法は複数あります; 一般的な方法を提示しましょう。バイナリ1つとライブラリ2つを持つワークスペースを作ります。 +ワークスペースを構築する方法は複数ありますが、一般的な方法を提示しましょう。バイナリ1つとライブラリ2つを含むワークスペースを作ります。 バイナリは、コマンドラインツールとして使用される主要な機能を提供し、2つのライブラリに依存しています。 一方のライブラリは、`add_one`関数を提供し、2番目のライブラリは、`add_two`関数を提供します。 これら3つのクレートが同じワークスペースの一部になります。ワークスペース用の新しいディレクトリを作ることから始めましょう: @@ -265,10 +265,10 @@ Hello, world! 10 plus one is 11! ワークスペースには、各クレートのディレクトリそれぞれに*Cargo.lock*が存在するのではなく、 ワークスペースの最上位階層にただ一つの*Cargo.lock*が存在するだけのことに注目してください。 -これにより、全クレートが全依存ファイルの同じバージョンを使用していることが確認されます。 +これにより、全クレートが全依存の同じバージョンを使用していることが確認されます。 `rand`クレートを*adder/Cargo.toml*と*add-one/Cargo.toml*ファイルに追加すると、 Cargoは両者をあるバージョンの`rand`に解決し、それを一つの*Cargo.lock*に記録します。 -ワークスペースの全クレートに同じ依存ファイルを使用させるということは、 +ワークスペースの全クレートに同じ依存を使用させるということは、 ワークスペースのクレートが相互に互換性を常に維持するということになります。 *add-one/Cargo.toml*ファイルの`[dependencies]`セクションに`rand`クレートを追加して、 `add-one`クレートで`rand`クレートを使用できます: @@ -335,8 +335,8 @@ issue #27703) -これを修正するには、`adder`クレートの*Cargo.toml*ファイルを編集し、同様に`rand`がそのクレートの依存ファイルであることを示してください。 -`adder`クレートをビルドすると、`rand`を*Cargo.lock*の`adder`の依存ファイル一覧に追加しますが、 +これを修正するには、`adder`クレートの*Cargo.toml*ファイルを編集し、同様にそのクレートが`rand`に依存していることを示してください。 +`adder`クレートをビルドすると、`rand`を*Cargo.lock*の`adder`の依存一覧に追加しますが、 `rand`のファイルが追加でダウンロードされることはありません。Cargoが、ワークスペースの`rand`を使用するどのクレートも、 同じバージョンを使っていることを確かめてくれるのです。ワークスペース全体で`rand`の同じバージョンを使用することにより、 複数のコピーが存在しないのでスペースを節約し、ワークスペースのクレートが相互に互換性を維持することを確かめます。 @@ -407,7 +407,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out 出力の最初の区域が、`add-one`クレートの`it_works`テストが通ったことを示しています。 次の区域には、`adder`クレートにはテストが見つなかったことが示され、 -さらに最後の区域は、`add-one`クレートにドキュメンテーションテストは見つからなかったと表示されています。 +さらに最後の区域には、`add-one`クレートにドキュメンテーションテストは見つからなかったと表示されています。 このような構造をしたワークスペースで`cargo test`を走らせると、ワークスペースの全クレートのテストを実行します。 @@ -439,7 +439,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out この出力は、`cargo test`が`add-one`クレートのテストのみを実行し、`adder`クレートのテストは実行しなかったことを示しています。 - + From 332e145add42e98b5d06dd174dcc01f695469770 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 2 Feb 2018 21:31:30 +0900 Subject: [PATCH 107/428] Fix some mistakes in the chapters 16-0 and 16-1 --- second-edition/src/ch16-00-concurrency.md | 4 ++-- second-edition/src/ch16-01-threads.md | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/second-edition/src/ch16-00-concurrency.md b/second-edition/src/ch16-00-concurrency.md index c0a287dfa..7ea602dce 100644 --- a/second-edition/src/ch16-00-concurrency.md +++ b/second-edition/src/ch16-00-concurrency.md @@ -10,7 +10,7 @@ -非同期処理を安全かつ効率的に扱うことは、Rustの別の主な目標です。非同期処理プログラミングは、プログラムの異なる部分が個別に実行することであり、 +非同期処理を安全かつ効率的に扱うことは、Rustの別の主な目標です。非同期プログラミングは、プログラムの異なる部分が個別に実行することであり、 並行プログラミングはプログラムの異なる部分が同時に実行することですが、多くのコンピュータが複数のプロセッサの利点を生かすようになるにつれ、 重要度を増しています。歴史的に、これらの文脈で行うプログラミングは困難で、エラーが起きやすいものでした: Rustはこれを変えると期待されています。 @@ -68,7 +68,7 @@ Rustのこの方向性を*恐れるな!非同期処理*とニックネーム 曖昧な方法しかありません。可能な解決策の一部のみをサポートすることは、高級言語にとっては合理的な施策です。 なぜなら、高級言語は一部の制御を失う代わりに抽象化することから恩恵を受けるからです。ところが、 低級言語は、どんな場面でも最高のパフォーマンスで解決策を提供すると想定され、ハードウェアに関してほとんど抽象化はしません。 -そのため、Rustは、自分の状況と必要性に適した方法で問題をモデル化するためのいろんな道具を備えています。 +そのため、Rustは、自分の状況と必要性に適した方法が何であれ、問題をモデル化するためのいろんな道具を備えています。 diff --git a/second-edition/src/ch16-01-threads.md b/second-edition/src/ch16-01-threads.md index 88f27493b..1373a5ca8 100644 --- a/second-edition/src/ch16-01-threads.md +++ b/second-edition/src/ch16-01-threads.md @@ -27,7 +27,7 @@ -* スレッドがデータやリソースに不安定な順番でアクセスする競合状態 +* スレッドがデータやリソースに矛盾した順番でアクセスする競合状態 * 2つのスレッドがお互いにもう一方が持っているリソースを使用し終わるのを待ち、両者が継続するのを防ぐデッドロック * 特定の状況でのみ起き、再現や信頼して修正が困難なバグ @@ -53,7 +53,7 @@ Rustは、スレッド使用のマイナスの効果を軽減しようとして -多くのプログラミング言語がスレッドのそれだけの特別な実装を提供しています。プログラミング言語が提供するスレッドは、 +多くのプログラミング言語がスレッドの独自の特別な実装を提供しています。プログラミング言語が提供するスレッドは、 *グリーン*スレッドとして知られ、このグリーンスレッドを使用する言語は、それを異なる数のOSスレッドの文脈で実行します。 このため、グリーンスレッドのモデルは*M:N*モデルと呼ばれます: `M`個のグリーンスレッドに対して、 `N`個のOSスレッドで、`M`と`N`は必ずしも同じ数字ではありません。 @@ -110,7 +110,7 @@ M:Nスレッドの実装をしたクレートもあります。 -新規スレッドを立ち上げるには、`thread::spawn`関数を呼び出し、 +新規スレッドを生成するには、`thread::spawn`関数を呼び出し、 新規スレッドで走らせたいコードを含むクロージャ(クロージャについては第13章で語りました)を渡します。 リスト16-1の例は、メインスレッドと新規スレッドからテキストを出力します: @@ -174,7 +174,7 @@ hi number 5 from the spawned thread! `thread::sleep`を呼び出すと、少々の間、スレッドの実行を止め、違うスレッドを走らせることができます。 スレッドは順番待ちをしますが、保証はありません: OSがスレッドのスケジュールを行う方法によります。 -この実行では、立ち上げられたスレッドのprint文がコードでは先に出現しているのに、メインスレッドがまず出力しています。 +この実行では、立ち上げられたスレッドのprint文がコードでは先に出現しているのに、メインスレッドがまず出力しています。また、 立ち上げたスレッドには`i`が9になるまで出力するよう指示しているのに、メインスレッドが終了する前の5までしか到達していません。 @@ -206,7 +206,7 @@ hi number 5 from the spawned thread! `thread::spawn`の戻り値を変数に保存することで、立ち上げたスレッドが実行されなかったり、 完全に実行されなかったりする問題を修正することができます。`thread:spawn`の戻り値の型は`JoinHandle`です。 -`JoinHandle`は、`join`メソッドを呼び出したときにスレッドの実行を待つ所有された値です。 +`JoinHandle`は、`join`メソッドを呼び出したときにスレッドの終了を待つ所有された値です。 リスト16-2は、リスト16-1で生成したスレッドの`JoinHandle`を使用し、`join`を呼び出して、 立ち上げたスレッドが、`main`が終了する前に完了することを確認する方法を示しています: @@ -428,7 +428,7 @@ variables), use the `move` keyword Rustは`v`のキャプチャ方法を*推論*し、`println!`は`v`への参照のみを必要とするので、クロージャは、 -`v`を借用しようとします。ですが、問題があります: コンパイラには、立ち上げたスレッドがどのくらい走るのかわからないので、 +`v`を借用しようとします。ですが、問題があります: コンパイラには、立ち上げたスレッドがどのくらいの期間走るのかわからないので、 `v`への参照が常に有効であるか把握できないのです。 @@ -493,7 +493,7 @@ variables), use the `move` keyword クロージャの前に`move`キーワードを付することで、コンパイラに値を借用すべきと推論させるのではなく、 -クロージャに使用している値の所有権を強制的に奪わせます。リスト16-4に示したリスト16-3に対する変更は、 +クロージャに使用している値の所有権を強制的に奪わせます。リスト16-5に示したリスト16-3に対する変更は、 コンパイルでき、意図通りに動きます: @@ -566,7 +566,9 @@ error[E0382]: use of moved value: `v` `move`キーワードにより、デフォルトで借用するというRustの保守性が上書きされるのです; 所有権ルールを侵害させてはくれないのです。 + + -スレッドとスレッドAPIの基礎知識が入ったので、スレッドでできることを見ていきましょう。 +スレッドとスレッドAPIの基礎知識が入ったので、スレッドで*できる*ことを見ていきましょう。 From 0b2de2a7a657ccaf554fc050023902490b5d05cb Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 2 Feb 2018 22:51:01 +0900 Subject: [PATCH 108/428] Fix some mistakes in the chapters 16-2 and 16-3 --- second-edition/src/ch16-02-message-passing.md | 20 +++++++++------- second-edition/src/ch16-03-shared-state.md | 24 +++++++++++-------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/second-edition/src/ch16-02-message-passing.md b/second-edition/src/ch16-02-message-passing.md index 151a1e76c..ee0a2728e 100644 --- a/second-edition/src/ch16-02-message-passing.md +++ b/second-edition/src/ch16-02-message-passing.md @@ -30,6 +30,8 @@ Rustの標準ライブラリが実装を提供しているプログラミング 水の流れのように考えることができます。小川とか川ですね。アヒルのおもちゃやボートみたいなものを小川に置いたら、 川の終端まで下流に流れていきます。 + + @@ -61,7 +63,7 @@ Rustの標準ライブラリが実装を提供しているプログラミング まず、リスト16-6において、チャンネルを生成するものの、何もしません。 -チャンネルを通してどんな型の値を送りたいのかコンパイラがわからないため、 +チャンネル越しにどんな型の値を送りたいのかコンパイラがわからないため、 これはまだコンパイルできないことに注意してください: @@ -95,8 +97,8 @@ fn main() { 簡潔に言えば、Rustの標準ライブラリがチャンネルを実装している方法は、1つのチャンネルが値を生成する複数の*送信*側と、 その値を消費するたった1つの*受信*側を持つことができるということを意味します。 複数の川と小川が互いに合わさって1つの大きな川になるところを想像してください: -どの川を通っても、送られたものは最終的に1つの川に行き着きます。今は、1つの生成機から始めますが、 -この例が動作するようになったら、複数の生成機を追加します。 +どの川を通っても、送られたものは最終的に1つの川に行き着きます。今は、1つの生成器から始めますが、 +この例が動作するようになったら、複数の生成器を追加します。 @@ -173,7 +175,7 @@ fn main() { リスト16-8において、メインスレッドのチャンネルの受信側から値を得ます。 -アヒルのおもちゃを川の終端で水から取り上げたり、チャットメッセージを取得するみたいですね: +アヒルのおもちゃを川の終端で水から回収したり、チャットメッセージを取得するみたいですね: @@ -355,7 +357,7 @@ fn main() { let (tx, rx) = mpsc::channel(); thread::spawn(move || { - // スレッドからやあ + // スレッドからやあ(hi from the thread) let vals = vec![ String::from("hi"), String::from("from"), @@ -413,12 +415,12 @@ Got: thread -メインスレッドの`for`ループには停止したり、遅れたりするコードは何もないので、 +メインスレッドの`for`ループには停止したり、遅れせたりするコードは何もないので、 メインスレッドが立ち上げたスレッドから値を受け取るのを待機していることがわかります。 -### 転送機をクローンして複数の生成機を作成する +### 転送機をクローンして複数の生成器を作成する @@ -459,7 +461,7 @@ thread::spawn(move || { }); thread::spawn(move || { - // 君のためにもっとメッセージを + // 君のためにもっとメッセージを(more messages for you) let vals = vec![ String::from("more"), String::from("messages"), @@ -484,7 +486,7 @@ for received in rx { -リスト16-11: 複数の生成機から複数のメッセージを送信する +リスト16-11: 複数の生成器から複数のメッセージを送信する diff --git a/second-edition/src/ch16-03-shared-state.md b/second-edition/src/ch16-03-shared-state.md index f36b008d9..f8ce7ecdf 100644 --- a/second-edition/src/ch16-03-shared-state.md +++ b/second-edition/src/ch16-03-shared-state.md @@ -31,13 +31,15 @@ Go言語ドキュメンテーションのスローガンのこの部分を再び メモリ共有非同期処理は、複数の所有権に似ています: 複数のスレッドが同時に同じメモリ位置にアクセスできるのです。 第15章でスマートポインタが複数の所有権を可能にするのを目の当たりにしたように、 異なる所有者を管理する必要があるので、複数の所有権は複雑度を増させます。 -Rustの型システムと所有権ルールにより、この管理を正当に行う非常に大きな助けになります。 -例を挙げれば、メモリ共有を行うより一般的な非同期処理の基礎の一つであるミューテックスを見ましょう。 +Rustの型システムと所有権ルールにより、この管理を正当に行う大きな助けになります。 +例を挙げれば、メモリ共有を行うより一般的な非同期処理の基本型の一つであるミューテックスを見ましょう。 ### ミューテックスは、一度に1つのスレッドからデータにアクセスすることを許可する + + @@ -161,7 +163,7 @@ fn main() { `lock`の呼び出しが`MutexGuard`というスマートポインタを*返却*します。このスマートポインタが、 内部のデータを指す`Deref`を実装しています; このスマートポインタはさらに`MutexGuard`がスコープを外れた時に、 自動的にロックを解除する`Drop`実装もしていて、これがリスト16-12の内部スコープの終わりで発生します。 -結果として、ロックの解除を忘れ、ロックの解除が自動的に行われるので、 +結果として、ロックの解除が自動的に行われるので、ロックの解除を忘れ、 ミューテックスが他のスレッドで使用されるのを阻害するリスクを負いません。 @@ -183,7 +185,7 @@ fn main() { さて、`Mutex`を使って複数のスレッド間で値を共有してみましょう。10個のスレッドを立ち上げ、 各々カウンタの値を1ずつインクリメントさせるので、カウンタは0から10まで上がります。 以下の数例は、コンパイルエラーになることに注意し、そのエラーを使用して`Mutex`の使用法と、 -コンパイラがそれを正しく扱う手助けをしてくれる方法について学びます。リスト16-13が最初の例です: +コンパイラがそれを正しく活用する手助けをしてくれる方法について学びます。リスト16-13が最初の例です: @@ -352,8 +354,9 @@ error: aborting due to 2 previous errors なるほど!最初のメッセージは、`handle`に紐付けられたスレッドのクロージャに`counter`がムーブされていることを示唆しています。 そのムーブにより、それに対して`lock`を呼び出し、結果を2番目のスレッドの`num2`に保持しようとした時に、 -`counter`をキャプチャすることを妨げています。これは、以前では確認しづらかったことです。 -なぜなら、スレッドはループの中にあり、ループの違う繰り返しにある違うスレッドをコンパイラは指し示せないからです。 +`counter`をキャプチャすることを妨げています。ゆえに、コンパイラは、`counter`の所有権を複数のスレッドに移すことはできないと教えてくれています。 +これは、以前では確認しづらかったことです。なぜなら、スレッドはループの中にあり、 +ループの違う繰り返しにある違うスレッドをコンパイラは指し示せないからです。 第15章で議論した複数所有権メソッドによりコンパイルエラーを修正しましょう。 @@ -453,8 +456,9 @@ counter:std::rc::Rc>]` おお、このエラーメッセージはとても長ったらしいですね!こちらが、注目すべき重要な部分です: 最初のインラインエラーは`` `std::rc::Rc>` cannot be sent -between threads safely``と述べています。蒸留されたエラーメッセージは、`` the trait bound -`Send` is not satisfied``と述べています。`Send`については、次の節で語ります: +between threads safely``と述べています。この理由は、次に注目すべき重要な部分、エラーメッセージにあります。 +蒸留されたエラーメッセージは、`` the trait bound `Send` is not satisfied``と述べています。 +`Send`については、次の節で語ります: スレッドとともに使用している型が非同期処理の場面で使われることを意図したものであることを保証するトレイトの1つです。 @@ -576,8 +580,8 @@ Result: 10 `counter`は不変なのに、その内部にある値への可変参照を得ることができたことに気付いたでしょうか; つまり、`Mutex`は、`Cell`系のように内部可変性(interior mutability)を提供するわけです。 -第15章で`RefCell`を使用して`Rc`の内部の内容を可変化できるようにしたのと同様に、 -`Mutex`を使用して`Arc`の内部の内容を可変化しているのです。 +第15章で`RefCell`を使用して`Rc`の内容を可変化できるようにしたのと同様に、 +`Mutex`を使用して`Arc`の内容を可変化しているのです。 From d08b86fac12fdf090fda3ce81f77f769c3ef57cd Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 3 Feb 2018 20:03:55 +0900 Subject: [PATCH 109/428] First draft of the chapter 15-0 --- second-edition/src/SUMMARY.md | 22 ++- second-edition/src/ch15-00-smart-pointers.md | 153 ++++++++++++------- 2 files changed, 112 insertions(+), 63 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index e639064af..5b576b00c 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -154,13 +154,21 @@ - [`cargo install`でCrates.ioからバイナリをインストールする](ch14-04-installing-binaries.md) - [独自のコマンドでCargoで拡張する](ch14-05-extending-cargo.md) -- [Smart Pointers](ch15-00-smart-pointers.md) - - [`Box` Points to Data on the Heap and Has a Known Size](ch15-01-box.md) - - [The `Deref` Trait Allows Access to the Data Through a Reference](ch15-02-deref.md) - - [The `Drop` Trait Runs Code on Cleanup](ch15-03-drop.md) - - [`Rc`, the Reference Counted Smart Pointer](ch15-04-rc.md) - - [`RefCell` and the Interior Mutability Pattern](ch15-05-interior-mutability.md) - - [Creating Reference Cycles and Leaking Memory is Safe](ch15-06-reference-cycles.md) + + + + + + + + +- [スマートポインタ](ch15-00-smart-pointers.md) + - [`Box`はヒープのデータを指し、既知のサイズである](ch15-01-box.md) + - [`Deref`トレイトにより、参照を通してデータにアクセスできる](ch15-02-deref.md) + - [`Drop`トレイトにより、片付けの時にコードを実行する](ch15-03-drop.md) + - [`Rc`は、参照カウントのスマートポインタ](ch15-04-rc.md) + - [`RefCell`と内部可変性パターン](ch15-05-interior-mutability.md) + - [循環参照し、メモリをリークするのは安全である](ch15-06-reference-cycles.md) diff --git a/second-edition/src/ch15-00-smart-pointers.md b/second-edition/src/ch15-00-smart-pointers.md index 82c8fa1cd..b369fca0e 100644 --- a/second-edition/src/ch15-00-smart-pointers.md +++ b/second-edition/src/ch15-00-smart-pointers.md @@ -1,56 +1,97 @@ -# Smart Pointers - -A *pointer* is a general concept for a variable that contains an address in -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. - -*Smart pointers*, on the other hand, are data structures that act like a -pointer but also have additional metadata and capabilities. The concept of -smart pointers isn’t unique to Rust: smart pointers originated in C++ and exist -in other languages as well. In Rust, the different smart pointers defined in -the standard library provide extra functionality beyond that provided by -references. One example that we’ll explore in this chapter is the *reference -counting* smart pointer type. This pointer enables you to have multiple owners -of data by keeping track of the number of owners and, when no owners remain, -taking care of cleaning up the data. - -In Rust, where we have the concept of ownership and borrowing, an additional -difference between references and smart pointers is that references are -pointers that only borrow data; in contrast, in many cases, smart pointers -*own* the data they point to. - -We’ve already encountered a few smart pointers in this book, such as `String` -and `Vec` in Chapter 8, although we didn’t call them smart pointers at the -time. Both these types count as smart pointers because they own some memory and -allow you to manipulate it. They also have metadata (such as their capacity) -and extra capabilities or guarantees (such as with `String` ensuring its data -will always be valid UTF-8). - -Smart pointers are usually implemented using structs. The characteristic that -distinguishes a smart pointer from an ordinary struct is that smart pointers -implement the `Deref` and `Drop` traits. The `Deref` trait allows an instance -of the smart pointer struct to behave like a reference so we can write code -that works with either references or smart pointers. The `Drop` trait allows us -to customize the code that is run when an instance of the smart pointer goes -out of scope. In this chapter, we’ll discuss both traits and demonstrate why -they’re important to smart pointers. - -Given that the smart pointer pattern is a general design pattern used -frequently in Rust, this chapter won’t cover every existing smart pointer. Many -libraries have their own smart pointers, and you can even write your own. We’ll -cover the most common smart pointers in the standard library: - -* `Box` for allocating values on the heap -* `Rc`, a reference counted type that enables multiple ownership -* `Ref` and `RefMut`, accessed through `RefCell`, a type that enforces - the borrowing rules at runtime instead of compile time - -In addition, we’ll cover the *interior mutability* pattern where an immutable -type exposes an API for mutating an interior value. We’ll also discuss -*reference cycles*: how they can leak memory and how to prevent them. - -Let’s dive in! + + +# スマートポインタ + + + + + + + + + +*ポインタ*は、メモリのアドレスを含む変数の一般的な概念です。このアドレスは、何らかの他のデータを参照、または「指します」。 +Rustにおいて、最もありふれた種類のポインタは、参照であり、第4章で習いましたね。参照は、 +`&`記号で示唆され、指している値を借用します。データを参照すること以外に特別な能力は何もありません。 +また、オーバーヘッドもなく、最も頻繁に使われる種類のポインタです。 + + + + + + + + + + + +一方、*スマートポインタ*は、ポインタのように振る舞うものの、追加のメタデータと能力があるデータ構造です。 +スマートポインタという概念は、Rustに固有のものではありません: スマートポインタは、C++に端を発し、 +他の言語にも存在しています。Rustでは、標準ライブラリに定義された色々なスマートポインタが、 +参照以上のおまけの機能を提供します。この章で探究する一つの例が、*参照カウント*方式のスマートポインタ型です。 +このポインタにより、所有者の数を追いかけることでデータに複数の所有者を持たせることができ、 +所有者がいなくなったら、データの片付けをしてくれます。 + + + + + + +所有権と借用の概念があるRustで、参照とスマートポインタの別の差異は、参照はデータを借用するだけのポインタであることです; +対照的に多くの場合、スマートポインタは指しているデータを*所有*します。 + + + + + + + + +当時は、スマートポインタとは呼ばなかったものの、第8章の`String`や`Vec`のように、 +この本の中でいくつかのスマートポインタに遭遇してきました。これらの型はどちらも、 +あるメモリを所有し、それを弄ることができるので、スマートポインタに数えられます。また、 +メタデータ(キャパシティなど)や追加の能力、あるいは保証(`String`ならデータが常に有効なUTF-8であると保証することなど)もあります。 + + + + + + + + + + +スマートポインタは普通、構造体を使用して実装されています。スマートポインタを通常の構造体と区別する特徴は、 +スマートポインタは、`Deref`と`Drop`トレイトを実装していることです。`Deref`トレイトにより、スマートポインタ構造体のインスタンスは、 +参照のように振る舞うことができるので、参照あるいはスマートポインタのどちらとも動作するコードを書くことができるのです。 +`Drop`トレイトにより、スマートポインタのインスタンスがスコープを外れた時に走るコードをカスタマイズすることができます。 +この章では、どちらのトレイトについても議論し、これらのトレイトがスマートポインタにとって重要な理由をデモします。 + + + + + + +スマートポインタパターンがRustにおいてよく使われる一般的なデザインパターンだとして、この章では、全ての既存のスマートポインタを講義します。 +多くのライブラリに独自のスマートポインタがあり、自分だけのスマートポインタを書くことさえできます。 +標準ライブラリの最もありふれたスマートポインタを講義します: + + + + + + +* ヒープに値を確保する`Box` +* 複数の所有権を可能にする参照カウント型の`Rc` +* `RefCell`を通してアクセスされ、コンパイル時ではなく実行時に借用ルールを強制する型の`Ref`と`RefMut` + + + + + +さらに、不変な型が、内部の値を可変化するAPIを晒す*内部可変性*パターンについても講義します。 +また、*循環参照*についても議論します: 循環参照により、メモリがリークする方法とそれを回避する方法です。 + + + +さあ、飛び込みましょう! From be2b6a3c1dc168c16edc972bc96fc714a91fc311 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 4 Feb 2018 14:40:40 +0900 Subject: [PATCH 110/428] First draft of the chapter 15-1 --- second-edition/src/ch15-01-box.md | 536 ++++++++++++++++++++---------- 1 file changed, 352 insertions(+), 184 deletions(-) diff --git a/second-edition/src/ch15-01-box.md b/second-edition/src/ch15-01-box.md index d188ff280..ee8731fde 100644 --- a/second-edition/src/ch15-01-box.md +++ b/second-edition/src/ch15-01-box.md @@ -1,39 +1,69 @@ -## `Box` Points to Data on the Heap and Has a Known Size + -The most straightforward smart pointer is a *box*, whose type is written -`Box`. Boxes allow you to store data on the heap rather than the stack. What -remains on the stack is the pointer to the heap data. Refer to Chapter 4 to -review the difference between the stack and the heap. +## `Box`はヒープのデータを指し、既知のサイズである -Boxes don’t have performance overhead, other than storing their data on the -heap instead of on the stack. But they don’t have many extra capabilities -either. You’ll use them most often in these situations: + + + + -* When you have a type whose size can’t be known at compile time, and you want - to use a value of that type in a context that needs to know an exact size -* When you have a large amount of data and you want to transfer ownership but - ensure the data won’t be copied when you do so -* When you want to own a value and only care that it’s a type that implements a - particular trait rather than knowing the concrete type +最も素直なスマートポインタは*ボックス*であり、その型は`Box`と記述されます。 +ボックスにより、スタックではなくヒープにデータを格納することができます。スタックに残るのは、 +ヒープデータへのポインタです。スタックとヒープの違いを再確認するには、第4章を参照されたし。 -We’ll demonstrate the first situation in this section. But before we do so, -we’ll elaborate on the other two situations a bit more: in the second case, -transferring ownership of a large amount of data can take a long time because -the data is copied around on the stack. To improve performance in this -situation, we can store the large amount of data on the heap in a box. Then, -only the small amount of pointer data is copied around on the stack, and the -data stays in one place on the heap. The third case is known as a *trait -object*, and Chapter 17 devotes an entire section just to that topic. So what -you learn here you’ll apply again in Chapter 17! + + + -### Using a `Box` to Store Data on the Heap +ボックスは、データをスタックの代わりにヒープに格納する以外は、パフォーマンスのオーバーヘッドはありません。 +しかし、多くのおまけの能力もありません。以下のような場面で最もよく使用するでしょう: -Before we discuss this use case for `Box`, we’ll cover the syntax and how to -interact with values stored within a `Box`. + + + + + + -Listing 15-1 shows how to use a box to store an `i32` value on the heap: +* コンパイル時にはサイズを知ることができない型があり、正確なサイズを知る必要がある文脈でその型の値を使用する時 +* 多くのデータがあり、所有権を転送したいが、そうする時にデータがコピーされないことを確認する時 +* 値を所有する必要があり、実際の型を知るのではなく特定のトレイトを実装する型であることのみ気にかけている時 -Filename: src/main.rs + + + + + + + + + + + + +この節では、最初の場面を模擬します。しかしそうする前に、それ以外の2つの場面をもうちょっと練ります: +2番目の場合、多くのデータの所有権を転送するには、データがスタック上でコピーされるので、長い時間がかかり得ます。 +この場面でパフォーマンスを向上させるには、多くのデータをヒープ上にボックスとして格納することができます。 +そして、少量のポインタのデータのみをスタック上でコピーし、データはヒープ上の1箇所に留まるのです。 +3番目のケースは、*トレイトオブジェクト*として知られ、第17章は、その話題だけに1節全体を捧げています。 +従って、ここで学ぶことは、第17章でまた適用するでしょう! + + + +### `Box`を使ってヒープにデータを格納する + + + + +`Box`のこのユースケースを議論する前に、記法と`Box`内に格納された値と相互作用する方法について講義しましょう。 + + + +リスト15-1は、ボックスを使用してヒープに`i32`の値を格納する方法を示しています: + + + +ファイル名: src/main.rs ```rust fn main() { @@ -42,69 +72,118 @@ fn main() { } ``` -Listing 15-1: Storing an `i32` value on the heap using a -box - -We define the variable `b` to have the value of a `Box` that points to the -value `5`, which is allocated on the heap. This program will print `b = 5`; in -this case, we can access the data in the box in a similar way as we would if -this data was on the stack. Just like any owned value, when a box goes out of -scope like `b` does at the end of `main`, it will be deallocated. The -deallocation happens for the box (stored on the stack) and the data it points -to (stored on the heap). - -Putting a single value on the heap isn’t very useful, so you won’t use boxes by -themselves in this way very often. Having values like a single `i32` on the -stack, where they’re stored by default, is more appropriate in the majority of -situations. Let’s look at a case where boxes allow us to define types that we -wouldn’t be allowed to if we didn’t have boxes. - -### Boxes Enable Recursive Types - -At compile time, Rust needs to know how much space a type takes up. One type -whose size can’t be known at compile time is a *recursive type*, where a value -can have as part of itself another value of the same type. Because this nesting -of values could theoretically continue infinitely, Rust doesn’t know how much -space a value of a recursive type needs. However, boxes have a known size, so -by inserting a box in a recursive type definition, we can have recursive types. - -Let’s explore the *cons list*, which is a data type common in functional -programming languages, as an example of a recursive type. The cons list type -we’ll define is straightforward except for the recursion; therefore, the -concepts in the example we’ll work with will be useful any time you get into -more complex situations involving recursive types. - -#### More Information About the Cons List - -A *cons list* is a data structure that comes from the Lisp programming language -and its dialects. In Lisp, the `cons` function (short for “construct function”) -constructs a new pair from its two arguments, which usually are a single value -and another pair. These pairs containing pairs form a list. - -The cons function concept has made its way into more general functional -programming jargon: “to cons x onto y” informally means to construct a new -container instance by putting the element x at the start of this new container, -followed by the container y. - -Each item in a cons list contains two elements: the value of the current item -and the next item. The last item in the list contains only a value called `Nil` -without a next item. A cons list is produced by recursively calling the `cons` -function. The canonical name to denote the base case of the recursion is `Nil`. -Note that this is not the same as the “null” or “nil” concept in Chapter 6, -which is an invalid or absent value. - -Although functional programming languages use cons lists frequently, it isn’t a -commonly used data structure in Rust. Most of the time when you have a list of -items in Rust, `Vec` is a better choice to use. Other, more complex -recursive data types *are* useful in various situations, but by starting with -the cons list, we can explore how boxes let us define a recursive data type -without much distraction. - -Listing 15-2 contains an enum definition for a cons list. Note that this code -won’t compile yet because the `List` type doesn’t have a known size, which -we’ll demonstrate: - -Filename: src/main.rs + + + +リスト15-1: ボックスを使用して`i32`の値をヒープに格納する + + + + + + + + + +変数`b`を定義して値`5`を指す`Box`の値を持っていて、この値はヒープに確保されています。このプログラムは、 +`b = 5`と出力するでしょう; この場合、このデータがスタックにあるのと同じような方法でボックスのデータにアクセスできます。 +あらゆる所有された値同様、`b`が`main`の終わりでするようにボックスがスコープを抜けたら、 +メモリから解放されます。メモリの解放は(スタックに格納されている)ボックスと(ヒープに格納されている)指しているデータに対して起きます。 + + + + + + + +ヒープに単独の値を置くことはあまり有用ではないので、このように単独でボックスを使用することはあまりありません。 +単独の`i32`のような値を規定で格納される場所であるスタックに置くことが、大多数の場合にはより適切です。 +ボックスがなかったら定義することの叶わない型をボックスが定義させてくれる場合を見ましょう。 + + + +### ボックスは、再帰的な型を可能にする + + + + + + + + +コンパイル時に、コンパイラは、ある型が取る領域を知る必要があります。コンパイル時にサイズがわからない型の1つは、 +*再帰的な型*であり、これは、型の一部として同じ型の他の値を持つものです。この値のネストは、 +理論的には無限に続く可能性があるので、コンパイラは再帰的な型の値が必要とする領域を知ることができないのです。 +しかしながら、ボックスは既知のサイズなので、再帰的な型の定義にボックスを挟むことで再帰的な型を存在させることができるのです。 + + + + + + + +*コンスリスト*は関数型プログラミング言語では一般的なデータ型ですが、これを再帰的な型の例として探求しましょう。 +我々が定義するコンスリストは、再帰を除いて素直です; 故に、これから取り掛かる例の概念は、 +再帰的な型が関わるもっと複雑な場面に遭遇したら必ず役に立つでしょう。 + + + +#### コンスリストについてもっと詳しく + + + + + + +コンスリストは、Lispプログラミング言語とその方言に由来するデータ構造です。Lispでは、 +`cons`関数("construct function"の省略形です)が2つの引数から新しいペアを構成し、 +この引数は通常、単独の値と別のペアからなります。これらのペアを含むペアがリストをなすのです。 + + + + + + +cons関数の概念は、より一般的な関数型プログラミングのスラングにもなっています: "to cons x onto y"は、 +俗に要素xをこの新しいコンテナの初めに置き、コンテナyを従わせて新しいコンテナのインスタンスを生成することを意味します。 + + + + + + + + +コンスリストの各要素は、2つの要素を含みます: 現在の要素の値と次の要素です。リストの最後の要素は、 +次の要素なしに`Nil`と呼ばれる値だけを含みます。コンスリストは、繰り返し`cons`関数を呼び出すことで生成されます。 +繰り返しの規範事例を意味する標準的な名前は、`Nil`です。これは第6章の"null"や"nil"の概念とは異なることに注意してください。 +"null"や"nil"は、無効だったり存在しない値です。 + + + + + + + + +関数型プログラミング言語は、頻繁にコンスリストを使用するものの、Rustではあまり使用されないデータ構造です。 +Rustで要素のリストがある場合はほとんどの場合、`Vec`を使用するのがよりよい選択になります。 +他のより複雑な再帰的なデータ型は、様々な場面で役に立ち*ます*が、コンスリストから始めることで、 +大して気を散らすことなく再帰的なデータ型をボックスが定義させてくれる方法を探求することができます。 + + + + + + + +リスト15-2には、コンスリストのenum定義が含まれています。このコードは、 +`List`型が既知のサイズではないため、まだコンパイルできないことに注意してください。 +既知のサイズがないことをこれから模擬します。 + + + +ファイル名: src/main.rs ```rust,ignore enum List { @@ -113,18 +192,27 @@ enum List { } ``` -Listing 15-2: The first attempt at defining an enum to -represent a cons list data structure of `i32` values + + + +リスト15-2: `i32`値のコンスリストデータ構造を表すenumを定義する最初の試行 -> Note: We’re implementing a cons list that only holds `i32` values for the -> purposes of this example. We could have implemented it using generics, as we -> discussed in Chapter 10, to define a cons list type that could store values of -> any type. + + + + -Using the `List` type to store the list `1, 2, 3` would look like the code in -Listing 15-3: +> 注釈: この例のためだけに`i32`値を保持するだけのコンスリストを実装します。第10章で議論したように、 +> ジェネリクスを使用してどんな型の値も格納できるコンスリストを定義して実装することもできました。 -Filename: src/main.rs + + + +この`List`型を使用してリスト`1, 2, 3`を格納すると、リスト15-3のコードのような見た目になるでしょう: + + + +ファイル名: src/main.rs ```rust,ignore use List::{Cons, Nil}; @@ -134,19 +222,28 @@ fn main() { } ``` -Listing 15-3: Using the `List` enum to store the list `1, -2, 3` + + + +リスト15-3: `List`enumを使用してリスト`1, 2, 3`を格納する -The first `Cons` value holds `1` and another `List` value. This `List` value is -another `Cons` value that holds `2` and another `List` value. This `List` value -is one more `Cons` value that holds `3` and a `List` value, which is finally -`Nil`, the non-recursive variant that signals the end of the list. + + + + -If we try to compile the code in Listing 15-3, we get the error shown in -Listing 15-4: +最初の`Cons`値は、`1`と別の`List`値を保持しています。この`List`値は、 +`2`とまた別の`List`値を保持する別の`Cons`値です。この`List`値は、 +`3`と、ついにリストの終端を通知する非再帰的なバリアントの`Nil`になる`List`値を保持するまたまた別の`Cons`値です。 + + + + +リスト15-3のコードをコンパイルしようとすると、リスト15-4に示したエラーが出ます: ```text error[E0072]: recursive type `List` has infinite size +(エラー: 再帰的な型`List`は無限のサイズです) --> src/main.rs:1:1 | 1 | enum List { @@ -156,22 +253,33 @@ error[E0072]: recursive type `List` has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable + (助言: 間接参照(例: `Box`、`Rc`、あるいは`&`)をどこかに挿入して、`List`を表現可能にしてください) ``` -Listing 15-4: The error we get when attempting to define -a recursive enum + + + +リスト15-4: 再帰的なenumを定義しようとすると得られるエラー + + + + + + + -The error shows this type “has infinite size.” The reason is that we’ve defined -`List` with a variant that is recursive: it holds another value of itself -directly. As a result, Rust can’t figure out how much space it needs to store a -`List` value. Let’s break down why we get this error a bit: first, let’s look -at how Rust decides how much space it needs to store a value of a non-recursive -type. +エラーは、この型は「無限のサイズである」と表示しています。理由は、再帰的な列挙子を含む`List`を定義したからです: +自身の別の値を直接保持しているのです。結果として、コンパイラは、`List`値を格納するのに必要な領域が計算できないのです。 +このエラーが得られた理由を少し噛み砕きましょう: まず、非再帰的な型の値を格納するのに必要な領域をどうコンパイラが決定しているかを見ましょう。 -#### Computing the Size of a Non-Recursive Type + -Recall the `Message` enum we defined in Listing 6-2 when we discussed enum -definitions in Chapter 6: +#### 非再帰的な型のサイズを計算する + + + + +第6章でenum定義を議論した時にリスト6-2で定義した`Message`enumを思い出してください: ```rust enum Message { @@ -182,55 +290,91 @@ enum Message { } ``` -To determine how much space to allocate for a `Message` value, Rust goes -through each of the variants to see which variant needs the most space. Rust -sees that `Message::Quit` doesn’t need any space, `Message::Move` needs enough -space to store two `i32` values, and so forth. Because only one variant will be -used, the most space a `Message` value will need is the space it would take to -store the largest of its variants. + + + + + + + +`Message`値一つにメモリを確保するために必要な領域を決定するために、コンパイラは、 +各列挙子を見てどの列挙子が最も領域を必要とするかを確認します。コンパイラは、 +`Message::Quit`は全く領域を必要とせず、`Message::Move`は`i32`値を2つ格納するのに十分な領域が必要などと確かめます。 +ただ1つの列挙子しか使用されないので、`Message`値一つが必要とする最大の領域は、 +最大の列挙子を格納するのに必要になる領域です。 + + + + + + + + + + +これをコンパイラがリスト15-2の`List`enumのような再帰的な型が必要とする領域を決定しようとする時に起こることと比較してください。 +コンパイラは、`Cons`列挙子を見ることから始め、この列挙子には、型`i32`値が一つと型`List`の値が一つ保持されます。 +故に、`Cons`は1つの`i32`と`List`のサイズに等しい領域を必要とします。`List`が必要とするメモリ量を計算するのに、 +コンパイラは`Cons`列挙子から列挙子を観察します。`Cons`列挙子は型`i32`を1つと型`List`の値1つを保持し、 +この過程は無限に続きます。図15-1のようにね: + + + +無限のコンスリスト + + + -Contrast this to what happens when Rust tries to determine how much space a -recursive type like the `List` enum in Listing 15-2 needs. The compiler starts -by looking at the `Cons` variant, which holds a value of type `i32` and a value -of type `List`. Therefore, `Cons` needs an amount of space equal to the size of -an `i32` plus the size of a `List`. To figure out how much memory the `List` -type needs, the compiler looks at the variants, starting with the `Cons` -variant. The `Cons` variant holds a value of type `i32` and a value of type -`List`, and this process continues infinitely, as shown in Figure 15-1: +図15-1: 無限の`Cons`列挙子からなる無限の`List` -An infinite Cons list + -Figure 15-1: An infinite `List` consisting of infinite -`Cons` variants +#### `Box`で既知のサイズの再帰的な型を得る -#### Using `Box` to Get a Recursive Type with a Known Size + + + -Rust can’t figure out how much space to allocate for recursively defined types, -so the compiler gives the error in Listing 15-4. But the error does include -this helpful suggestion: +コンパイラは、再帰的に定義された型に必要なメモリ量を計算できないので、リスト15-4ではエラーを返します。 +しかし、エラーには確かにこの役に立つ提言が含まれています: ```text = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable ``` -In this suggestion, “indirection” means that instead of storing a value -directly, we’ll change the data structure to store the value indirectly by -storing a pointer to the value instead. + + + -Because a `Box` is a pointer, Rust always knows how much space a `Box` -needs: a pointer’s size doesn’t change based on the amount of data it’s -pointing to. This means we can put a `Box` inside the `Cons` variant instead -of another `List` value directly. The `Box` will point to the next `List` -value that will be on the heap rather than inside the `Cons` variant. -Conceptually, we still have a list, created with lists “holding” other lists, -but this implementation is now more like the items being next to one another -rather than inside one another. +この提言において、「間接参照」は、値を直接格納する代わりに、データ構造を変更して値へのポインタを代わりに格納することで、 +値を間接的に格納することを意味します。 -We can change the definition of the `List` enum in Listing 15-2 and the usage -of the `List` in Listing 15-3 to the code in Listing 15-5, which will compile: + + + + + + + + -Filename: src/main.rs +`Box`はポインタなので、コンパイラには`Box`が必要とする領域が必ずわかります: ポインタのサイズは、 +指しているデータの量によって変わることはありません。つまり、別の`List`値を直接置く代わりに、 +`Cons`列挙子の中に`Box`を配置することができます。`Box`は、 +`Cons`列挙子の中ではなく、ヒープに置かれる次の`List`値を指します。概念的には、 +それでも他のリストを「保持する」リストとともに作られたリストがありますが、 +この実装は今では、要素はお互いの中にあるというよりも、隣り合って存在するような感じになります。 + + + + +リスト15-2の`List`enumの定義とリスト15-3の`List`の使用をリスト15-5のコードに変更することができ、 +これはコンパイルが通ります: + + + +ファイル名: src/main.rs ```rust enum List { @@ -248,33 +392,57 @@ fn main() { } ``` -Listing 15-5: Definition of `List` that uses `Box` in -order to have a known size - -The `Cons` variant will need the size of an `i32` plus the space to store the -box’s pointer data. The `Nil` variant stores no values, so it needs less space -than the `Cons` variant. We now know that any `List` value will take up the -size of an `i32` plus the size of a box’s pointer data. By using a box, we’ve -broken the infinite, recursive chain, so the compiler can figure out the size -it needs to store a `List` value. Figure 15-2 shows what the `Cons` variant -looks like now: - -A finite Cons list - -Figure 15-2: A `List` that is not infinitely sized -because `Cons` holds a `Box` - -Boxes only provide the indirection and heap allocation; they don’t have any -other special capabilities, like those we’ll see with the other smart pointer -types. They also don’t have any performance overhead that these special -capabilities incur, so they can be useful in cases like the cons list where the -indirection is the only feature we need. We’ll look at more use cases for boxes -in Chapter 17, too. - -The `Box` type is a smart pointer because it implements the `Deref` trait, -which allows `Box` values to be treated like references. When a `Box` -value goes out of scope, the heap data that the box is pointing to is cleaned -up as well because of the `Drop` trait implementation. Let’s explore these two -traits in more detail. These two traits will be even more important to the -functionality provided by the other smart pointer types we’ll discuss in the -rest of this chapter. + + + +リスト15-5: 既知のサイズを得るために`Box`を使用する`List`の定義 + + + + + + + + + +`Cons`列挙子は、1つの`i32`のサイズプラスボックスのポインタデータを格納する領域を必要とするでしょう。 +`Nil`列挙子は、値を格納しないので、`Cons`列挙子よりも必要な領域は小さいです。これで、 +どんな`List`値も`i32`1つのサイズプラスボックスのポインタデータのサイズを必要とすることがわかりました。 +ボックスを使うことで、無限の再帰的な繰り返しを破壊したので、コンパイラは、`List`値を格納するのに必要なサイズを計算できます。 +図15-2は、`Cons`列挙子の今の見た目を示しています: + + + +有限のコンスリスト + + + + +図15-2: `Cons`が`Box`を保持しているので、無限にサイズがあるわけではない`List` + + + + + + + + +ボックスは、間接参照とヒープメモリ確保を提供するだけです; 他のスマートポインタ型で目撃するような、 +他の特別な能力は何もありません。これらの特別な能力が招くパフォーマンスのオーバーヘッドもないので、 +間接参照だけが必要になる唯一の機能であるコンスリストのような場合に有用になり得ます。 +より多くのボックスのユースケースは第17章でもお見かけするでしょう。 + + + + + + + + + +`Box`型は、`Deref`トレイトを実装しているので、スマートポインタであり、 +このトレイトにより`Box`の値を参照のように扱うことができます。`Box`値がスコープを抜けると、 +`Drop`トレイト実装によりボックスが参照しているヒープデータも片付けられます。 +これら2つのトレイトをより詳しく探求しましょう。これら2つのトレイトは、 +この章の残りで議論する他のスマートポインタ型で提供される機能にとってさらに重要でしょう。 + From df211b800a718bda6cdefd09314052f151ef6d47 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 4 Feb 2018 18:25:12 +0900 Subject: [PATCH 111/428] First drafts of the chapters 15-2 and 15-3 --- second-edition/src/ch15-02-deref.md | 569 ++++++++++++++++++---------- second-edition/src/ch15-03-drop.md | 308 ++++++++++----- 2 files changed, 579 insertions(+), 298 deletions(-) diff --git a/second-edition/src/ch15-02-deref.md b/second-edition/src/ch15-02-deref.md index ecb8fa38f..8e05c3d33 100644 --- a/second-edition/src/ch15-02-deref.md +++ b/second-edition/src/ch15-02-deref.md @@ -1,26 +1,44 @@ -## Treating Smart Pointers Like Regular References with the `Deref` Trait + -Implementing the `Deref` trait allows us to customize the behavior of the -*dereference operator*, `*` (as opposed to the multiplication or glob -operator). By implementing `Deref` in such a way that a smart pointer can be -treated like a regular reference, we can write code that operates on references -and use that code with smart pointers too. +## `Deref`トレイトでスマートポインタを普通の参照のように扱う -Let’s first look at how `*` works with regular references, and then try to -define our own type like `Box` and see why `*` doesn’t work like a reference -on our newly defined type. We’ll explore how implementing the `Deref` trait -makes it possible for smart pointers to work in a similar way as references. -Then we’ll look at Rust’s *deref coercion* feature and how it lets us work with -either references or smart pointers. + + + + + -### Following the Pointer to the Value with `*` +`Deref`トレイトを実装することで*参照外し演算子*の`*`(掛け算やグロブ演算子とは対照的に)の振る舞いをカスタマイズすることができます。 +スマートポインタを普通の参照のように扱えるように`Deref`を実装することで、 +参照に対して処理を行うコードを書き、そのコードをスマートポインタとともに使用することもできます。 -A regular reference is a type of pointer, and one way to think of a pointer is -as an arrow to a value stored somewhere else. In Listing 15-6, we create a -reference to an `i32` value and then use the dereference operator to follow the -reference to the data: + + + + + + -Filename: src/main.rs +まずは、`*`が普通の参照に対して動作するところを見て、それから`Box`のような独自の型を定義し、 +`*`が新しく定義した型に対して参照のように動作しない理由を確認しましょう。 +`Deref`トレイトを実装することでスマートポインタが参照と似た方法で動作するようにできる方法を探求します。 +そして、Rustの*参照外し型強制*機能と、それにより参照やスマートポインタに取り掛かる方法を見ます。 + + + +### `*`で値までポインタを追いかける + + + + + + +普通の参照は1種のポインタであり、ポインタの捉え方の一つが、どこか他の場所に格納された値への矢印としてです。 +リスト15-6で、`i32`値への参照を生成し、それから参照外し演算子を使用して参照をデータまで追いかけています: + + + +ファイル名: src/main.rs ```rust fn main() { @@ -32,22 +50,31 @@ fn main() { } ``` -Listing 15-6: Using the dereference operator to follow a -reference to an `i32` value + + + +リスト15-6: 参照外し演算子を使用して参照を`i32`値まで追いかける + + + + + + + -The variable `x` holds an `i32` value, `5`. We set `y` equal to a reference to -`x`. We can assert that `x` is equal to `5`. However, if we want to make an -assertion about the value in `y`, we have to use `*y` to follow the reference -to the value it’s pointing to (hence *dereference*). Once we dereference `y`, -we have access to the integer value `y` is pointing to that we can compare with -`5`. +変数`x`は`i32`値の`5`を保持しています。`y`を`x`への参照にセットします。`x`は`5`に等しいとアサートできます。 +しかしながら、`y`の値に関するアサートを行いたい場合、`*y`を使用して参照を指している値まで追いかけなければなりません(そのため*参照外し*です)。 +一旦、`y`を参照外ししたら、`y`が指している`5`と比較できる整数値にアクセスできます。 -If we tried to write `assert_eq!(5, y);` instead, we would get this compilation -error: + + + +代わりに`assert_eq!(5, y);`と書こうとしたら、こんなコンパイルエラーが出るでしょう: ```text error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<&{integer}>` is not satisfied +(エラー: トレイト境界`{integer}: std::cmp::PartialEq<&{integer}>`は満たされていません) --> src/main.rs:6:5 | 6 | assert_eq!(5, y); @@ -55,19 +82,30 @@ not satisfied | = help: the trait `std::cmp::PartialEq<&{integer}>` is not implemented for `{integer}` + (助言: トレイト`std::cmp::PartialEq<&{integer}>`は`{integer}`に対して実装されていません) ``` -Comparing a number and a reference to a number isn’t allowed because they’re -different types. We must use `*` to follow the reference to the value it’s -pointing to. + + + + +参照と数値は異なる型なので、比較することは許可されていません。`*`を使用して、 +参照を指している値まで追いかけなければならないのです。 -### Using `Box` Like a Reference + -We can rewrite the code in Listing 15-6 to use a `Box` instead of a -reference, and the dereference operator will work the same way as shown in -Listing 15-7: +### `Box`を参照のように使う -Filename: src/main.rs + + + + +リスト15-6のコードを参照の代わりに`Box`を使うように書き直すことができ、 +参照外し演算子は、リスト15-7に示したように同じように動くでしょう: + + + +ファイル名: src/main.rs ```rust fn main() { @@ -79,28 +117,45 @@ fn main() { } ``` -Listing 15-7: Using the dereference operator on a -`Box` + + + +リスト15-7: `Box`に対して参照外し演算子を使用する + + + + + + + -The only difference between Listing 15-7 and Listing 15-6 is that here we set -`y` to be an instance of a box pointing to the value in `x` rather than a -reference pointing to the value of `x`. In the last assertion, we can use the -dereference operator to follow the box’s pointer in the same way that we did -when `y` was a reference. Next, we’ll explore what is special about `Box` -that enables us to use the dereference operator by defining our own box type. +リスト15-7とリスト15-6の唯一の違いは、ここでは、`x`の値を指す参照ではなく、 +`x`の値を指すボックスのインスタンスに`y`をセットしていることです。 +最後のアサートで参照外し演算子を使用して`y`が参照だった時のようにボックスのポインタを追いかけることができます。 +次に、独自のボックス型を定義することで参照外し演算子を使用させてくれる`Box`について何が特別なのかを探求します。 -### Defining Our Own Smart Pointer + -Let’s build a smart pointer similar to the `Box` type provided by the -standard library to experience how smart pointers behave differently to -references by default. Then we’ll look at how to add the ability to use the -dereference operator. +### 独自のスマートポインタを定義する -The `Box` type is ultimately defined as a tuple struct with one element, so -Listing 15-8 defines a `MyBox` type in the same way. We’ll also define a -`new` function to match the `new` function defined on `Box`: + + + + -Filename: src/main.rs +標準ライブラリが提供している`Box`型に似たスマートポインタを構築して、スマートポインタは規定で、 +どう異なって参照に対して振る舞うのか経験しましょう。それから、参照外し演算子を使う能力を追加する方法に目を向けましょう。 + + + + + +`Box`型は究極的に1要素のタプル構造体として定義されているので、リスト15-8は、同じように`MyBox`型を定義しています。 +また、`Box`に定義された`new`関数と合致する`new`関数も定義しています: + + + +ファイル名: src/main.rs ```rust struct MyBox(T); @@ -112,19 +167,30 @@ impl MyBox { } ``` -Listing 15-8: Defining a `MyBox` type + + +リスト15-8: `MyBox`型を定義する -We define a struct named `MyBox` and declare a generic parameter `T`, because -we want our type to hold values of any type. The `MyBox` type is a tuple struct -with one element of type `T`. The `MyBox::new` function takes one parameter of -type `T` and returns a `MyBox` instance that holds the value passed in. + + + + -Let’s try adding the `main` function in Listing 15-7 to Listing 15-8 and -changing it to use the `MyBox` type we’ve defined instead of `Box`. The -code in Listing 15-9 won’t compile because Rust doesn’t know how to dereference -`MyBox`: +`MyBox`という構造体を定義し、ジェネリック引数の`T`を宣言しています。自分の型にどんな型の値も保持させたいからです。 +`MyBox`型は、型`T`を1要素持つタプル構造体です。`MyBox::new`関数は型`T`の引数を1つ取り、 +渡した値を保持する`MyBox`インスタンスを返します。 -Filename: src/main.rs + + + + + +試しにリスト15-7の`main`関数をリスト15-8に追加し、`Box`の代わりに定義した`MyBox`型を使うよう変更してみてください。 +コンパイラは`MyBox`を参照外しする方法がわからないので、リスト15-9のコードはコンパイルできません: + + + +ファイル名: src/main.rs ```rust,ignore fn main() { @@ -136,32 +202,49 @@ fn main() { } ``` -Listing 15-9: Attempting to use `MyBox` in the same -way we used references and `Box` + + + +リスト15-9: 参照と`Box`を使ったのと同じように`MyBox`を使おうとする + + -Here’s the resulting compilation error: +こちらが結果として出るコンパイルエラーです: ```text error[E0614]: type `MyBox<{integer}>` cannot be dereferenced +(エラー: 型`MyBox<{integer}>`は参照外しできません) --> src/main.rs:14:19 | 14 | assert_eq!(5, *y); | ^^ ``` -Our `MyBox` type can’t be dereferenced because we haven’t implemented that -ability on our type. To enable dereferencing with the `*` operator, we -implement the `Deref` trait. + + + -### Treating a Type Like a Reference by Implementing the `Deref` Trait +`MyBox`に参照外しの能力を実装していないので、参照外しできません。`*`演算子で参照外しできるようにするには、 +`Deref`トレイトを実装します。 -As discussed in Chapter 10, to implement a trait, we need to provide -implementations for the trait’s required methods. The `Deref` trait, provided -by the standard library, requires us to implement one method named `deref` that -borrows `self` and returns a reference to the inner data. Listing 15-10 -contains an implementation of `Deref` to add to the definition of `MyBox`: + -Filename: src/main.rs +### `Deref`トレイトを実装して型を参照のように扱う + + + + + + + +第10章で議論したように、トレイトを実装するには、トレイトの必須メソッドに実装を提供する必要があります。 +`Deref`トレイトは標準ライブラリで提供されていますが、`self`を借用し、 +内部のデータへの参照を返す`deref`という1つのメソッドを実装する必要があります。リスト15-10には、 +`MyBox`の定義に追記する`Deref`の実装が含まれています: + + + +ファイル名: src/main.rs ```rust use std::ops::Deref; @@ -176,70 +259,116 @@ impl Deref for MyBox { } ``` -Listing 15-10: Implementing `Deref` on `MyBox` + + +リスト15-10: `MyBox`に`Deref`を実装する -The `type Target = T;` syntax defines an associated type for the `Deref` trait -to use. Associated types are a slightly different way of declaring a generic -parameter, but you don’t need to worry about them for now; we’ll cover them in -more detail in Chapter 19. + + + + -We fill in the body of the `deref` method with `&self.0` so `deref` returns a -reference to the value we want to access with the `*` operator. The `main` -function in Listing 15-9 that calls `*` on the `MyBox` value now compiles -and the assertions pass! +`type Target = T;`という記法は、`Deref`トレイトが使用する関連型を定義しています。関連型は、 +ジェネリック引数を宣言する少しだけ異なる方法ですが、今は気にする必要はありません; 第19章でより詳しく講義します。 -Without the `Deref` trait, the compiler can only dereference `&` references. -The `deref` method gives the compiler the ability to take a value of any type -that implements `Deref` and call the `deref` method to get a `&` reference that -it knows how to dereference. + + + + -When we entered `*y` in Listing 15-9, behind the scenes Rust actually ran this -code: +`deref`メソッドの本体を`&self.0`で埋めているので、`deref`は`*`演算子でアクセスしたい値への参照を返します。 +リスト15-9の`MyBox`に`*`を呼び出す`main`関数はこれでコンパイルでき、アサートも通ります! + + + + + + +`Deref`がなければ、コンパイラは`&`参照しか参照外しできなくなります。`deref`メソッドによりコンパイラは、 +`Deref`を実装するあらゆる型の値を取り、`deref`メソッドを呼び出して参照外しの仕方を知っている`&`参照を得る能力を獲得するのです。 + + + + +リスト15-9に`*y`を入力した時、水面下でコンパイラは、実際にはこのようなコードを走らせていました: ```rust,ignore *(y.deref()) ``` -Rust substitutes the `*` operator with a call to the `deref` method and then a -plain dereference so as programmers we don’t have to think about whether or not -we need to call the `deref` method. This Rust feature lets us write code that -functions identically whether we have a regular reference or a type that -implements `Deref`. - -The reason the `deref` method returns a reference to a value and that the plain -dereference outside the parentheses in `*(y.deref())` is still necessary is due -to the ownership system. If the `deref` method returned the value directly -instead of a reference to the value, the value would be moved out of `self`. We -don’t want to take ownership of the inner value inside `MyBox` in this case -and in most cases where we use the dereference operator. - -Note that the `*` is replaced with a call to the `deref` method and then a call -to `*` just once, each time we type a `*` in our code. Because the substitution -of `*` does not recurse infinitely, we end up with data of type `i32`, which -matches the `5` in `assert_eq!` in Listing 15-9. - -### Implicit Deref Coercions with Functions and Methods - -*Deref coercion* is a convenience that Rust performs on arguments to functions -and methods. Deref coercion converts a reference to a type that implements -`Deref` into a reference to a type that `Deref` can convert the original type -into. Deref coercion happens automatically when we pass a reference to a -particular type’s value as an argument to a function or method that doesn’t -match the parameter type in the function or method definition. A sequence of -calls to the `deref` method converts the type we provided into the type the -parameter needs. - -Deref coercion was added to Rust so that programmers writing function and -method calls don’t need to add as many explicit references and dereferences -with `&` and `*`. The deref coercion feature also lets us write more code that -can work for either references or smart pointers. - -To see deref coercion in action, let’s use the `MyBox` type we defined in -Listing 15-8 as well as the implementation of `Deref` that we added in Listing -15-10. Listing 15-11 shows the definition of a function that has a string slice -parameter: - -Filename: src/main.rs + + + + + + + + +コンパイラは、`*`演算子を`deref`メソッド、それから何の変哲もない参照外しの呼び出しに置き換えるので、 +プログラマとして`deref`メソッドを呼び出す必要があるかどうかを考える必要はないわけです。このRustの機能により、 +普通の参照か`Deref`を実装した型があるかどうかと等しく機能するコードを書くことができます。 + + + + + + + + +`deref`メソッドが値への参照を返し、`*(y.deref())`のかっこの外の何の変哲もない参照外しがそれでも必要な理由は、 +所有権システムのためです。`deref`メソッドが値への参照ではなく、値を直接返したら、値は`self`から外にムーブされてしまいます。 +今回の場合や、参照外し演算子を使用する多くの場合には`MyBox`の中の値の所有権を奪いたくはありません。 + + + + + + + + +`*`は`deref`メソッドの呼び出し1回とコードで`*`打つたび、ただ1回の`*`の呼び出しに置き換えられることに注意してください。 +`*`の置き換えは、無限に繰り返されないので、型`i32`に行き着き、リスト15-9で`assert_eq!`の`5`と合致します。 + + + +### 関数やメソッドで暗黙的な参照外し型強制 + + + + + + + + + + +*参照外し型強制*は、コンパイラが関数やメソッドの実引数に行う便利なものです。参照外し型強制は、 +`Deref`を実装する型への参照を`Deref`が元の型を変換できる型への参照に変換します。参照外し型強制は、 +特定の型の値への参照を関数やメソッド定義の引数型と一致しない引数として関数やメソッドに渡すときに自動的に発生します。 +一連の`deref`メソッドの呼び出しが、提供した型を引数が必要とする型に変換します。 + + + + + + + + +参照外し型強制は、関数やメソッド呼び出しを書くプログラマが`&`や`*`で多くの明示的な参照や参照外しとして追加する必要がないように、 +Rustに追加されました。また、参照外し型強制のおかげで参照あるいはスマートポインタで動くコードをもっと書くことができます。 + + + + + + +参照外し型強制が実際に動いていることを確認するため、リスト15-8で定義した`MyBox`と、 +リスト15-10で追加した`Deref`の実装を使用しましょう。リスト15-11は、 +文字列スライス引数のある関数の定義を示しています: + + + +ファイル名: src/main.rs ```rust fn hello(name: &str) { @@ -247,14 +376,21 @@ fn hello(name: &str) { } ``` -Listing 15-11: A `hello` function that has the parameter -`name` of type `&str` + + + +リスト15-11: 型`&str`の引数`name`のある`hello`関数 + + + + -We can call the `hello` function with a string slice as an argument, such as -`hello("Rust");` for example. Deref coercion makes it possible to call `hello` -with a reference to a value of type `MyBox`, as shown in Listing 15-12: +`hello`関数は、文字列スライスを引数として呼び出すことができます。例えば、`hello("Rust")`などです。 +参照外し型強制により、`hello`を型`MyBox`の値への参照とともに呼び出すことができます。リスト15-12のようにね: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust # use std::ops::Deref; @@ -285,22 +421,35 @@ fn main() { } ``` -Listing 15-12: Calling `hello` with a reference to a -`MyBox` value, which works because of deref coercion + + + +リスト15-12: `hello`を`MyBox`値とともに呼び出し、参照外し型強制のおかげで動く + + + + + + + + + +ここで、`hello`関数を引数`&m`とともに呼び出しています。この引数は、`MyBox`値への参照です。 +リスト15-10で`MyBox`に`Deref`トレイトを実装したので、コンパイラは`deref`を呼び出すことで、 +`&MyBox`を`&String`に変換できるのです。標準ライブラリは、`String`に文字列スライスを返す`Deref`の実装を提供していて、 +この実装は、`Deref`のAPIドキュメンテーションに載っています。コンパイラはさらに`deref`を呼び出して、 +`&String`を`&str`に変換し、これは`hello`関数の定義と合致します。 -Here we’re calling the `hello` function with the argument `&m`, which is a -reference to a `MyBox` value. Because we implemented the `Deref` trait -on `MyBox` in Listing 15-10, Rust can turn `&MyBox` into `&String` -by calling `deref`. The standard library provides an implementation of `Deref` -on `String` that returns a string slice, which is in the API documentation for -`Deref`. Rust calls `deref` again to turn the `&String` into `&str`, which -matches the `hello` function’s definition. + + + -If Rust didn’t implement deref coercion, we would have to write the code in -Listing 15-13 instead of the code in Listing 15-12 to call `hello` with a value -of type `&MyBox`: +Rustに参照外し型強制が実装されていなかったら、リスト15-12のコードの代わりにリスト15-13のコードを書き、 +型`&MyBox`の値で`hello`を呼び出さなければならなかったでしょう: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust # use std::ops::Deref; @@ -331,46 +480,80 @@ fn main() { } ``` -Listing 15-13: The code we would have to write if Rust -didn’t have deref coercion - -The `(*m)` dereferences the `MyBox` into a `String`. Then the `&` and -`[..]` take a string slice of the `String` that is equal to the whole string to -match the signature of `hello`. The code without deref coercions is harder to -read, write, and understand with all of these symbols involved. Deref coercion -allows Rust to handle these conversions for us automatically. - -When the `Deref` trait is defined for the types involved, Rust will analyze the -types and use `Deref::deref` as many times as necessary to get a reference to -match the parameter’s type. The number of times that `Deref::deref` needs to be -inserted is resolved at compile time, so there is no runtime penalty for taking -advantage of deref coercion! - -### How Deref Coercion Interacts with Mutability - -Similar to how we use the `Deref` trait to override `*` on immutable -references, Rust provides a `DerefMut` trait for overriding `*` on mutable -references. - -Rust does deref coercion when it finds types and trait implementations in three -cases: - -* From `&T` to `&U` when `T: Deref` -* From `&mut T` to `&mut U` when `T: DerefMut` -* From `&mut T` to `&U` when `T: Deref` - -The first two cases are the same except for mutability. The first case states -that if you have a `&T`, and `T` implements `Deref` to some type `U`, you can -get a `&U` transparently. The second case states that the same deref coercion -happens for mutable references. - -The third case is trickier: Rust will also coerce a mutable reference to an -immutable one. But the reverse is *not* possible: immutable references will -never coerce to mutable references. Because of the borrowing rules, if you have -a mutable reference, that mutable reference must be the only reference to that -data (otherwise, the program wouldn’t compile). Converting one mutable -reference to one immutable reference will never break the borrowing rules. -Converting an immutable reference to a mutable reference would require that -there is only one immutable reference to that data, and the borrowing rules -don’t guarantee that. Therefore, Rust can’t make the assumption that converting -an immutable reference to a mutable reference is possible. + + + +リスト15-13: Rustに参照外し型強制がなかった場合に書かなければならないであろうコード + + + + + + + +`(*m)`が`MyBox`を`String`に参照外ししています。そして、`&`と`[..]`により、 +文字列全体と等しい`String`の文字列スライスを取り、`hello`のシグニチャと一致するわけです。 +参照外し型強制のないコードは、これらの記号が関係するので、読むのも書くのも理解するのもより難しくなります。 +参照外し型強制により、コンパイラはこれらの変換を自動的に扱えるのです。 + + + + + + + +`Deref`トレイトが関係する型に定義されていると、コンパイラは、型を分析し必要なだけ`Deref::deref`を使用して、 +参照を得、引数の型と一致させます。`Deref::deref`が挿入される必要のある回数は、コンパイル時に解決されるので、 +参照外し型強制を活用する実行時の代償は何もありません。 + + + +### 参照外し型強制が可変性と相互作用する方法 + + + + + +`Deref`トレイトを使用して不変参照に対して`*`をオーバーライドするように、Rustには、 +可変参照の`*`をオーバーライドする`DerefMut`トレイトが用意されています。 + + + + +以下の3つの場合に型やトレイト実装を見つけた時にコンパイラは、参照外し型強制を行います: + + + + + +* `T: Deref`の時、`&T`から`&U` +* `T: DerefMut`の時、`&mut T`から`&mut U` +* `T: Deref`の時、`&mut T`から`&U` + + + + + + +前者2つは、可変性を除いて一緒です。最初のケースは、`&T`があり、`T`が何らかの型`U`への`Deref`を実装しているなら、 +透過的に`&U`を得られると述べています。2番目のケースは、同じ参照外し型強制が可変参照についても起こることを述べています。 + + + + + + + + + + + + + + +3番目のケースはもっと巧妙です: Rustはさらに、可変参照を不変参照にも型強制するのです。ですが、逆はできま*せん*: +不変参照は、絶対に可変参照に型強制されないのです。借用ルールにより、可変参照があるなら、 +その可変参照がそのデータへの唯一の参照に違いありません(でなければ、プログラムはコンパイルできません)。 +1つの可変参照を1つの不変参照に変換することは、借用ルールを絶対に破壊しません。 +不変参照を可変参照にするには、そのデータへの不変参照がたった1つしかないことが必要ですが、 +借用ルールはそれを保証してくれません。故に、不変参照を可変参照に変換することが可能であるという前提を敷けません。 diff --git a/second-edition/src/ch15-03-drop.md b/second-edition/src/ch15-03-drop.md index da3e193fa..29ffa596e 100644 --- a/second-edition/src/ch15-03-drop.md +++ b/second-edition/src/ch15-03-drop.md @@ -1,33 +1,57 @@ -## The `Drop` Trait Runs Code on Cleanup - -The second trait important to the smart pointer pattern is `Drop`, which lets -us customize what happens when a value is about to go out of scope. We can -provide an implementation for the `Drop` trait on any type, and the code we -specify can be used to release resources like files or network connections. -We’re introducing `Drop` in the context of smart pointers because the -functionality of the `Drop` trait is almost always used when implementing a -smart pointer. For example, `Box` customizes `Drop` to deallocate the space -on the heap that the box points to. - -In some languages, the programmer must call code to free memory or resources -every time they finish using an instance of a smart pointer. If they forget, -the system might become overloaded and crash. In Rust, we can specify that a -particular bit of code should be run whenever a value goes out of scope, and -the compiler will insert this code automatically. As a result, we don’t need to -be careful about placing cleanup code everywhere in a program that an instance -of a particular type is finished with, but we still won’t leak resources! - -We specify the code to run when a value goes out of scope by implementing the -`Drop` trait. The `Drop` trait requires us to implement one method named `drop` -that takes a mutable reference to `self`. To see when Rust calls `drop`, let’s -implement `drop` with `println!` statements for now. - -Listing 15-14 shows a `CustomSmartPointer` struct whose only custom -functionality is that it will print `Dropping CustomSmartPointer!` when the -instance goes out of scope. This example demonstrates when Rust runs the `drop` -function: - -Filename: src/main.rs + + +## `Drop`トレイトは片付け時にコードを走らせる + + + + + + + + + + +スマートポインタパターンにとって重要な2番目のトレイトは、`Drop`であり、 +これのおかげで値がスコープを抜けそうになった時に起こることをカスタマイズできます。 +どんな型に対しても`Drop`トレイトの実装を提供することができ、指定したコードは、 +ファイルやネットワーク接続などのリソースを解放するのに活用できます。 +`Drop`をスマートポインタの文脈で導入しています。`Drop`トレイトの機能は、ほぼ常にスマートポインタを実装する時に使われるからです。 +例えば、`Box`は`Drop`をカスタマイズしてボックスが指しているヒープの領域を解放しています。 + + + + + + + + + +ある言語では、プログラマがスマートポインタのインスタンスを使い終わる度にメモリやリソースを解放するコードを呼ばなければなりません。 +忘れてしまったら、システムは詰め込みすぎになりクラッシュする可能性があります。Rustでは、 +値がスコープを抜ける度に特定のコードが走るよう指定でき、コンパイラはこのコードを自動的に挿入します。 +結果として、特定の型のインスタンスを使い終わったプログラムの箇所全部にクリーンアップコードを配置するのに配慮する必要はないのに、 +それでもリソースをリークすることはありません。 + + + + + + +`Drop`トレイトを実装することで値がスコープを抜けた時に走るコードを指定します。 +`Drop`トレイトは、`self`への可変参照を取る`drop`という1つのメソッドを実装する必要があります。 +いつRustが`drop`を呼ぶのか確認するために、今は`println!`文のある`drop`を実装しましょう。 + + + + + + +リスト15-14は、唯一の独自の機能が、インスタンスがスコープを抜ける時に`Dropping CustomSmartPointer!`と出力するだけの、 +`CustomSmartPointer`構造体です。この例は、コンパイラがいつ`drop`関数を走らせるかをデモしています: + + + +ファイル名: src/main.rs ```rust struct CustomSmartPointer { @@ -36,34 +60,48 @@ 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") }; - println!("CustomSmartPointers created."); + let c = CustomSmartPointer { data: String::from("my stuff") }; // 俺のもの + let d = CustomSmartPointer { data: String::from("other stuff") }; // 別のもの + println!("CustomSmartPointers created."); // CustomSmartPointerが生成された } ``` -Listing 15-14: A `CustomSmartPointer` struct that -implements the `Drop` trait where we would put our cleanup code + + -The `Drop` trait is included in the prelude, so we don’t need to import it. We -implement the `Drop` trait on `CustomSmartPointer` and provide an -implementation for the `drop` method that calls `println!`. The body of the -`drop` function is where you would place any logic that you wanted to run when -an instance of your type goes out of scope. We’re printing some text here to -demonstrate when Rust will call `drop`. +リスト15-14: クリーンアップコードを配置する`Drop`トレイトを実装する`CustomSmartPointer`構造体 -In `main`, we create two instances of `CustomSmartPointer` and then print -`CustomSmartPointers created.`. At the end of `main`, our instance of -`CustomSmartPointer` will go out of scope, and Rust will call the code we put -in the `drop` method, printing our final message. Note that we didn’t need to -call the `drop` method explicitly. + + + + + + -When we run this program, we’ll see the following output: +`Drop`トレイトは、初期化処理に含まれるので、インポートする必要はありません。 +`CustomSmartPointer`に`Drop`トレイトを実装し、`println!`を呼び出す`drop`メソッドの実装を提供しています。 +`drop`関数の本体は、自分の型のインスタンスがスコープを抜ける時に走らせたいあらゆるロジックを配置する場所です。 +ここで何らかのテキストを出力し、コンパイラがいつ`drop`を呼ぶのかデモしています。 + + + + + + + +`main`で、`CustomSmartPointer`のインスタンスを2つ作り、それから`CustomSmartPointers created.`と出力しています。 +`main`の最後で、`CustomSmartPointer`のインスタンスはスコープを抜け、コンパイラは最後のメッセージを出力しながら、 +`drop`メソッドに置いたコードを呼び出します。`drop`メソッドを明示的に呼び出す必要はなかったことに注意してください。 + + + +このプログラムを実行すると、以下のような出力が出ます: ```text CustomSmartPointers created. @@ -71,74 +109,117 @@ Dropping CustomSmartPointer with data `other stuff`! Dropping CustomSmartPointer with data `my stuff`! ``` -Rust automatically called `drop` for us when our instance went out of scope, -calling the code we specified. Variables are dropped in the reverse order of -the order in which they were created, so `d` was dropped before `c`. This -example just gives you a visual guide to how the `drop` method works, but -usually you would specify the cleanup code that your type needs to run rather -than a print message. + + + + + + + +インスタンスがスコープを抜けた時に指定したコードを呼び出しながらコンパイラは、`drop`を自動的に呼び出してくれました。 +変数は、生成されたのと逆の順序でドロップされるので、`d`は`c`より先にドロップされました。 +この例は、`drop`メソッドの動き方を見た目で案内するだけですが、通常は、メッセージ出力ではなく、 +自分の型が走らせる必要のあるクリーンアップコードを指定するでしょう。 + + -### Dropping a Value Early with `std::mem::drop` +### `std::mem::drop`で早期に値をドロップする -Unfortunately, it’s not straightforward to disable the automatic `drop` -functionality. Disabling `drop` isn’t usually necessary; the whole point of the -`Drop` trait is that it’s taken care of automatically. Occasionally, you might -want to clean up a value early. One example is when using smart pointers that -manage locks: you might want to force the `drop` method that releases the lock -to run so other code in the same scope can acquire the lock. Rust doesn’t let -us call the `Drop` trait’s `drop` method manually; instead we have to call the -`std::mem::drop` function provided by the standard library if we want to force -a value to be dropped before the end of its scope. + + + + + + + + + -Let’s see what happens when we try to call the `Drop` trait’s `drop` method -manually by modifying the `main` function in Listing 15-14, as shown in Listing -15-15: +残念ながら、自動的な`drop`機能を無効化することは、素直ではありません。通常、`drop`を無効化する必要はありません; +`Drop`トレイトの重要な目的は、自動的に考慮されることです。時として、値を早期に片付けたくなる可能性があります。 +1例は、ロックを管理するスマートポインタを使用する時です: 同じスコープの他のコードがロックを獲得できるように、 +ロックを解放する`drop`メソッドを強制的に走らせたくなる可能性があります。Rustは、 +`Drop`トレイトの`drop`メソッドを手動で呼ばせてくれません; スコープが終わる前に値を強制的にドロップさせたいなら、 +標準ライブラリが提供する`std::mem:drop`関数を呼ばなければなりません。 -Filename: src/main.rs + + + + +リスト15-14の`main`関数を変更して手動で`Drop`トレイトの`drop`メソッドを呼び出そうとしたらどうなるか確認しましょう。 +リスト15-15のようにね: + + + +ファイル名: 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."); } ``` -Listing 15-15: Attempting to call the `drop` method from -the `Drop` trait manually to clean up early + + + +リスト15-15: `Drop`トレイトから`drop`メソッドを手動で呼び出し、早期に片付けようとする + + -When we try to compile this code, we’ll get this error: +このコードをコンパイルしてみようとすると、こんなエラーが出ます: ```text error[E0040]: explicit use of destructor method +(エラー: デストラクタメソッドを明示的に使用しています) --> src/main.rs:14:7 | 14 | c.drop(); | ^^^^ explicit destructor calls not allowed ``` -This error message states that we’re not allowed to explicitly call `drop`. The -error message uses the term *destructor*, which is the general programming term -for a function that cleans up an instance. A *destructor* is analogous to a -*constructor* that creates an instance. The `drop` function in Rust is one -particular destructor. + + + + + -Rust doesn’t let us call `drop` explicitly because Rust would still -automatically call `drop` on the value at the end of `main`. This would be a -*double free* error because Rust would be trying to clean up the same value -twice. +明示的に`drop`を呼び出すことは許されていないことをこのエラーメッセージは述べています。 +エラーメッセージは*デストラクタ*という専門用語を使っていて、これは、 +インスタンスを片付ける関数の一般的なプログラミング専門用語です。*デストラクタ*は、 +インスタンスを生成する*コンストラクタ*に類似しています。Rustの`drop`関数は、 +一つの特定のデストラクタです。 -We can’t disable the automatic insertion of `drop` when a value goes out of -scope, and we can’t call the `drop` method explicitly. So, if we need to force -a value to be cleaned up early, we can use the `std::mem::drop` function. + + + + -The `std::mem::drop` function is different than the `drop` method in the `Drop` -trait. We call it by passing the value we want to force to be dropped early as -an argument. The function is in the prelude, so we can modify `main` in Listing -15-14 to call the `drop` function, as shown in Listing 15-16: +コンパイラはそれでも、`main`の終端で値に対して自動的に`drop`を呼び出すので、`drop`を明示的に呼ばせてくれません。 +コンパイラが2回同じ値を片付けようとするので、これは*二重解放*エラーになるでしょう。 -Filename: src/main.rs + + + + +値がスコープを抜けるときに`drop`が自動的に挿入されるのを無効化できず、`drop`メソッドを明示的に呼ぶこともできません。 +よって、値を早期に片付けさせる必要があるなら、`std::mem::drop`関数を使用できます。 + + + + + + +`std::mem::drop`関数は、`Drop`トレイトの`drop`メソッドとは異なります。 +早期に強制的にドロップさせたい値を引数で渡すことで呼びます。この関数は初期化処理に含まれているので、 +リスト15-14の`main`を変更して`drop`関数を呼び出せます。リスト15-16のようにね: + + + +ファイル名: src/main.rs ```rust # struct CustomSmartPointer { @@ -159,10 +240,14 @@ fn main() { } ``` -Listing 15-16: Calling `std::mem::drop` to explicitly -drop a value before it goes out of scope + + + +リスト15-16: 値がスコープを抜ける前に明示的にドロップするために`std::mem::drop`を呼び出す -Running this code will print the following: + + +このコードを実行すると、以下のように出力されます: ```text CustomSmartPointer created. @@ -170,21 +255,34 @@ Dropping CustomSmartPointer with data `some data`! CustomSmartPointer dropped before the end of main. ``` -The text ```Dropping CustomSmartPointer with data `some data`!``` is printed -between the `CustomSmartPointer created.` and `CustomSmartPointer dropped -before the end of main.` text, showing that the `drop` method code is called to -drop `c` at that point. + + + + + +```Dropping CustomSmartPointer with data `some data`!```というテキストが、 +`CustomSmartPointer created.`と`CustomSmartPointer dropped before the end of main`テキストの間に出力されるので、 +`drop`メソッドのコードがその時点で呼び出されて`c`をドロップしたことを示しています。 + + + + + + +`Drop`トレイト実装で指定されたコードをいろんな方法で使用し、片付けを便利で安全にすることができます: +例を挙げれば、これを使用して独自のメモリアロケータを作ることもできるでしょう。`Drop`トレイトとRustの所有権システムがあれば、 +コンパイラが自動的に行うので、片付けを覚えておく必要はなくなります。 + + + + + -We can use code specified in a `Drop` trait implementation in many ways to make -cleanup convenient and safe: for instance, we could use it to create our own -memory allocator! With the `Drop` trait and Rust’s ownership system, we don’t -have to remember to clean up because Rust does it automatically. +コンパイルエラーを引き起こすので、まだ使用中の値を間違って片付けてしまう心配もしなくて済みます。 +参照が常に有効であると確認してくれる所有権システムが、値が最早使用されなくなった時に`drop`が1回だけ呼ばれることを保証してくれるのです。 -We also don’t have to worry about accidentally cleaning up values still in use -because that would cause a compiler error: the ownership system that makes sure -references are always valid also ensures that `drop` gets called only once when -the value is no longer being used. + + + -Now that we’ve examined `Box` and some of the characteristics of smart -pointers, let’s look at a few other smart pointers defined in the standard -library. +これで`Box`とスマートポインタの特徴の一部を調査したので、標準ライブラリに定義されている他のスマートポインタをいくつか見ましょう。 From 73c243e0791d8b2034586557793111d629f495ed Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 4 Feb 2018 22:08:06 +0900 Subject: [PATCH 112/428] First draft of the chapter 15-4 --- second-edition/src/SUMMARY.md | 2 +- second-edition/src/ch15-04-rc.md | 359 ++++++++++++++++++++----------- 2 files changed, 238 insertions(+), 123 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index 5b576b00c..6f5d34328 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -166,7 +166,7 @@ - [`Box`はヒープのデータを指し、既知のサイズである](ch15-01-box.md) - [`Deref`トレイトにより、参照を通してデータにアクセスできる](ch15-02-deref.md) - [`Drop`トレイトにより、片付けの時にコードを実行する](ch15-03-drop.md) - - [`Rc`は、参照カウントのスマートポインタ](ch15-04-rc.md) + - [`Rc`は、参照カウント方式のスマートポインタ](ch15-04-rc.md) - [`RefCell`と内部可変性パターン](ch15-05-interior-mutability.md) - [循環参照し、メモリをリークするのは安全である](ch15-06-reference-cycles.md) diff --git a/second-edition/src/ch15-04-rc.md b/second-edition/src/ch15-04-rc.md index 63108932a..163725483 100644 --- a/second-edition/src/ch15-04-rc.md +++ b/second-edition/src/ch15-04-rc.md @@ -1,54 +1,96 @@ -## `Rc`, the Reference Counted Smart Pointer + -In the majority of cases, ownership is clear: you know exactly which variable -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. +## `Rc`は、参照カウント方式のスマートポインタ -To enable multiple ownership, Rust has a type called `Rc`. Its name is an -abbreviation for *reference counting*, which keeps track of the number of -references to a value to know whether or not a value is still in use. If there -are zero references to a value, the value can be cleaned up without any -references becoming invalid. + + + + + + -Imagine `Rc` as a TV in a family room. When one person enters to watch TV, -they turn it on. Others can come into the room and watch the TV. When the last -person leaves the room, they turn off the TV because it’s no longer being used. -If someone turns off the TV while others are still watching it, there would be -uproar from the remaining TV watchers! +大多数の場合、所有権は明らかです: 一体どの変数が与えられた値を所有しているかわかるのです。 +ところが、単独の値が複数の所有者を持つ可能性のある場合もあります。例えば、グラフデータ構造では、 +複数の辺が同じノードを指す可能性があり、概念的にそのノードはそれを指す全ての辺に所有されるわけです。 +指す辺がなくならない限り、ノードは片付けられるべきではありません。 -We use the `Rc` type when we want to allocate some data on the heap for -multiple parts of our program to read, and we can’t determine at compile time -which part will finish using the data last. If we knew which part would finish -last, we could just make that part the data’s owner and the normal ownership -rules enforced at compile time would take effect. + + + + + -Note that `Rc` is only for use in single-threaded scenarios. When we discuss -concurrency in Chapter 16, we’ll cover how to do reference counting in -multithreaded programs. +複数の所有権を可能にするため、Rustには`Rc`という型があります。この名前は、*reference counting*の省略形であり、 +値がまだ使用中かどうか知るために値への参照の数を追跡します。値への参照が0なら、どの参照も無効にすることなく、 +値は片付けられます。 -### Using `Rc` to Share Data + + + + + -Let’s return to our cons list example in Listing 15-5. Recall that we defined -it using `Box`. This time, we’ll create two lists that both share ownership -of a third list, which conceptually will look similar to Figure 15-3: +`Rc`を家族部屋のテレビと想像してください。1人がテレビを見に部屋に入ったら、テレビをつけます。 +他の人も部屋に入ってテレビを観ることができます。最後の人が部屋を離れる時、 +もう使用されてないので、テレビを消します。他の人がまだ観ているのに誰かがテレビを消したら、 +残りのテレビ視聴者が騒ぐでしょう! -Two lists that share ownership of a third list + + + + + -Figure 15-3: Two lists, `b` and `c`, sharing ownership of -a third list, `a` +ヒープにプログラムの複数箇所で読む何らかのデータを確保したい時に`Rc`型を使用し、 +コンパイル時には、どの部分が最後にデータを使用し終わるか決定できません。どの部分が最後に使用し終わるかわかれば、 +単にその部分をデータの所有者にして、コンパイル時に強制される普通の所有権ルールが効果を発揮するでしょう。 -We’ll create list `a` that contains 5 and then 10. Then we’ll make two more -lists: `b` that starts with 3 and `c` that starts with 4. Both `b` and `c` -lists will then continue on to the first `a` list containing 5 and 10. In other -words, both lists will share the first list containing 5 and 10. + + + -Trying to implement this scenario using our definition of `List` with `Box` -won’t work, as shown in Listing 15-17: +`Rc`は、シングルスレッドシナリオで使用するためだけのものであることに注意してください。 +第16章で非同期処理について議論する時に、マルチスレッドプログラムで参照カウントをする方法を講義します。 -Filename: src/main.rs + + +### `Rc`でデータを共有する + + + + + +リスト15-5のコンスリストの例に回帰しましょう。`Box`を使って定義したことを思い出してください。 +今回は、両方とも3番目のリストの所有権を共有する2つのリストを作成し、 +これは概念的には図15-3のような見た目になります: + + + +3番目のリストの所有権を共有する2つのリスト + + + + +図15-3: 3番目のリスト、`a`の所有権を共有する2つのリスト、`b`と`c` + + + + + + +5と10を含むリスト`a`を作ります。さらにもう2つリストを作ります: 3で始まる`b`と4で始まる`c`です。 +`b`と`c`のどちらもそれから5と10を含む最初の`a`リストに続きます。換言すれば、 +どちらのリストも5と10を含む最初のリストを共有しています。 + + + + +`List`の定義を使用して`Box`とともにこの筋書きを実装しようとしても、うまくいきません。 +リスト15-17のようにね: + + + +ファイル名: src/main.rs ```rust,ignore enum List { @@ -67,10 +109,14 @@ fn main() { } ``` -Listing 15-17: Demonstrating we’re not allowed to have -two lists using `Box` that try to share ownership of a third list + + + +リスト15-17: 3番目のリストの所有権を共有しようとする`Box`を使った2つのリストを存在させることはできないとデモする + + -When we compile this code, we get this error: +このコードをコンパイルすると、こんなエラーが出ます: ```text error[E0382]: use of moved value: `a` @@ -85,29 +131,48 @@ error[E0382]: use of moved value: `a` the `Copy` trait ``` -The `Cons` variants own the data they hold, so when we create the `b` list, `a` -is moved into `b` and `b` owns `a`. Then, when we try to use `a` again when -creating `c`, we’re not allowed to because `a` has been moved. - -We could change the definition of `Cons` to hold references instead, but then -we would have to specify lifetime parameters. By specifying lifetime -parameters, we would be specifying that every element in the list will live at -least as long as the entire list. The borrow checker wouldn’t let us compile -`let a = Cons(10, &Nil);` for example, because the temporary `Nil` value would -be dropped before `a` could take a reference to it. - -Instead, we’ll change our definition of `List` to use `Rc` in place of -`Box`, as shown in Listing 15-18. Each `Cons` variant will now hold a value -and an `Rc` pointing to a `List`. When we create `b`, instead of taking -ownership of `a`, we’ll clone the `Rc` that `a` is holding, which -increases the number of references from one to two and lets `a` and `b` share -ownership of the data in that `Rc`. We’ll also clone `a` when creating -`c`, which increases the number of references from two to three. Every time we -call `Rc::clone`, the reference count to the data within the `Rc` will -increase, and the data won’t be cleaned up unless there are zero references to -it: - -Filename: src/main.rs + + + + +`Cons`列挙子は、保持しているデータを所有するので、`b`リストを作成する時に、 +`a`が`b`にムーブされ、`b`が`a`を所有します。それから`c`を作る際に再度`a`を使用しようとすると、 +`a`はムーブ済みなので、できないわけです。 + + + + + + + + +`Cons`定義を代わりに参照を保持するように変更することもできますが、そうしたら、 +ライフタイム引数を指定しなければなりません。ライフタイム引数を指定することで、 +リストの各要素が最低でもリスト全体と同じ期間だけ生きることを指定することになります。 +例えば、借用精査機は`let a = Cons(10, &Nil);`をコンパイルさせてくれません。 +一時的な`Nil`値が、`a`が参照を得られるより前にドロップされてしまうからです。 + + + + + + + + + + + + +代わりに、`List`の定義をリスト15-18のように、`Box`の箇所に`Rc`を使うように変更します。 +これで各`Cons`列挙子は、値と`List`を指す`Rc`を保持するようになりました。`b`を作る際、 +`a`の所有権を奪うのではなく、`a`が保持している`Rc`をクローンします。 +これにより、参照の数が1から2に増え、`a`と`b`にその`Rc`にあるデータの所有権を共有させます。 +また、`c`を生成する際にも`a`をクローンするので、参照の数は2から3になります。`Rc::clone`を呼ぶ度に、 +`Rc`内のデータの参照カウントが増え、参照が0にならない限りデータは片付けられません。 + + + +ファイル名: src/main.rs ```rust enum List { @@ -125,40 +190,67 @@ fn main() { } ``` -Listing 15-18: A definition of `List` that uses -`Rc` - -We need to add a `use` statement to bring `Rc` into scope because it’s not -in the prelude. In `main`, we create the list holding 5 and 10 and store it in -a new `Rc` in `a`. Then when we create `b` and `c`, we call the -`Rc::clone` function and pass a reference to the `Rc` in `a` as an -argument. - -We could have called `a.clone()` rather than `Rc::clone(&a)`, but Rust’s -convention is to use `Rc::clone` in this case. The implementation of -`Rc::clone` doesn’t make a deep copy of all the data like most types’ -implementations of `clone` do. The call to `Rc::clone` only increments the -reference count, which doesn’t take much time. Deep copies of data can take a -lot of time. By using `Rc::clone` for reference counting, we can visually -distinguish between the deep copy kinds of clones and the kinds of clones that -increase the reference count. When looking for performance problems in the -code, we only need to consider the deep copy clones and can disregard calls to -`Rc::clone`. - -### Cloning an `Rc` Increases the Reference Count - -Let’s change our working example in Listing 15-18 so we can see the reference -counts changing as we create and drop references to the `Rc` in `a`. - -In Listing 15-19, we’ll change `main` so it has an inner scope around list `c`; -then we can see how the reference count changes when `c` goes out of scope. At -each point in the program where the reference count changes, we’ll print the -reference count, which we can get by calling the `Rc::strong_count` function. -This function is named `strong_count` rather than `count` because the `Rc` -type also has a `weak_count`; we’ll see what `weak_count` is used for in the -“Preventing Reference Cycles” section. - -Filename: src/main.rs + + + +リスト15-18: `Rc`を使用する`List`の定義 + + + + + + + +初期化処理に含まれていないので、`use`文を追加して`Rc`をスコープに導入する必要があります。 +`main`で5と10を保持するリストを作成し、`a`の新しい`Rc`に格納しています。それから、 +`b`と`c`を作成する際に、`Rc::clone`関数を呼び出し、引数として`a`の`Rc`への参照を渡しています。 + + + + + + + + + + + + +`Rc::clone(&a)`ではなく、`a.clone()`を呼ぶこともできますが、Rustのしきたりは、この場合`Rc::clone`を使うことです。 +`Rc::clone`の実装は、多くの型の`clone`実装がするように、全てのデータのディープコピーをすることではありません。 +`Rc::clone`の呼び出しは、参照カウントをインクリメントするだけであり、時間はかかりません。 +データのディープコピーは時間がかかることもあります。参照カウントに`Rc::clone`を使うことで、 +視覚的にディープコピーをする類のクローンと参照カウントを増やす種類のクローンを区別することができます。 +コード内でパフォーマンスの問題を探す際、ディープコピーのクローンだけを考慮し、`Rc::clone`の呼び出しを無視できるのです。 + + + +### `Rc`をクローンすると、参照カウントが増える + + + + +`a`の`Rc`への参照を作ったりドロップする毎に参照カウントが変化するのが確かめられるように、 +リスト15-18の動く例を変更しましょう。 + + + + + + + + + +リスト15-19で、リスト`c`を囲む内側のスコープができるよう`main`を変更します; +そうすれば、`c`がスコープを抜けるときに参照カウントがどう変化するか確認できます。 +プログラム内で参照カウントが変更される度に、参照カウントを出力します。参照カウントは、 +`Rc::strong_count`関数を呼び出すことで得られます。`Rc`型には`weak_count`もあるので、 +この関数は`count`ではなく`strong_count`と命名されています; `weak_count`の使用目的は、 +「循環参照を回避する」節で確かめます。 + + + +ファイル名: src/main.rs ```rust # enum List { @@ -171,20 +263,28 @@ type also has a `weak_count`; we’ll see what `weak_count` is used for in the # 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)); } ``` -Listing 15-19: Printing the reference count + + +リスト15-19: 参照カウントを出力する + + -This code prints the following: +このコードは、以下の出力をします: ```text count after creating a = 1 @@ -193,24 +293,39 @@ count after creating c = 3 count after c goes out of scope = 2 ``` -We can see that the `Rc` in `a` has an initial reference count of one; -then each time we call `clone`, the count goes up by one. When `c` goes out of -scope, the count goes down by one. We don’t have to call a function to decrease -the reference count like we have to call `Rc::clone` to increase the reference -count: the implementation of the `Drop` trait decreases the reference count -automatically when an `Rc` value goes out of scope. - -What we can’t see in this example is that when `b` and then `a` go out of scope -at the end of `main`, the count is then 0, and the `Rc` is cleaned up -completely at that point. Using `Rc` allows a single value to have -multiple owners, and the count ensures that the value remains valid as long as -any of the owners still exist. - -Via immutable references, `Rc` allows us to share data between multiple -parts of our program for reading only. If `Rc` allowed us to have multiple -mutable references too, we might violate one of the borrowing rules discussed -in Chapter 4: multiple mutable borrows to the same place can cause data races -and inconsistencies. But being able to mutate data is very useful! In the next -section, we’ll discuss the interior mutability pattern and the `RefCell` -type that we can use in conjunction with an `Rc` to work with this -immutability restriction. + + + + + + + +`a`の`Rc`は最初1という参照カウントであることがわかります; そして、`clone`を呼び出す度に、 +カウントは1ずつ上がります。`c`がスコープを抜けると、カウントは1下がります。参照カウントを増やすのに、 +`Rc::clone`を呼ばなければいけなかったみたいに参照カウントを減らすのに関数を呼び出す必要はありません: +`Rc`値がスコープを抜けるときに`Drop`トレイトの実装が自動的に参照カウントを減らします。 + + + + + + + +この例ではわからないことは、`b`そして`a`が、`main`の終端でスコープを抜ける時に、カウントが0になり、 +その時点で`Rc`が完全に片付けられることです。`Rc`で単独の値に複数の所有者を持たせることができ、 +所有者のいずれも存在している限り、値が有効であり続けることをカウントは保証します。 + + + + + + + + + + +不変参照経由で、`Rc`は読み取り専用でプログラムの複数箇所間でデータを共有させてくれます。 +`Rc`が複数の可変参照を存在させることも許可してくれたら、第4章で議論した借用ルールの1つを侵害する恐れがあります: +同じ場所への複数の可変借用は、データ競合や矛盾を引き起こすことがあるのです。しかし、 +データを可変化する能力はとても有用です!次の節では、内部可変性パターンと、 +`Rc`と絡めて使用してこの不変性制限を手がけられる`RefCell`型について議論します。 From 22b549caee3de1d1a963fe1056c85b7fb9abc719 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 5 Feb 2018 20:39:55 +0900 Subject: [PATCH 113/428] First draft of the chapter 15-5 --- README.md | 1 + .../src/ch15-05-interior-mutability.md | 775 ++++++++++++------ 2 files changed, 504 insertions(+), 272 deletions(-) diff --git a/README.md b/README.md index b972524bb..99152e53d 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ some of the peopleも(一部の人々)などと訳し、[`いくつか`]は`a fe * doの強調用法(I do appreciate it!)は、「実は」「本当に」「実際に」などと訳出します。 * 元来、日本語は無生物主語を嫌う言語なので、主語位置にある無生物は、「により」「によって」「のおかげで」などと訳出し、無生物主語を避けます。 * 基本動詞のhaveですが、上記の方針により、基本的に「AにBがある」「AにBが存在する」などと訳し、「持つ」という訳語を極力避けます(Rust have several wonderful features.のような文がよく出てくるので)。 +* allow, letについて。無生物主語で使われることが多いので、allowは「できる」、letは「させてくれる」などと訳していることが多いです。本来の意味はどちらも「許す」です。(My wife allows me to spend up to 1000 yen on lunch.: 妻は、お昼に1000円まで使わせてくれる)(Let me in!: 入れさせて!)(ちなみにletの方が許す度合いはゆるいです)(余談ですが、Let's doは"let us do": 「〜させてよ」という意味です) * 命令文は、基本的に「〜してください」と訳します。 * 時制について。日本語の時制は、英語ほど厳密ではなく、曖昧なことが多いため、あまり気にする必要はないと考えています。 * 完了形は基本的に本来のイメージに近い「〜してきました」と訳していますが、単純に「〜しました」「〜しています」のように訳している箇所もあります。 diff --git a/second-edition/src/ch15-05-interior-mutability.md b/second-edition/src/ch15-05-interior-mutability.md index 600b912b4..b845c9c0d 100644 --- a/second-edition/src/ch15-05-interior-mutability.md +++ b/second-edition/src/ch15-05-interior-mutability.md @@ -1,78 +1,143 @@ -## `RefCell` and the Interior Mutability Pattern - -*Interior mutability* is a design pattern in Rust that allows you to mutate -data even when there are immutable references to that data: normally, this -action is disallowed by the borrowing rules. To do so, 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. - -Let’s explore this concept by looking at the `RefCell` type that follows the -interior mutability pattern. - -### Enforcing Borrowing Rules at Runtime with `RefCell` - -Unlike `Rc`, the `RefCell` type represents single ownership over the data -it holds. So, what makes `RefCell` different than a type like `Box`? -Recall the borrowing rules you learned in Chapter 4: - -* At any given time, you can have *either* but not both of the following: one - mutable reference or any number of immutable references. -* References must always be valid. - -With references and `Box`, the borrowing rules’ invariants are enforced at -compile time. With `RefCell`, these invariants are enforced *at runtime*. -With references, if you break these rules, you’ll get a compiler error. With -`RefCell`, if you break these rules, your program will `panic!` and exit. - -The advantages of checking the borrowing rules at compile time are that errors -will be caught sooner in the development process, and there is no impact on -runtime performance because all the analysis is completed beforehand. For those -reasons, checking the borrowing rules at compile time is the best choice in the -majority of cases, which is why this is Rust’s default. - -The advantage of checking the borrowing rules at runtime instead is that -certain memory safe scenarios are then allowed, whereas they are disallowed by -the compile time checks. Static analysis, like the Rust compiler, is inherently -conservative. Some properties of code are impossible to detect by analyzing the -code: the most famous example is the Halting Problem, which is beyond the scope -of this book but is an interesting topic to research. - -Because some analysis is impossible, if the Rust compiler can’t be sure the -code complies with the ownership rules, it might reject a correct program; in -this way, it’s conservative. If Rust accepted an incorrect program, users -wouldn’t be able to trust in the guarantees Rust makes. However, if Rust -rejects a correct program, the programmer will be inconvenienced, but nothing -catastrophic can occur. The `RefCell` type is useful when you’re sure your -code follows the borrowing rules, but the compiler is unable to understand and -guarantee that. - -Similar to `Rc`, `RefCell` is only for use in single-threaded scenarios -and will give you a compile time error if you try using it in a multithreaded -context. We’ll talk about how to get the functionality of `RefCell` in a -multithreaded program in Chapter 16. - -Here is a recap of the reasons to choose `Box`, `Rc`, or `RefCell`: - -* `Rc` enables multiple owners of the same data; `Box` and `RefCell` - have single owners. -* `Box` allows immutable or mutable borrows checked at compile time; `Rc` - only allows immutable borrows checked at compile time; `RefCell` allows - immutable or mutable borrows checked at runtime. -* Because `RefCell` allows mutable borrows checked at runtime, we can mutate - the value inside the `RefCell` even when the `RefCell` is immutable. - -Mutating the value inside an immutable value is the *interior mutability* -pattern. Let’s look at a situation in which interior mutability is useful and -examine how it’s possible. - -### Interior Mutability: A Mutable Borrow to an Immutable Value - -A consequence of the borrowing rules is that when we have an immutable value, -we can’t borrow it mutably. For example, this code won’t compile: + + +## `RefCell`と内部可変性パターン + + + + + + + + + + + +内部可変性は、そのデータへの不変参照がある時でさえもデータを可変化できるRustでのデザインパターンです: +普通、この行動は借用ルールにより許可されません。そうするために、このパターンは、データ構造内で`unsafe`コードを使用して、 +可変性と借用を支配するRustの通常のルールを捻じ曲げています。まだ、unsafeコードについては講義していません; +第19章で行います。たとえ、コンパイラが保証できなくても、借用ルールに実行時に従うことが保証できる時、 +内部可変性パターンを使用した型を使用できます。関係する`unsafe`コードはそうしたら、安全なAPIにラップされ、 +外側の型は、不変です。 + + + + +内部可変性パターンに従う`RefCell`型を眺めてこの概念を探求しましょう。 + + + +### `RefCell`で実行時に借用ルールを強制する + + + + + +`Rc`と異なり、`RefCell`型は、保持するデータに対して単独の所有権を表します。では、 +どうして`RefCell`が`Box`のような型と異なるのでしょうか?第4章で学んだ借用ルールを思い出してください: + + + + + +* いかなる時も以下のどちらかが可能になる: 1つの可変参照、あるいはいくつもの不変参照。 +* 参照は常に有効でなければならない。 + + + + + + +参照と`Box`では、借用ルールの不変条件は、コンパイル時に強制されています。`RefCell`では、 +これらの不変条件は、*実行時に*強制されます。参照でこれらの規則を破ったら、コンパイルエラーになりました。 +`RefCell`でこれらの規則を破ったら、プログラムは`panic!`し、終了します。 + + + + + + + + + +コンパイル時に借用ルールを確認する利点は、エラーが開発過程の早い段階でキャッチされ、 +分析が予め全て終わるので、実行パフォーマンスに影響がないことです。そのような理由のため、 +コンパイル時に借用ルールを確認することが大多数の場合において最善の選択であり、 +そのためこれがRustの規定になっているのです。 + + + + + + + + +代わりに実行時に借用ルールを確認する利点は、コンパイル時のチェックでは許可されない特定のメモリ安全の筋書きが可能になることです。 +Rustコンパイラのような静的な分析は、本質的に保守的です。コードを分析しても、検出できないコードの特性もあります: +最も有名な例は、停止性問題であり、この本の範疇を超えていますが、調査するのに面白い話題です。 + +> `編注`: 停止性問題とは、あるチューリング機械(≒コンピュータプログラム・アルゴリズム)が +> そのテープのある初期状態(≒入力)に対し、有限時間で停止するか、という問題。 +> Wikipediaより抜粋 + + + + + + + + + + +不可能な分析もあるので、Rustのコンパイラが、コードが所有権ルールに応じていると確証を得られない場合、 +正しいプログラムを拒否する可能性があります; このように、保守的なのです。コンパイラが不正なプログラムを受け入れたら、 +ユーザは、コンパイラが行う保証を信じることはできなくなるでしょう。しかしながら、 +コンパイラが正当なプログラムを拒否するのなら、プログラマは不便に思うでしょうが、悲劇的なことは何も起こり得ません。 +コードが借用ルールに従っていると確証を得られる時に`RefCell`型は有用ですが、 +コンパイラはそれを理解し、保証できません。 + + + + + + +`Rc`と類似して、`RefCell`もシングルスレッドシナリオで使用するためのものであり、 +試しにマルチスレッドの文脈で使ってみようとすると、コンパイルエラーを出します。 +`RefCell`の機能をマルチスレッドのプログラムで得る方法については、第16章で語ります。 + + + +こちらに`Box`, `Rc`, `RefCell`を選択する理由を要約しておきます: + + + + + + + + + +* `Rc`は、同じデータに複数の所有者を持たせてくれる; `Box`と`RefCell`は単独の所有者。 +* `Box`は、不変または可変借用をコンパイル時に精査してくれる; `Rc`は不変借用のみをコンパイル時に精査してくれる; + `RefCell`は、不変または可変借用を実行時に精査してくれる。 +* `RefCell`は実行時に精査される可変借用を許可するので、`RefCell`が不変でも、 + `RefCell`内の値を可変化できる。 + + + + + +不変な値の中の値を可変化することは、*内部可変性*パターンです。内部可変性が有用になる場面を見て、 +それが可能になる方法を調査しましょう。 + + + +### 内部可変性: 不変値への可変借用 + + + + +借用ルールの結果は、不変値がある時、可変で借用することはできないということです。 +例えば、このコードはコンパイルできません: ```rust,ignore fn main() { @@ -81,10 +146,13 @@ fn main() { } ``` -When we try to compile this code, we’ll get the following error: + + +このコードをコンパイルしようとすると、以下のようなエラーが出ます: ```text error[E0596]: cannot borrow immutable local variable `x` as mutable +(エラー: ローカル変数`x`を可変で借用することはできません) --> src/main.rs:3:18 | 2 | let x = 5; @@ -93,44 +161,74 @@ error[E0596]: cannot borrow immutable local variable `x` as mutable | ^ cannot borrow mutably ``` -However, there are situations in which it would be useful for a value to mutate -itself in its methods, but to other code, the value would appear immutable. -Code outside the value’s methods would not be able to mutate the value. Using -`RefCell` is one way to get the ability to have interior mutability. But -`RefCell` doesn’t get around the borrowing rules completely: the borrow -checker in the compiler allows this interior mutability, and the borrowing -rules are checked at runtime instead. If we violate the rules, we’ll get a -`panic!` instead of a compiler error. - -Let’s work through a practical example where we can use `RefCell` to mutate -an immutable value and see why that is useful. - -#### A Use Case for Interior Mutability: Mock Objects - -A *test double* is the general programming concept for a type used in place of -another type during testing. *Mock objects* are specific types of test doubles -that record what happens during a test so we can assert that the correct -actions took place. - -Rust doesn’t have objects in the same sense as other languages have objects, -and Rust doesn’t have mock object functionality built into the standard library -like some other languages do. However, we can definitely create a struct that -will serve the same purposes as a mock object. - -Here’s the scenario we’ll test: we’ll create a library that tracks a value -against a maximum value and sends messages based on how close to the maximum -value the current value is. This library could be used for keeping track of a -user’s quota for the number of API calls they’re allowed to make, for example. - -Our library will only provide the functionality of tracking how close to the -maximum a value is and what the messages should be at what times. Applications -that use our library will be expected to provide the mechanism for sending the -messages: the application could put a message in the application, send an -email, send a text message, or something else. The library doesn’t need to know -that detail. All it needs is something that implements a trait we’ll provide -called `Messenger`. Listing 15-20 shows the library code: - -Filename: src/lib.rs + + + + + + + + + +ですが、メソッド内で値が自身を可変化するけれども、他のコードにとっては、 +その値は不変に見えることが有用な場面もあります。その値のメソッドの外のコードは、その値を可変化することはできないでしょう。 +`RefCell`を使うことは、内部可変性を取得する能力を得る1つの方法です。しかし、 +`RefCell`は借用ルールを完全に回避するものではありません: コンパイラの借用精査機は、内部可変性を許可し、 +借用ルールは代わりに実行時に精査されます。この規則を侵害したら、コンパイルエラーではなく`panic!`になるでしょう。 + + + + +`RefCell`を使用して不変値を可変化する実践的な例に取り組み、それが役に立つ理由を確認しましょう。 + + + +#### 内部可変性のユースケース: モックオブジェクト + + + + + + +*テストダブル*は、テスト中に別の型の代わりに使用される型の一般的なプログラミングの概念です。 +*モックオブジェクト*は、テスト中に起きることを記録するテストダブルの特定の型なので、 +正しい動作が起きたことをアサートできます。 + +> `編注`: テストダブルとは、ソフトウェアテストにおいて、テスト対象が依存しているコンポーネントを置き換える代用品のこと + + + + + + +Rustには、他の言語でいうオブジェクトは存在せず、また、他の言語のように標準ライブラリにモックオブジェクトの機能が組み込まれてもいません。 +ですが、同じ目的をモックオブジェクトとして提供する構造体を作成することは確かにできます。 + + + + + + +以下が、テストを行う筋書きです: 値を最大値に対して追跡し、現在値が最大値に近い程度に基づいてメッセージを送信するライブラリを作成します。 +このライブラリは、ユーザが行うことのできるAPIコールの数の割り当てを追跡するのに使用することができるでしょう。 + + + + + + + + + +作成するライブラリは、値がどれくらい最大に近いかと、いつどんなメッセージになるべきかを追いかける機能を提供するだけです。 +このライブラリを使用するアプリケーションは、メッセージを送信する機構を提供すると期待されるでしょう: +アプリケーションは、アプリケーションにメッセージを置いたり、メールを送ったり、テキストをメッセージを送るなどできるでしょう。 +ライブラリはその詳細を知る必要はありません。必要なのは、提供する`Messenger`と呼ばれるトレイトを実装している何かなのです。 +リスト15-20は、ライブラリのコードを示しています: + + + +ファイル名: src/lib.rs ```rust pub trait Messenger { @@ -159,39 +257,57 @@ impl<'a, T> LimitTracker<'a, T> let percentage_of_max = self.value as f64 / self.max as f64; if percentage_of_max >= 0.75 && percentage_of_max < 0.9 { + // 警告: 割り当ての75%以上を使用してしまいました self.messenger.send("Warning: You've used up over 75% of your quota!"); } else if percentage_of_max >= 0.9 && percentage_of_max < 1.0 { + // 切迫した警告: 割り当ての90%以上を使用してしまいました self.messenger.send("Urgent warning: You've used up over 90% of your quota!"); } else if percentage_of_max >= 1.0 { + // エラー: 割り当てを超えています self.messenger.send("Error: You are over your quota!"); } } } ``` -Listing 15-20: A library to keep track of how close to a -maximum value a value is and warn when the value is at certain levels - -One important part of this code is that the `Messenger` trait has one method -called `send` that takes an immutable reference to `self` and text of the -message. This is the interface our mock object needs to have. The other -important part is that we want to test the behavior of the `set_value` method -on the `LimitTracker`. We can change what we pass in for the `value` parameter, -but `set_value` doesn’t return anything for us to make assertions on. We want -to be able to say that if we create a `LimitTracker` with something that -implements the `Messenger` trait and a particular value for `max`, when we pass -different numbers for `value`, the messenger is told to send the appropriate -messages. - -We need a mock object that instead of sending an email or text message when we -call `send` will only keep track of the messages it’s told to send. We can -create a new instance of the mock object, create a `LimitTracker` that uses the -mock object, call the `set_value` method on `LimitTracker`, and then check that -the mock object has the messages we expect. Listing 15-21 shows an attempt of -implementing a mock object to do just that but that the borrow checker won’t -allow: - -Filename: src/lib.rs + + + +リスト15-20: 値が最大値にどれくらい近いかを追跡し、任意のレベルの時に警告するライブラリ + + + + + + + + + + + + +このコードの重要な部分の1つは、`Messenger`トレイトには、`self`への不変参照とメッセージのテキストを取る`send`というメソッドが1つあることです。 +これが、モックオブジェクトが持つ必要のあるインターフェイスなのです。もう1つの重要な部分は、 +`LimitTracker`の`set_value`メソッドの振る舞いをテストしたいということです。`value`引数に渡すものを変えることができますが、 +`set_value`はアサートを行えるものは何も返してくれません。`LimitTracker`を`Messenger`トレイトを実装する何かと、 +`max`の特定の値で生成したら、`value`に異なる数値を渡した時にメッセンジャーは適切なメッセージを送ると指示されると言えるようになりたいです。 + + + + + + + + + +`send`を呼び出す時にメールやテキストメッセージを送る代わりに送ると指示されたメッセージを追跡するだけのモックオブジェクトが必要です。 +モックオブジェクトの新規インスタンスを生成し、モックオブジェクトを使用する`LimitTracker`を生成し、 +`LimitTracker`の`set_value`を呼び出し、それからモックオブジェクトに期待しているメッセージがあることを確認できます。 +リスト15-21は、それだけをするモックオブジェクトを実装するけど、借用精査機が許可してくれない試行を示しています: + + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -226,31 +342,47 @@ mod tests { } ``` -Listing 15-21: An attempt to implement a `MockMessenger` -that isn’t allowed by the borrow checker - -This test code defines a `MockMessenger` struct that has a `sent_messages` -field with a `Vec` of `String` values to keep track of the messages it’s told -to send. We also define an associated function `new` to make it convenient to -create new `MockMessenger` values that start with an empty list of messages. We -then implement the `Messenger` trait for `MockMessenger` so we can give a -`MockMessenger` to a `LimitTracker`. In the definition of the `send` method, we -take the message passed in as a parameter and store it in the `MockMessenger` -list of `sent_messages`. - -In the test, we’re testing what happens when the `LimitTracker` is told to set -`value` to something that is more than 75 percent of the `max` value. First, we -create a new `MockMessenger`, which will start with an empty list of messages. -Then we create a new `LimitTracker` and give it a reference to the new -`MockMessenger` and a `max` value of 100. We call the `set_value` method on the -`LimitTracker` with a value of 80, which is more than 75 percent of 100. Then -we assert that the list of messages that the `MockMessenger` is keeping track -of should now have one message in it. - -However, there’s one problem with this test, as shown here: + + + +リスト15-21: 借用精査機が許可してくれない`MockMessanger`を実装しようとする + + + + + + + + + + +このテストコードは`String`の`Vec`で送信すると指示されたメッセージを追跡する`sent_messages`フィールドのある`MockMessenger`構造体を定義しています。 +また、空のメッセージリストから始まる新しい`MockMessenger`値を作るのを便利にしてくれる関連関数の`new`も定義しています。 +それから`MockMessenger`に`Messenger`トレイトを実装しているので、`LimitTracker`に`MockMessenger`を与えられます。 +`send`メソッドの定義で引数として渡されたメッセージを取り、`sent_messages`の`MockMessenger`リストに格納しています。 + + + + + + + + + + +テストでは、`max`値の75%以上になる何かに`value`をセットしろと`LimitTracker`が指示される時に起きることをテストしています。 +まず、新しい`MockMessenger`を生成し、空のメッセージリストから始まります。そして、 +新しい`LimitTracker`を生成し、新しい`MockMessenger`の参照と100という`max`値を与えます。 +`LimitTracker`の`set_value`メソッドは80という値で呼び出し、これは100の75%を上回っています。 +そして、`MockMessenger`が追いかけているメッセージのリストが今は1つのメッセージを含んでいるはずとアサートします。 + + + +ところが、以下のようにこのテストには1つ問題があります: ```text error[E0596]: cannot borrow immutable field `self.sent_messages` as mutable +(エラー: 不変なフィールド`self.sent_messages`を可変で借用できません) --> src/lib.rs:52:13 | 51 | fn send(&self, message: &str) { @@ -259,18 +391,28 @@ error[E0596]: cannot borrow immutable field `self.sent_messages` as mutable | ^^^^^^^^^^^^^^^^^^ cannot mutably borrow immutable field ``` -We can’t modify the `MockMessenger` to keep track of the messages because the -`send` method takes an immutable reference to `self`. We also can’t take the -suggestion from the error text to use `&mut self` instead because then the -signature of `send` wouldn’t match the signature in the `Messenger` trait -definition (feel free to try and see what error message you get). + + + + + + +`send`メソッドは`self`への不変参照を取るので、`MockMessenger`を変更してメッセージを追跡できないのです。 +代わりに`&mut self`を使用するというエラーテキストからの提言を選ぶこともできないのです。 +そうしたら、`send`のシグニチャが、`Messenger`トレイト定義のシグニチャと一致しなくなるからです(気軽に試してエラーメッセージを確認してください)。 + + + + + -This is a situation in which interior mutability can help! We’ll store the -`sent_messages` within a `RefCell`, and then the `send` message will be -able to modify `sent_messages` to store the messages we’ve seen. Listing 15-22 -shows what that looks like: +これは、内部可変性が役に立つ場面なのです!`sent_messages`を`RefCell`内部に格納し、 +そして`send`メッセージは、`sent_messages`を変更して見かけたメッセージを格納できるようになるでしょう。 +リスト15-22は、それがどんな感じかを示しています: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust #[cfg(test)] @@ -306,50 +448,83 @@ mod tests { } ``` -Listing 15-22: Using `RefCell` to mutate an inner -value while the outer value is considered immutable + + + +リスト15-22: 外側の値は不変と考えられる一方で`RefCell`で内部の値を可変化する + + + + + +さて、`sent_messages`フィールドは、`Vec`ではなく、型`RefCell>`になりました。 +`new`関数で、空のベクタの周りに`RefCell>`を新しく作成しています。 + + + + + + + + +`send`メソッドの実装については、最初の引数はそれでも`self`への不変借用で、トレイト定義と合致しています。 +`RefCell>`の`borrow_mut`を`self.sent_messages`に呼び出し、 +`RefCell>`の中の値への可変参照を得て、これはベクタになります。 +それからベクタへの可変参照に`push`を呼び出して、テスト中に送られるメッセージを追跡しています。 + + + + + +行わなければならない最後の変更は、アサート内部にあります: 内部のベクタにある要素の数を確認するため、 +`RefCell>`に`borrow`を呼び出し、ベクタへの不変参照を得ています。 -The `sent_messages` field is now of type `RefCell>` instead of -`Vec`. In the `new` function, we create a new `RefCell>` -instance around the empty vector. + -For the implementation of the `send` method, the first parameter is still an -immutable borrow of `self`, which matches the trait definition. We call -`borrow_mut` on the `RefCell>` in `self.sent_messages` to get a -mutable reference to the value inside the `RefCell>`, which is -the vector. Then we can call `push` on the mutable reference to the vector to -keep track of the messages sent during the test. +`RefCell`の使用法を見かけたので、動作法を深掘りしましょう! -The last change we have to make is in the assertion: to see how many items are -in the inner vector, we call `borrow` on the `RefCell>` to get an -immutable reference to the vector. + -Now that you’ve seen how to use `RefCell`, let’s dig into how it works! +#### `RefCell`は実行時に借用を追いかける -#### `RefCell` Keeps Track of Borrows at Runtime + + + + + + -When creating immutable and mutable references, we use the `&` and `&mut` -syntax, respectively. With `RefCell`, we use the `borrow` and `borrow_mut` -methods, which are part of the safe API that belongs to `RefCell`. The -`borrow` method returns the smart pointer type `Ref`, and `borrow_mut` -returns the smart pointer type `RefMut`. Both types implement `Deref` so -we can treat them like regular references. +不変および可変参照を作成する時、それぞれ`&`と`&mut`記法を使用します。`RefCell`では、 +`borrow`と`borrow_mut`メソッドを使用し、これらは`RefCell`に所属する安全なAPIの一部です。 +`borrow`メソッドは、スマートポインタ型の`Ref`を返し、`borrow_mut`はスマートポインタ型の`RefMut`を返します。 +どちらの型も`Deref`を実装しているので、普通の参照のように扱うことができます。 -The `RefCell` keeps track of how many `Ref` and `RefMut` smart -pointers are currently active. Every time we call `borrow`, the `RefCell` -increases its count of how many immutable borrows are active. When a `Ref` -value goes out of scope, the count of immutable borrows goes down by one. Just -like the compile time borrowing rules, `RefCell` lets us have many immutable -borrows or one mutable borrow at any point in time. + + + + + + -If we try to violate these rules, rather than getting a compiler error like we -would with references, the implementation of `RefCell` will `panic!` at -runtime. Listing 15-23 shows a modification of the implementation of `send` in -Listing 15-22. We’re deliberately trying to create two mutable borrows active -for the same scope to illustrate that `RefCell` prevents us from doing this -at runtime: +`RefCell`は、現在活動中の`Ref`と`RefMut`スマートポインタの数を追いかけます。 +`borrow`を呼び出す度に、`RefCell`は活動中の不変参照の数を増やします。`Ref`の値がスコープを抜けたら、 +不変参照の数は1下がります。コンパイル時の借用ルールと全く同じように、`RefCell`はいかなる時も、 +多くの不変借用または1つの可変借用を持たせてくれるのです。 -Filename: src/lib.rs + + + + + + + +これらの規則を侵害しようとすれば、参照のようにコンパイルエラーになるのではなく、 +`RefCell`の実装は実行時に`panic!`するでしょう。リスト15-23はリスト15-22の`send`実装に対する変更を示しています。 +同じスコープで2つの可変借用が活動するようわざと生成し、`RefCell`が実行時にこれをすることを阻止してくれるところを具体化しています。 + + + +ファイル名: src/lib.rs ```rust,ignore impl Messenger for MockMessenger { @@ -363,14 +538,21 @@ impl Messenger for MockMessenger { } ``` -Listing 15-23: Creating two mutable references in the -same scope to see that `RefCell` will panic + + + +リスト15-23: 同じスコープで2つの可変参照を生成して`RefCell`がパニックすることを確かめる -We create a variable `one_borrow` for the `RefMut` smart pointer returned -from `borrow_mut`. Then we create another mutable borrow in the same way in the -variable `two_borrow`. This makes two mutable references in the same scope, -which isn’t allowed. When we run the tests for our library, the code in Listing -15-23 will compile without any errors, but the test will fail: + + + + + + +`borrow_mut`から返ってきた`RefMut`スマートポインタに対して変数`one_borrow`を生成しています。 +そして、同様にして変数`two_borrow`にも別の可変借用を生成しています。これにより同じスコープで2つの可変参照ができ、 +これは許可されないことです。このテストをライブラリ用に走らせると、リスト15-23のコードはエラーなくコンパイルできますが、 +テストは失敗するでしょう: ```text ---- tests::it_sends_an_over_75_percent_warning_message stdout ---- @@ -379,36 +561,59 @@ which isn’t allowed. When we run the tests for our library, the code in Listin note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` -Notice that the code panicked with the message `already borrowed: -BorrowMutError`. This is how `RefCell` handles violations of the borrowing -rules at runtime. - -Catching borrowing errors at runtime rather than compile time means that we -would find a mistake in our code later in the development process and possibly -not even until our code was deployed to production. Also, our code will incur a -small runtime performance penalty as a result of keeping track of the borrows -at runtime rather than compile time. However, using `RefCell` makes it -possible for us to write a mock object that can modify itself to keep track of -the messages it has seen while we’re using it in a context where only immutable -values are allowed. We can use `RefCell` despite its trade-offs to get more -functionality than regular references give us. - -### Having Multiple Owners of Mutable Data by Combining `Rc` and `RefCell` - -A common way to use `RefCell` is in combination with `Rc`. Recall that -`Rc` lets us have multiple owners of some data, but it only gives us -immutable access to that data. If we have an `Rc` that holds a `RefCell`, -we can get a value that can have multiple owners *and* that we can mutate! - -For example, recall the cons list example in Listing 15-18 where we used -`Rc` to let us have multiple lists share ownership of another list. Because -`Rc` only holds immutable values, we can’t change any of the values in the -list once we’ve created them. Let’s add in `RefCell` to gain the ability to -change the values in the lists. Listing 15-24 shows that by using a -`RefCell` in the `Cons` definition, we can modify the value stored in all -the lists: - -Filename: src/main.rs + + + + +コードは、`already borrowed: BorrowMutError`というメッセージとともにパニックしたことに気付いてください。 +このようにして`RefCell`は実行時に借用ルールの侵害を扱うのです。 + + + + + + + + + + + +コンパイル時ではなく実行時に借用エラーをキャッチするということは、開発過程の遅い段階でコードのミスを発見し、 +コードをプロダクションにデプロイする時までさえ発見しないことを意味します。また、 +コンパイル時ではなく、実行時に借用を追いかける結果として、少し実行時にパフォーマンスを犠牲にするでしょう。 +しかしながら、`RefCell`を使うことで不変値のみが許可される文脈で使用しつつ、 +自身を変更して見かけたメッセージを追跡するモックオブジェクトを書くことを可能にしてくれます。 +代償にも関わらず`RefCell`を使用して、普通の参照よりも多くの機能を得ることができるわけです。 + + + +### `Rc`と`RefCell`を組み合わせることで可変なデータに複数の所有者を持たせる + + + + + + +`RefCell`の一般的な使用法は、`Rc`と組み合わせることにあります。`Rc`は何らかのデータに複数の所有者を持たせてくれるけれども、 +そのデータに不変のアクセスしかさせてくれないことを思い出してください。`RefCell`を抱える`Rc`があれば、 +複数の所有者を持ち*そして*、可変化できる値を得ることができるのです。 + + + + + + + + + +例を挙げれば、`Rc`を使用して複数のリストに別のリストの所有権を共有させたリスト15-18のコンスリストの例を思い出してください。 +`Rc`は不変値を抱えるだけなので、一旦生成したら、リストの値はどれも変更できません。`RefCell`を含めて、 +リストの値を変更する能力を得ましょう。`RefCell`を`Cons`定義で使用することで、 +リスト全てに格納されている値を変更できることをリスト15-24は示しています: + + + +ファイル名: src/main.rs ```rust #[derive(Debug)] @@ -437,28 +642,45 @@ fn main() { } ``` -Listing 15-24: Using `Rc>` to create a -`List` that we can mutate + + + +リスト15-24: `Rc>`で可変化できる`List`を生成する + + + + + + + + +`Rc>`のインスタンスの値を生成し、`value`という名前の変数に格納しているので、 +直接後ほどアクセスすることができます。そして、`a`に`value`を持つ`Cons`列挙子で`List`を生成しています。 +`value`から`a`に所有権を移したり、`a`が`value`から借用するのではなく、`a`と`value`どちらにも中の`5`の値の所有権を持たせるよう、 +`value`をクローンする必要があります。 + + + + +リスト`a`を`Rc`に包んでいるので、リスト`b`と`c`を生成する時に、どちらも`a`を参照できます。 +リスト15-18ではそうしていました。 -We create a value that is an instance of `Rc` and store it in a -variable named `value` so we can access it directly later. Then we create a -`List` in `a` with a `Cons` variant that holds `value`. We need to clone -`value` so both `a` and `value` have ownership of the inner `5` value rather -than transferring ownership from `value` to `a` or having `a` borrow from -`value`. + + + + + + -We wrap the list `a` in an `Rc` so when we create lists `b` and `c`, they -can both refer to `a`, which is what we did in Listing 15-18. +`a`、`b`、`c`のリストを作成した後、`value`の値に10を足しています。これを`value`の`borrow_mut`を呼び出すことで行い、 +これは、第5章で議論した自動参照外し機能(「`->`演算子はどこに行ったの?」節をご覧ください)を使用して、 +`Rc`を内部の`RefCell`値に参照外ししています。`borrow_mut`メソッドは、 +`RefMut`スマートポインタを返し、それに対して参照外し演算子を使用し、中の値を変更します。 -After we’ve created the lists in `a`, `b`, and `c`, we add 10 to the value in -`value`. We do this by calling `borrow_mut` on `value`, which uses the -automatic dereferencing feature we discussed in Chapter 5 (see the section -“Where’s the `->` Operator?”) to dereference the `Rc` to the inner -`RefCell` value. The `borrow_mut` method returns a `RefMut` smart -pointer, and we use the dereference operator on it and change the inner value. + + -When we print `a`, `b`, and `c`, we can see that they all have the modified -value of 15 rather than 5: +`a`、`b`、`c`を出力すると、全て5ではなく、変更された15という値になっていることがわかります。 ```text a after = Cons(RefCell { value: 15 }, Nil) @@ -466,16 +688,25 @@ b after = Cons(RefCell { value: 6 }, Cons(RefCell { value: 15 }, Nil)) c after = Cons(RefCell { value: 10 }, Cons(RefCell { value: 15 }, Nil)) ``` -This technique is pretty neat! By using `RefCell`, we have an outwardly -immutable `List`. But we can use the methods on `RefCell` that provide -access to its interior mutability so we can modify our data when we need to. -The runtime checks of the borrowing rules protect us from data races, and it’s -sometimes worth trading a bit of speed for this flexibility in our data -structures. - -The standard library has other types that provide interior mutability, such as -`Cell`, which is similar except that instead of giving references to the -inner value, the value is copied in and out of the `Cell`. There’s also -`Mutex`, which offers interior mutability that’s safe to use across threads; -we’ll discuss its use in Chapter 16. Check out the standard library docs for -more details on the differences between these types. + + + + + + + +このテクニックは非常に綺麗です!`RefCell`を使用することで表面上は不変な`List`を持てます。 +しかし、内部可変性へのアクセスを提供する`RefCell`のメソッドを使用できるので、必要な時にはデータを変更できます。 +借用ルールを実行時に精査することでデータ競合を防ぎ、時としてデータ構造でちょっとのスピードを犠牲にこの柔軟性を得るのは価値があります。 + + + + + + + + +標準ライブラリには、`Cell`などの内部可変性を提供する他の型もあり、この型は、内部値への参照を与える代わりに、 +値は`Cell`の内部や外部へコピーされる点を除き似ています。また`Mutex`もあり、 +これはスレッド間で使用するのが安全な内部可変性を提供します; 第16章で使用することを議論しましょう。 +標準ライブラリのドキュメンテーションをチェックして、これらの型の違いを詳しく知ってください。 From fbb076d4091058d460d250d5b7bd7fa32168244d Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Tue, 6 Feb 2018 20:16:32 +0900 Subject: [PATCH 114/428] First draft of the chapter 15-6 --- .../src/ch15-06-reference-cycles.md | 693 ++++++++++++------ 1 file changed, 452 insertions(+), 241 deletions(-) diff --git a/second-edition/src/ch15-06-reference-cycles.md b/second-edition/src/ch15-06-reference-cycles.md index aeb9d38d6..11f1b45be 100644 --- a/second-edition/src/ch15-06-reference-cycles.md +++ b/second-edition/src/ch15-06-reference-cycles.md @@ -1,21 +1,36 @@ -## Reference Cycles Can Leak Memory + -Rust’s memory safety guarantees make it *difficult* but not impossible to -accidentally create memory that is never cleaned up (known as a *memory leak*). -Preventing memory leaks entirely is not one of Rust’s guarantees in the same -way that disallowing data races at compile time is, meaning memory leaks are -memory safe in Rust. We can see that Rust allows memory leaks by using `Rc` -and `RefCell`: it’s possible to create references where items refer to each -other in a cycle. This creates memory leaks because the reference count of each -item in the cycle will never reach 0, and the values will never be dropped. +## 循環参照してメモリをリークすることもある -### Creating a Reference Cycle + + + + + + + + -Let’s look at how a reference cycle might happen and how to prevent it, -starting with the definition of the `List` enum and a `tail` method in Listing -15-25: +Rustのメモリ安全保証により誤って絶対に片付けられることのないメモリ(*メモリリーク*として知られています)を生成してしまうことが困難にはなりますが、 +不可能にはなりません。コンパイル時にデータ競合を防ぐのと同じようにメモリリークを完全に回避することは、 +Rustの保証の一つではなく、メモリリークはRustにおいてはメモリ安全であることを意味します。 +Rustでは、`Rc`と`RefCell`を使用してメモリリークを許可するとわかります: +要素がお互いに循環して参照する参照を生成することも可能ということです。循環の各要素の参照カウントが絶対に0にならないので、 +これはメモリリークを起こし、値は絶対にドロップされません。 -Filename: src/main.rs + + +### 循環参照させる + + + + + +リスト15-25の`List`enumの定義と`tail`メソッドから始めて、循環参照が起こる可能性のある方法とその回避策を見ましょう: + + + +ファイル名: src/main.rs @@ -42,23 +57,35 @@ impl List { } ``` -Listing 15-25: A cons list definition that holds a -`RefCell` so we can modify what a `Cons` variant is referring to + + + +リスト15-25: `Cons`列挙子が参照しているものを変更できるように`RefCell`を抱えているコンスリストの定義 + + + + + + + -We’re using another variation of the `List` definition in Listing 15-5. The -second element in the `Cons` variant is now `RefCell>`, meaning that -instead of having the ability to modify the `i32` value like we did in Listing -15-24, we want to modify which `List` a `Cons` variant is pointing to. We’re -also adding a `tail` method to make it convenient for us to access the second -item if we have a `Cons` variant. +リスト15-5の`List`定義の別バリエーションを使用しています。`Cons`列挙子の2番目の要素はこれで`RefCell>`になり、 +リスト15-24のように`i32`値を変更する能力があるのではなく、`Cons`列挙子が指している`List`の先を変えたいということです。 +また、`tail`メソッドを追加して`Cons`列挙子があるときに2番目の要素にアクセスするのが便利になるようにしています。 -In Listing 15-26, we’re adding a `main` function that uses the definitions in -Listing 15-25. This code creates a list in `a` and a list in `b` that points to -the list in `a`, and then modifies the list in `a` to point to `b`, which -creates a reference cycle. There are `println!` statements along the way to -show what the reference counts are at various points in this process: + + + + + -Filename: src/main.rs +リスト15-26でリスト15-25の定義を使用する`main`関数を追加しています。このコードは、`a`にリストを、 +`b`に`a`のリストを指すリストを作成し、それから`a`のリストを変更して`b`を指し、循環参照させます。 +その流れの中に過程のいろんな場所での参照カウントを示す`println!`文が存在しています。 + + + +ファイル名: src/main.rs ```rust # use List::{Cons, Nil}; @@ -82,44 +109,64 @@ show what the reference counts are at various points in this process: 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 - // println!("a next item = {:?}", a.tail()); + // 次の行のコメントを外して循環していると確認してください; スタックオーバーフローします + // println!("a next item = {:?}", a.tail()); // aの次の要素 = {:?} } ``` -Listing 15-26: Creating a reference cycle of two `List` -values pointing to each other + + + +リスト15-26: 2つの`List`値がお互いを指して循環参照する + + + + + -We create an `Rc` instance holding a `List` value in the variable `a` -with an initial list of `5, Nil`. We then create an `Rc` instance -holding another `List` value in the variable `b` that contains the value 10 and -then points to the list in `a`. +最初のリストが`5, Nil`の`List`値を保持する`Rc`インスタンスを変数`a`に生成します。 +そして、値10とそれから`a`のリストを指す別の`List`値を保持する`Rc`インスタンスを変数`b`に生成します。 -We modify `a` so it points to `b` instead of `Nil`, which creates a cycle. We -do that by using the `tail` method to get a reference to the -`RefCell>` in `a`, which we put in the variable `link`. Then we use -the `borrow_mut` method on the `RefCell>` to change the value inside -from an `Rc` that holds a `Nil` value to the `Rc` in `b`. + + + + + -When we run this code, keeping the last `println!` commented out for the -moment, we’ll get this output: +`a`が`Nil`ではなく`b`を指すように変更して、循環にさせます。`tail`メソッドを使用して、 +`a`の`RefCell>`への参照を得ることでそうして、この参照は変数`link`に配置します。 +それから`RefCell>`の`borrow_mut`メソッドを使用して中の値を`Nil`値を持つ`Rc`から、 +`b`の`Rc`に変更します。 + + + + +最後の`println!`を今だけコメントアウトしたまま、このコードを実行すると、こんな出力が得られます: ```text a initial rc count = 1 @@ -131,88 +178,144 @@ b rc count after changing a = 2 a rc count after changing a = 2 ``` -The reference count of the `Rc` instances in both `a` and `b` are 2 -after we change the list in `a` to point to `b`. At the end of `main`, Rust -will try to drop `b` first, which will decrease the count in each of the -`Rc` instances in `a` and `b` by one. - -However, because `a` is still referencing the `Rc` that was in `b`, -that `Rc` has a count of 1 rather than 0, so the memory the -`Rc` has on the heap won’t be dropped. The memory will just sit there -with a count of one, forever. To visualize this reference cycle, we’ve created -a diagram in Figure 15-4: - -Reference cycle of lists - -Figure 15-4: A reference cycle of lists `a` and `b` -pointing to each other - -If you uncomment the last `println!` and run the program, Rust will try to -print this cycle with `a` pointing to `b` pointing to `a` and so forth until it -overflows the stack. - -In this case, right after we create the reference cycle, the program ends. The -consequences of this cycle aren’t very dire. If a more complex program -allocates lots of memory in a cycle and holds onto it for a long time, the -program would use more memory than it needs and might overwhelm the system, -causing it to run out of available memory. - -Creating reference cycles is not easily done, but it’s not impossible either. -If you have `RefCell` values that contain `Rc` values or similar nested -combinations of types with interior mutability and reference counting, you must -ensure that you don’t create cycles; you can’t rely on Rust to catch them. -Creating a reference cycle would be a logic bug in your program that you should -use automated tests, code reviews, and other software development practices to -minimize. - -Another solution for avoiding reference cycles is reorganizing your data -structures so that some references express ownership and some references don’t. -As a result, you can have cycles made up of some ownership relationships and -some non-ownership relationships, and only the ownership relationships affect -whether or not a value can be dropped. In Listing 15-25, we always want `Cons` -variants to own their list, so reorganizing the data structure isn’t possible. -Let’s look at an example using graphs made up of parent nodes and child nodes -to see when non-ownership relationships are an appropriate way to prevent -reference cycles. - -### Preventing Reference Cycles: Turn an `Rc` into a `Weak` - -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. We 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 we call `Rc::downgrade`, we get a smart -pointer of type `Weak`. Instead of increasing the `strong_count` in the -`Rc` instance by one, calling `Rc::downgrade` increases the `weak_count` -by one. 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. - -Strong references are how we can share ownership of an `Rc` instance. Weak -references don’t express an ownership relationship. 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. - -Because the value that `Weak` references might have been dropped, to do -anything with the value that a `Weak` is pointing to, we must make sure the -value still exists. We do this by calling the `upgrade` method on a `Weak` -instance, which will return an `Option>`. We’ll get a result of `Some` if -the `Rc` value has not been dropped yet and a result of `None` if the -`Rc` value has been dropped. Because `upgrade` returns an `Option`, Rust -will ensure that we handle the `Some` case and the `None` case, and there won’t -be an invalid pointer. - -As an example, rather than using a list whose items know only about the next -item, we’ll create a tree whose items know about their children items *and* -their parent items. - -#### Creating a Tree Data Structure: a `Node` with Child Nodes - -To start, we’ll build a tree with nodes that know about their child nodes. -We’ll create a struct named `Node` that holds its own `i32` value as well as -references to its children `Node` values: - -Filename: src/main.rs + + + + + +`a`のリストを`b`を指すように変更した後の`a`と`b`の`Rc`インスタンスの参照カウントは2です。 +`main`の終端で、コンパイラはまず`b`をドロップしようとし、`a`と`b`の各`Rc`インスタンスのカウントを1減らします。 + + + + + + + +しかしながら、それでも`a`は`b`にあった`Rc`を参照しているので、その`Rc`のカウントは0ではなく1になり、 +その`Rc`がヒープに確保していたメモリはドロップされません。メモリはただ、カウント1のままそこに永遠に居座るのです。 +この循環参照を可視化するために、図15-4に図式を作成しました: + + + +リストの循環参照 + + + + +図15-4: お互いを指すリスト`a`と`b`の循環参照 + + + + + +最後の`println!`のコメントを外してプログラムを実行したら、`a`が`b`を指して、`b`が`a`を指してと、 +スタックがオーバーフローするまでコンパイラはこの循環を出力しようとするでしょう。 + + + + + + + +この場合、循環参照を作る直後にプログラムは終了します。この循環の結果は、それほど悲壮なものではありません。 +より複雑なプログラムが多くのメモリを循環で確保し長い間その状態を保ったら、プログラムは必要以上のメモリを使用し、 +使用可能なメモリを枯渇させてシステムを参らせてしまう可能性があります。 + + + + + + + + + +循環参照は簡単にできることではありませんが、不可能というわけでもありません。 +`Rc`値を含む`RefCell`値があるなどの内部可変性と参照カウントのある型がネストしてコンビネーションしていたら、 +循環していないことを保証しなければなりません; コンパイラがそれを捕捉することを信頼できないのです。 +循環参照をするのは、自動化テストやコードレビューなどの他のソフトウェア開発手段を使用して最小化すべきプログラム上のロジックバグでしょう。 + + + + + + + + + + + +循環参照を回避する別の解決策は、ある参照は所有権を表現して他の参照はしないというようにデータ構造を再構成することです。 +結果として所有権のある関係と所有権のない関係からなる循環ができ、所有権のある関係だけが値がドロップされうるかどうかに影響します。 +リスト15-25では、常に`Cons`列挙子にリストを所有してほしいので、データ構造を再構成することはできません。 +親ノードと子ノードからなるグラフを使った例に目を向けて、どんな時に所有権のない関係が循環参照を回避するのに適切な方法になるか確認しましょう。 + + + +### 循環参照を回避する: `Rc`を`Weak`に変換する + + + + + + + + + + + + +ここまで、`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`インスタンスの所有権を共有する方法です。弱い参照は、所有権関係を表現しません。 +ひとたび、関係する値の強い参照カウントが0になれば、弱い参照が関わる循環はなんでも破壊されるので、 +循環参照にはなりません。 + + + + + + + + + + +`Weak`が参照する値はドロップされてしまう可能性があるので、`Weak`が指す値に何かをするには、 +値がまだ存在することを確認しなければなりません。`Weak`の`upgrade`メソッドを呼び出すことでこれをし、 +このメソッドは`Option>`を返します。`Rc`値がまだドロップされていなければ、`Some`の結果が、 +`Rc`値がドロップ済みなら、`None`の結果が得られます。`upgrade`が`Option`を返すので、 +コンパイラは、`Some`ケースと`None`ケースを扱っていることを確かめてくれ、無効なポインタは存在しません。 + + + + + +例として、要素が次の要素を知っているだけのリストを使うのではなく、要素が子要素*と*親要素を知っている木を作りましょう。 + + + +#### 木データ構造を作る: 子ノードのある`Node` + + + + + +手始めに子ノードを知っているノードのある木を構成します。独自の`i32`値と子供の`Node`値への参照を抱える`Node`という構造体を作ります: + + + +ファイル名: src/main.rs ```rust use std::rc::Rc; @@ -225,17 +328,27 @@ struct Node { } ``` -We want a `Node` to own its children, and we want to share that ownership with -variables so we can access each `Node` in the tree directly. To do this, we -define the `Vec` items to be values of type `Rc`. We also want to -modify which nodes are children of another node, so we have a `RefCell` in -`children` around the `Vec>`. + + + + + + +`Node`に子供を所有してほしく、木の各`Node`に直接アクセスできるよう、その所有権を変数と共有したいです。 +こうするために、`Vec`要素を型`Rc`の値になるよう定義しています。どのノードが他のノードの子供になるかも変更したいので、 +`Vec>`の周りの`children`を`RefCell`にしています。 -Next, we’ll use our struct definition and create one `Node` instance named -`leaf` with the value 3 and no children, and another instance named `branch` -with the value 5 and `leaf` as one of its children, as shown in Listing 15-27: + + + -Filename: src/main.rs +次にこの構造体定義を使って値3と子供なしの`leaf`という1つの`Node`インスタンスと、 +値5と`leaf`を子要素の一つとして持つ`branch`という別のインスタンスを作成します。 +リスト15-27のようにね: + + + +ファイル名: src/main.rs ```rust # use std::rc::Rc; @@ -260,35 +373,58 @@ fn main() { } ``` -Listing 15-27: Creating a `leaf` node with no children -and a `branch` node with `leaf` as one of its children + + + +リスト15-27: 子供なしの`leaf`ノードと`leaf`を子要素に持つ`branch`ノードを作る + + + + + + + + +`leaf`の`Rc`をクローンし、`branch`に格納しているので、`leaf`の`Node`は`leaf`と`branch`という2つの所有者を持つことになります。 +`branch.children`を通して`branch`から`leaf`へ辿ることはできるものの、`leaf`から`branch`へ辿る方法はありません。 +理由は、`leaf`には`branch`への参照がなく、関係していることを知らないからです。`leaf`に`branch`が親であることを知ってほしいです。 +次はそれを行います。 + + + +#### 子供から親に参照を追加する -We clone the `Rc` in `leaf` and store that in `branch`, meaning the -`Node` in `leaf` now has two owners: `leaf` and `branch`. We can get from -`branch` to `leaf` through `branch.children`, but there’s no way to get from -`leaf` to `branch`. The reason is that `leaf` has no reference to `branch` and -doesn’t know they’re related. We want `leaf` to know that `branch` is its -parent. We’ll do that next. + + + + + + -#### Adding a Reference from a Child to Its Parent +子供に親の存在を気付かせるために、`Node`構造体定義に`parent`フィールドを追加する必要があります。 +`parent`の型を決める際に困ったことになります。`Rc`を含むことができないのはわかります。 +そうしたら、`leaf.parent`が`branch`を指し、`branch.children`が`leaf`を指して循環参照になり、 +`strong_count`値が絶対に0にならなくなってしまうからです。 -To make the child node aware of its parent, we need to add a `parent` field to -our `Node` struct definition. The trouble is in deciding what the type of -`parent` should be. We know it can’t contain an `Rc` because that would -create a reference cycle with `leaf.parent` pointing to `branch` and -`branch.children` pointing to `leaf`, which would cause their `strong_count` -values to never be 0. + + + + -Thinking about the relationships another way, a parent node should own its -children: if a parent node is dropped, its child nodes should be dropped as -well. However, a child should not own its parent: if we drop a child node, the -parent should still exist. This is a case for weak references! +この関係を別の方法で捉えると、親ノードは子供を所有すべきです: 親ノードがドロップされたら、 +子ノードもドロップされるべきなのです。ですが、子供は親を所有するべきではありません: +子ノードをドロップしても、親はまだ存在するべきです。弱い参照を使う場面ですね! -So instead of `Rc`, we’ll make the type of `parent` use `Weak`, -specifically a `RefCell>`. Now our `Node` struct definition looks -like this: + + + -Filename: src/main.rs +従って、`Rc`の代わりに`parent`の型を`Weak`を使ったもの、具体的には`RefCell>`にします。 +さあ、`Node`構造体定義はこんな見た目になりました: + + + +ファイル名: src/main.rs ```rust use std::rc::{Rc, Weak}; @@ -302,11 +438,16 @@ struct Node { } ``` -Now a node will be able to refer to its parent node but doesn’t own its parent. -In Listing 15-28, we update `main` to use this new definition so the `leaf` -node will have a way to refer to its parent, `branch`: + + + + +これで、ノードは親ノードを参照できるものの、所有はしないでしょう。リスト15-28で、 +`leaf`ノードが親の`branch`を参照できるよう、この新しい定義を使用するように`main`を更新します: -Filename: src/main.rs + + +ファイル名: src/main.rs ```rust # use std::rc::{Rc, Weak}; @@ -340,34 +481,52 @@ fn main() { } ``` -Listing 15-28: A `leaf` node with a `Weak` reference to -its parent node `branch` + + + +リスト15-28: 親ノードの`branch`への`Weak`参照のある`leaf`ノード + + + + -Creating the `leaf` node looks similar to how creating the `leaf` node looked -in Listing 15-27 with the exception of the `parent` field: `leaf` starts out -without a parent, so we create a new, empty `Weak` reference instance. +`leaf`ノードを作成することは、`parent`フィールドの例外を除いてリスト15-27での`leaf`ノードの作成法に似ています: +`leaf`は親なしで始まるので、新しく空の`Weak`参照インスタンスを作ります。 -At this point, when we try to get a reference to the parent of `leaf` by using -the `upgrade` method, we get a `None` value. We see this in the output from the -first `println!` statement: + + + + +この時点で`upgrade`メソッドを使用して`leaf`の親への参照を得ようとすると、`None`値になります。 +このことは、最初の`println!`文の出力でわかります: ```text leaf parent = None ``` -When we create the `branch` node, it will also have a new `Weak` -reference in the `parent` field, because `branch` doesn’t have a parent node. -We still have `leaf` as one of the children of `branch`. Once we have the -`Node` instance in `branch`, we can modify `leaf` to give it a `Weak` -reference to its parent. We use the `borrow_mut` method on the -`RefCell>` in the `parent` field of `leaf`, and then we use the -`Rc::downgrade` function to create a `Weak` reference to `branch` from -the `Rc` in `branch.` - -When we print the parent of `leaf` again, this time we’ll get a `Some` variant -holding `branch`: now `leaf` can access its parent! When we print `leaf`, we -also avoid the cycle that eventually ended in a stack overflow like we had in -Listing 15-26: the `Weak` references are printed as `(Weak)`: + + + + + + + + + +`branch`ノードを作る際、`branch`には親ノードがないので、こちらも`parent`フィールドには新しい`Weak`参照が入ります。 +それでも、`leaf`は`branch`の子供になっています。一旦`branch`に`Node`インスタンスができたら、 +`leaf`を変更して親への`Weak`参照を与えることができます。`leaf`の`parent`フィールドには、 +`RefCell>`の`borrow_mut`メソッドを使用して、それから`Rc::downgrade`関数を使用して、 +`branch`の`Rc`から`branch`への`Weak`参照を作ります。 + + + + + + +再度`leaf`の親を出力すると、今度は`branch`を保持する`Some`列挙子が得られます: これで`leaf`が親にアクセスできるようになったのです! +`leaf`を出力すると、リスト15-26で起こっていたような最終的にスタックオーバーフローに行き着く循環を避けることもできます: +`Weak`参照は、`(Weak)`と出力されます: ```text leaf parent = Some(Node { value: 5, parent: RefCell { value: (Weak) }, @@ -375,19 +534,31 @@ children: RefCell { value: [Node { value: 3, parent: RefCell { value: (Weak) }, children: RefCell { value: [] } }] } }) ``` -The lack of infinite output indicates that this code didn’t create a reference -cycle. We can also tell this by looking at the values we get from calling -`Rc::strong_count` and `Rc::weak_count`. + + + + +無限の出力が欠けているということは、このコードは循環参照しないことを示唆します。 +このことは、`Rc::strong_count`と`Rc::weak_count`を呼び出すことで得られる値を見てもわかります。 + + -#### Visualizing Changes to `strong_count` and `weak_count` +#### `strong_count`と`weak_count`への変更を可視化する -Let’s look at how the `strong_count` and `weak_count` values of the `Rc` -instances change by creating a new inner scope and moving the creation of -`branch` into that scope. By doing so, we can see what happens when `branch` is -created and then dropped when it goes out of scope. The modifications are shown -in Listing 15-29: + + + + + -Filename: src/main.rs +新しい内部スコープを作り、`branch`の作成をそのスコープに移動することで、 +`Rc`インスタンスの`strong_count`と`weak_count`値がどう変化するかを眺めましょう。 +そうすることで、`branch`が作成され、それからスコープを抜けてドロップされる時に起こることが確認できます。 +変更は、リスト15-29に示してあります: + + + +ファイル名: src/main.rs ```rust # use std::rc::{Rc, Weak}; @@ -444,53 +615,93 @@ fn main() { } ``` -Listing 15-29: Creating `branch` in an inner scope and -examining strong and weak reference counts - -After `leaf` is created, its `Rc` has a strong count of 1 and a weak -count of 0. In the inner scope, we create `branch` and associate it with -`leaf`, at which point when we print the counts, the `Rc` in `branch` -will have a strong count of 1 and a weak count of 1 (for `leaf.parent` pointing -to `branch` with a `Weak`). When we print the counts in `leaf`, we’ll see -it will have a strong count of 2, because `branch` now has a clone of the -`Rc` of `leaf` stored in `branch.children` but will still have a weak -count of 0. - -When the inner scope ends, `branch` goes out of scope and the strong count of -the `Rc` decreases to 0, so its `Node` is dropped. The weak count of 1 -from `leaf.parent` has no bearing on whether or not `Node` is dropped, so we -don’t get any memory leaks! - -If we try to access the parent of `leaf` after the end of the scope, we’ll get -`None` again. At the end of the program, the `Rc` in `leaf` has a strong -count of 1 and a weak count of 0, because the variable `leaf` is now the only -reference to the `Rc` again. - -All of the logic that manages the counts and value dropping is built into -`Rc` and `Weak` and their implementations of the `Drop` trait. By -specifying that the relationship from a child to its parent should be a -`Weak` reference in the definition of `Node`, we’re able to have parent -nodes point to child nodes and vice versa without creating a reference cycle -and memory leaks. - -## Summary - -This chapter covered how to use smart pointers to make different guarantees and -trade-offs than those Rust makes by default with regular references. The -`Box` type has a known size and points to data allocated on the heap. The -`Rc` type keeps track of the number of references to data on the heap, so -that data can have multiple owners. The `RefCell` type with its interior -mutability gives us a type that we can use when we need an immutable type but -need to change an inner value of that type; it also enforces the borrowing -rules at runtime instead of at compile time. - -Also discussed were the `Deref` and `Drop` traits that enable a lot of the -functionality of smart pointers. We explored reference cycles that can cause -memory leaks and how to prevent them using `Weak`. - -If this chapter has piqued your interest and you want to implement your own -smart pointers, check out “The Rustonomicon” at -*https://doc.rust-lang.org/stable/nomicon/* for more useful information. - -Next, we’ll talk about concurrency in Rust. You’ll even learn about a few new -smart pointers. + + + +リスト15-29: 内側のスコープで`branch`を作成し、強弱参照カウントを調査する + + + + + + + + + + + + +`leaf`作成後、その`Rc`の強カウントは1、弱カウントは0になります。内側のスコープで`branch`を作成し、 +`leaf`に紐付け、この時点でカウントを出力すると、`branch`の`Rc`の強カウントは1、 +弱カウントも1になります(`leaf.parent`が`Weak`で`branch`を指しているため)。 +`leaf`のカウントを出力すると、強カウントが2になっていることがわかります。`branch`が今は、 +`branch.children`に格納された`leaf`の`Rc`のクローンを持っているからですが、 +それでも弱カウントは0でしょう。 + + + + + + +内側のスコープが終わると、`branch`はスコープを抜け、`Rc`の強カウントは0に減るので、 +この`Node`はドロップされます。`leaf.parent`からの弱カウント1は、`Node`がドロップされるか否かには関係ないので、 +メモリリークはしないのです! + + + + + + +このスコープの終端以後に`leaf`の親にアクセスしようとしたら、再び`None`が得られます。 +プログラムの終端で`leaf`の`Rc`の強カウントは1、弱カウントは0です。 +変数`leaf`が今では`Rc`への唯一の参照に再度なったからです。 + + + + + + + + +カウントや値のドロップを管理するロジックは全て、`Rc`や`Weak`とその`Drop`トレイトの実装に組み込まれています。 +`Node`の定義で子供から親への関係は`Weak`参照になるべきと指定することで、 +循環参照やメモリリークを引き起こさずに親ノードに子ノードを参照させたり、その逆を行うことができます。 + + + +## まとめ + + + + + + + + + + +この章は、スマートポインタを使用してRustが規定で普通の参照に対して行うのと異なる保証や代償を行う方法を講義しました。 +`Box`型は、既知のサイズで、ヒープに確保されたデータを指します。`Rc`型は、ヒープのデータへの参照の数を追跡するので、 +データは複数の所有者を保有できます。内部可変性のある`RefCell`型は、不変型が必要だけれども、 +その型の中の値を変更する必要がある時に使用できる型を与えてくれます; また、コンパイル時ではなく実行時に借用ルールを強制します。 + + + + + +スマートポインタの多くの機能を可能にする`Deref`と`Drop`トレイトについても議論しましたね。 +メモリリークを引き起こす循環参照と`Weak`でそれを回避する方法も探求しました。 + + + + + + + +この章で興味をそそられ、独自のスマートポインタを実装したくなったら、もっと役に立つ情報を求めて、 +*https://doc.rust-lang.org/stable/nomicon/*の"The Rustonomicon"をチェックしてください。 + + + + +次は、Rustでの非同期処理について語ります。もういくつか新しいスマートポインタについてさえも学ぶでしょう。 From e4ebd4b639d3ffb5dd5601a79b42995c0fc95a96 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 23 Feb 2018 20:23:57 +0900 Subject: [PATCH 115/428] Fix a mistake in the chapter 15-0 --- second-edition/src/ch15-00-smart-pointers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/second-edition/src/ch15-00-smart-pointers.md b/second-edition/src/ch15-00-smart-pointers.md index b369fca0e..a3f2ef448 100644 --- a/second-edition/src/ch15-00-smart-pointers.md +++ b/second-edition/src/ch15-00-smart-pointers.md @@ -72,7 +72,7 @@ Rustにおいて、最もありふれた種類のポインタは、参照であ -スマートポインタパターンがRustにおいてよく使われる一般的なデザインパターンだとして、この章では、全ての既存のスマートポインタを講義します。 +スマートポインタパターンがRustにおいてよく使われる一般的なデザインパターンだとして、この章では、全ての既存のスマートポインタを講義しません。 多くのライブラリに独自のスマートポインタがあり、自分だけのスマートポインタを書くことさえできます。 標準ライブラリの最もありふれたスマートポインタを講義します: From b57fa272f6aff35af6a3deee4b9d24d9d79dfe02 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 23 Feb 2018 22:20:34 +0900 Subject: [PATCH 116/428] Revise some texts in the chapter 15-2 --- second-edition/src/ch15-02-deref.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/second-edition/src/ch15-02-deref.md b/second-edition/src/ch15-02-deref.md index 8e05c3d33..eb51d72bf 100644 --- a/second-edition/src/ch15-02-deref.md +++ b/second-edition/src/ch15-02-deref.md @@ -319,7 +319,7 @@ impl Deref for MyBox { 所有権システムのためです。`deref`メソッドが値への参照ではなく、値を直接返したら、値は`self`から外にムーブされてしまいます。 今回の場合や、参照外し演算子を使用する多くの場合には`MyBox`の中の値の所有権を奪いたくはありません。 - + @@ -355,7 +355,7 @@ impl Deref for MyBox { 参照外し型強制は、関数やメソッド呼び出しを書くプログラマが`&`や`*`で多くの明示的な参照や参照外しとして追加する必要がないように、 -Rustに追加されました。また、参照外し型強制のおかげで参照あるいはスマートポインタで動くコードをもっと書くことができます。 +Rustに追加されました。また、参照外し型強制のおかげで参照あるいはスマートポインタのどちらかで動くコードをもっと書くことができます。 From a6238c63a818b7627f5cb1f0c542cd5b0f50dd89 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Fri, 23 Feb 2018 22:56:41 +0900 Subject: [PATCH 117/428] Fix some mistakes and make improvements in the chapters 15-3 and 15-4 --- second-edition/src/ch15-03-drop.md | 7 +++++-- second-edition/src/ch15-04-rc.md | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/second-edition/src/ch15-03-drop.md b/second-edition/src/ch15-03-drop.md index 29ffa596e..fb87c0c8d 100644 --- a/second-edition/src/ch15-03-drop.md +++ b/second-edition/src/ch15-03-drop.md @@ -191,7 +191,7 @@ error[E0040]: explicit use of destructor method エラーメッセージは*デストラクタ*という専門用語を使っていて、これは、 インスタンスを片付ける関数の一般的なプログラミング専門用語です。*デストラクタ*は、 インスタンスを生成する*コンストラクタ*に類似しています。Rustの`drop`関数は、 -一つの特定のデストラクタです。 +1種の特定のデストラクタです。 @@ -236,6 +236,7 @@ fn main() { let c = CustomSmartPointer { data: String::from("some data") }; println!("CustomSmartPointer created."); drop(c); + // CustomSmartPointerはmainが終わる前にドロップされた println!("CustomSmartPointer dropped before the end of main."); } ``` @@ -264,6 +265,8 @@ CustomSmartPointer dropped before the end of main. `CustomSmartPointer created.`と`CustomSmartPointer dropped before the end of main`テキストの間に出力されるので、 `drop`メソッドのコードがその時点で呼び出されて`c`をドロップしたことを示しています。 + + @@ -278,7 +281,7 @@ CustomSmartPointer dropped before the end of main. -コンパイルエラーを引き起こすので、まだ使用中の値を間違って片付けてしまう心配もしなくて済みます。 +コンパイルエラーを引き起こすので、まだ使用中の値を間違って片付けてしまう心配もしなくて済みます: 参照が常に有効であると確認してくれる所有権システムが、値が最早使用されなくなった時に`drop`が1回だけ呼ばれることを保証してくれるのです。 diff --git a/second-edition/src/ch15-04-rc.md b/second-edition/src/ch15-04-rc.md index 163725483..bf544c598 100644 --- a/second-edition/src/ch15-04-rc.md +++ b/second-edition/src/ch15-04-rc.md @@ -32,7 +32,7 @@ `Rc`を家族部屋のテレビと想像してください。1人がテレビを見に部屋に入ったら、テレビをつけます。 他の人も部屋に入ってテレビを観ることができます。最後の人が部屋を離れる時、 -もう使用されてないので、テレビを消します。他の人がまだ観ているのに誰かがテレビを消したら、 +もう使用されていないので、テレビを消します。他の人がまだ観ているのに誰かがテレビを消したら、 残りのテレビ視聴者が騒ぐでしょう! @@ -324,7 +324,7 @@ count after c goes out of scope = 2 -不変参照経由で、`Rc`は読み取り専用でプログラムの複数箇所間でデータを共有させてくれます。 +不変参照経由で、`Rc`は読み取り専用にプログラムの複数箇所間でデータを共有させてくれます。 `Rc`が複数の可変参照を存在させることも許可してくれたら、第4章で議論した借用ルールの1つを侵害する恐れがあります: 同じ場所への複数の可変借用は、データ競合や矛盾を引き起こすことがあるのです。しかし、 データを可変化する能力はとても有用です!次の節では、内部可変性パターンと、 From 82ef13d9a393dc6e9c7bf573bf2cfc00cc2f3e21 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sat, 24 Feb 2018 19:59:21 +0900 Subject: [PATCH 118/428] Make some improvements in the translated texts in the chapters 15-5 and 15-6 --- second-edition/src/ch15-05-interior-mutability.md | 14 ++++++++------ second-edition/src/ch15-06-reference-cycles.md | 14 +++++++++----- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/second-edition/src/ch15-05-interior-mutability.md b/second-edition/src/ch15-05-interior-mutability.md index b845c9c0d..20b260a12 100644 --- a/second-edition/src/ch15-05-interior-mutability.md +++ b/second-edition/src/ch15-05-interior-mutability.md @@ -39,7 +39,7 @@ -* いかなる時も以下のどちらかが可能になる: 1つの可変参照、あるいはいくつもの不変参照。 +* いかなる時も以下の両方ではなく、*どちらか*が可能になる: 1つの可変参照、あるいはいくつもの不変参照。 * 参照は常に有効でなければならない。 @@ -76,7 +76,7 @@ Rustコンパイラのような静的な分析は、本質的に保守的です 最も有名な例は、停止性問題であり、この本の範疇を超えていますが、調査するのに面白い話題です。 > `編注`: 停止性問題とは、あるチューリング機械(≒コンピュータプログラム・アルゴリズム)が -> そのテープのある初期状態(≒入力)に対し、有限時間で停止するか、という問題。 +> そのテープのある初期状態(≒入力)に対し、有限時間で停止するか、という問題。 > Wikipediaより抜粋 @@ -222,7 +222,7 @@ Rustには、他の言語でいうオブジェクトは存在せず、また、 作成するライブラリは、値がどれくらい最大に近いかと、いつどんなメッセージになるべきかを追いかける機能を提供するだけです。 このライブラリを使用するアプリケーションは、メッセージを送信する機構を提供すると期待されるでしょう: -アプリケーションは、アプリケーションにメッセージを置いたり、メールを送ったり、テキストをメッセージを送るなどできるでしょう。 +アプリケーションは、アプリケーションにメッセージを置いたり、メールを送ったり、テキストメッセージを送るなどできるでしょう。 ライブラリはその詳細を知る必要はありません。必要なのは、提供する`Messenger`と呼ばれるトレイトを実装している何かなのです。 リスト15-20は、ライブラリのコードを示しています: @@ -509,7 +509,7 @@ mod tests { `RefCell`は、現在活動中の`Ref`と`RefMut`スマートポインタの数を追いかけます。 `borrow`を呼び出す度に、`RefCell`は活動中の不変参照の数を増やします。`Ref`の値がスコープを抜けたら、 不変参照の数は1下がります。コンパイル時の借用ルールと全く同じように、`RefCell`はいかなる時も、 -多くの不変借用または1つの可変借用を持たせてくれるのです。 +複数の不変借用または1つの可変借用を持たせてくれるのです。 @@ -519,7 +519,7 @@ mod tests { これらの規則を侵害しようとすれば、参照のようにコンパイルエラーになるのではなく、 -`RefCell`の実装は実行時に`panic!`するでしょう。リスト15-23はリスト15-22の`send`実装に対する変更を示しています。 +`RefCell`の実装は実行時に`panic!`するでしょう。リスト15-23は、リスト15-22の`send`実装に対する変更を示しています。 同じスコープで2つの可変借用が活動するようわざと生成し、`RefCell`が実行時にこれをすることを阻止してくれるところを具体化しています。 @@ -551,13 +551,15 @@ impl Messenger for MockMessenger { `borrow_mut`から返ってきた`RefMut`スマートポインタに対して変数`one_borrow`を生成しています。 そして、同様にして変数`two_borrow`にも別の可変借用を生成しています。これにより同じスコープで2つの可変参照ができ、 -これは許可されないことです。このテストをライブラリ用に走らせると、リスト15-23のコードはエラーなくコンパイルできますが、 +これは許可されないことです。このテストを自分のライブラリ用に走らせると、リスト15-23のコードはエラーなくコンパイルできますが、 テストは失敗するでしょう: ```text ---- tests::it_sends_an_over_75_percent_warning_message stdout ---- thread 'tests::it_sends_an_over_75_percent_warning_message' panicked at 'already borrowed: BorrowMutError', src/libcore/result.rs:906:4 + (スレッド'tests::it_sends_an_over_75_percent_warning_message'は、 + 'すでに借用されています: BorrowMutError', src/libcore/result.rs:906:4でパニックしました) note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` diff --git a/second-edition/src/ch15-06-reference-cycles.md b/second-edition/src/ch15-06-reference-cycles.md index 11f1b45be..362cb2139 100644 --- a/second-edition/src/ch15-06-reference-cycles.md +++ b/second-edition/src/ch15-06-reference-cycles.md @@ -11,7 +11,7 @@ -Rustのメモリ安全保証により誤って絶対に片付けられることのないメモリ(*メモリリーク*として知られています)を生成してしまうことが困難にはなりますが、 +Rustのメモリ安全保証により誤って絶対に片付けられることのないメモリ(*メモリリーク*として知られています)を生成してしまうことが*困難*にはなりますが、 不可能にはなりません。コンパイル時にデータ競合を防ぐのと同じようにメモリリークを完全に回避することは、 Rustの保証の一つではなく、メモリリークはRustにおいてはメモリ安全であることを意味します。 Rustでは、`Rc`と`RefCell`を使用してメモリリークを許可するとわかります: @@ -158,8 +158,8 @@ fn main() { -`a`が`Nil`ではなく`b`を指すように変更して、循環にさせます。`tail`メソッドを使用して、 -`a`の`RefCell>`への参照を得ることでそうして、この参照は変数`link`に配置します。 +`a`が`Nil`ではなく`b`を指すように変更して、循環させます。`tail`メソッドを使用して、 +`a`の`RefCell>`への参照を得ることで循環させて、この参照は変数`link`に配置します。 それから`RefCell>`の`borrow_mut`メソッドを使用して中の値を`Nil`値を持つ`Rc`から、 `b`の`Rc`に変更します。 @@ -231,7 +231,7 @@ a rc count after changing a = 2 循環参照は簡単にできることではありませんが、不可能というわけでもありません。 -`Rc`値を含む`RefCell`値があるなどの内部可変性と参照カウントのある型がネストしてコンビネーションしていたら、 +`Rc`値を含む`RefCell`値があるなどの内部可変性と参照カウントのある型がネストして組み合わさっていたら、 循環していないことを保証しなければなりません; コンパイラがそれを捕捉することを信頼できないのです。 循環参照をするのは、自動化テストやコードレビューなどの他のソフトウェア開発手段を使用して最小化すべきプログラム上のロジックバグでしょう。 @@ -467,6 +467,7 @@ fn main() { children: RefCell::new(vec![]), }); + // leafの親 = {:?} println!("leaf parent = {:?}", leaf.parent.borrow().upgrade()); let branch = Rc::new(Node { @@ -578,6 +579,7 @@ fn main() { children: RefCell::new(vec![]), }); + // leafのstrong_count = {}, weak_count = {} println!( "leaf strong = {}, weak = {}", Rc::strong_count(&leaf), @@ -593,6 +595,7 @@ fn main() { *leaf.parent.borrow_mut() = Rc::downgrade(&branch); + // branchのstrong_count = {}, weak_count = {} println!( "branch strong = {}, weak = {}", Rc::strong_count(&branch), @@ -620,7 +623,8 @@ fn main() { リスト15-29: 内側のスコープで`branch`を作成し、強弱参照カウントを調査する - + + From cf8df507aebc411f03de0040f977bc6cc33a1b10 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 11 Mar 2018 20:01:06 +0900 Subject: [PATCH 119/428] Fix the conflicts spread across Chapter 2, 3, 4, 12 and 13 --- second-edition/src/SUMMARY.md | 13 +- .../src/ch02-00-guessing-game-tutorial.md | 981 +++++------------- .../ch03-00-common-programming-concepts.md | 28 +- .../src/ch03-01-variables-and-mutability.md | 282 ++--- second-edition/src/ch03-02-data-types.md | 356 ++----- .../src/ch03-03-how-functions-work.md | 150 +-- second-edition/src/ch03-05-control-flow.md | 262 ++--- .../src/ch04-00-understanding-ownership.md | 14 +- .../src/ch04-01-what-is-ownership.md | 579 +++-------- .../src/ch04-02-references-and-borrowing.md | 188 +--- second-edition/src/ch04-03-slices.md | 257 ++--- ...2-04-testing-the-librarys-functionality.md | 12 +- second-edition/src/ch13-02-iterators.md | 10 +- 13 files changed, 826 insertions(+), 2306 deletions(-) diff --git a/second-edition/src/SUMMARY.md b/second-edition/src/SUMMARY.md index 2cebd7a30..6049dc7fb 100644 --- a/second-edition/src/SUMMARY.md +++ b/second-edition/src/SUMMARY.md @@ -185,10 +185,15 @@ - [状態共有](ch16-03-shared-state.md) - [さらなる非同期処理: `Sync`と`Send`](ch16-04-extensible-concurrency-sync-and-send.md) -- [Is Rust an Object-Oriented Programming Language?](ch17-00-oop.md) - - [What Does Object-Oriented Mean?](ch17-01-what-is-oo.md) - - [Trait Objects for Using Values of Different Types](ch17-02-trait-objects.md) - - [Object-Oriented Design Pattern Implementations](ch17-03-oo-design-patterns.md) + + + + + +- [Rustはオブジェクト指向プログラミング言語なの?](ch17-00-oop.md) + - [オブジェクト指向って?](ch17-01-what-is-oo.md) + - [トレイトオブジェクトで異なる型の値を使用する](ch17-02-trait-objects.md) + - [オブジェクト指向デザインパターンの実装](ch17-03-oo-design-patterns.md) diff --git a/second-edition/src/ch02-00-guessing-game-tutorial.md b/second-edition/src/ch02-00-guessing-game-tutorial.md index b0053d100..7153ddc2f 100644 --- a/second-edition/src/ch02-00-guessing-game-tutorial.md +++ b/second-edition/src/ch02-00-guessing-game-tutorial.md @@ -1,73 +1,49 @@ -<<<<<<< HEAD - -======= -# Programming a Guessing Game ->>>>>>> fork_master_master + -# 数当てゲーム +# 数当てゲームをプログラムする -<<<<<<< HEAD -======= -We’ll implement a classic beginner programming problem: a guessing game. Here’s -how it works: the program will generate a random integer between 1 and 100. It -will then prompt the player to enter a guess. After a guess is entered, the -program will indicate whether the guess is too low or too high. If the guess is -correct, the game will print a congratulatory message and exit. ->>>>>>> fork_master_master 実物のプロジェクトに一緒に取り組むことで、Rustの世界へ飛び込みましょう! この章では、実際のプログラム内で使用しながらいくつかの一般的なRustの概念に触れます。 let文、match式、メソッド、関連関数、外部クレートの使用などについて学ぶでしょう! 後ほどの章でこれらの概念について深く知ることになります。この章では、基礎部分だけにしましょう。 -<<<<<<< HEAD - - - + + + 古典的な初心者向けのプログラミング問題を実装してみましょう: 数当てゲームです。 これは以下のように動作します: プログラムは1から100までの乱数整数を生成します。 そしてプレーヤーに予想を入力するよう促します。予想を入力したら、プログラムは、 -その予想が少なすぎたか多すぎたかを出力します。予想が当たっていれば、ゲームが祝福してくれ、 -そのまま終了します。 +その予想が少なすぎたか多すぎたかを出力します。予想が当たっていれば、ゲームは祝福メッセージを表示し、 +終了します。 ## 新規プロジェクトの立ち上げ - + 新規プロジェクトを立ち上げるには、第1章で作成した*projects*ディレクトリに行き、 Cargoを使って以下のように新規プロジェクトを作成します。 -======= -To set up a new project, go to the *projects* directory that you created in -Chapter 1 and make a new project using Cargo, like so: ->>>>>>> fork_master_master ```text $ cargo new guessing_game --bin $ cd guessing_game ``` -<<<<<<< HEAD - + -======= -The first command, `cargo new`, takes the name of the project (`guessing_game`) -as the first argument. The `--bin` flag tells Cargo to make a binary project, -like the one in Chapter 1. The second command changes to the new project’s -directory. ->>>>>>> fork_master_master 最初のコマンド`cargo new`は、プロジェクト名を第1引数に取ります(`guessing_game`ですね)。 `--bin`というフラグは、Cargoにバイナリ生成プロジェクトを作成させます。第1章のものと似ていますね。 @@ -126,14 +102,12 @@ $ cargo run Hello, world! ``` -<<<<<<< HEAD - - + + `run`コマンドは、プロジェクトに迅速に段階を踏んで取り掛かる必要がある場合に有用であり、 -このゲームはその類のプロジェクトになります。 -つまり、次のステップに進む前に各段階を急速にテストする必要があるわけです。 +次のステップに進む前に各段階を急速にテストして、このゲームではそれを行います。 @@ -142,28 +116,17 @@ Hello, world! ## 予想を処理する -======= -The `run` command comes in handy when you need to rapidly iterate on a project, -as we’ll do in this game, quickly testing each iteration before moving on to -the next one. ->>>>>>> fork_master_master - - - + + + + -プログラムの最初のパートは、ユーザに入力を求め、その入力を処理し、予期した形式になっていることを確認します。 +数当てプログラムの最初の部分は、ユーザに入力を求め、その入力を処理し、予期した形式になっていることを確認します。 手始めにプレーヤーが予想を入力できるようにしましょう。 リスト2-1のコードを*src/main.rs*に入力してください。 -<<<<<<< HEAD -======= -The first part of the guessing game program will ask for user input, process -that input, and check that the input is in the expected form. To start, we’ll -allow the player to input a guess. Enter the code in Listing 2-1 into -*src/main.rs*. ->>>>>>> fork_master_master ファイル名: src/main.rs @@ -184,9 +147,8 @@ fn main() { } ``` -<<<<<<< HEAD - - + + リスト2-1: ユーザに予想を入力してもらい、それを出力するコード @@ -194,45 +156,28 @@ fn main() { > ソースコードのコメント中以外に日本語文字があるとコンパイルに失敗することがあるそうなので、文字列の英語は、コメントに和訳を載せます。 > また、重複する内容の場合には、最初の1回だけ掲載するようにします。 - + -このコードには、たくさんの情報が詰め込まれてますね。なので、少しずつ噛み砕いていきましょう。 +このコードには、たくさんの情報が詰め込まれてますね。なので、行ごとに見ていきましょう。 ユーザ入力を受け付け、結果を出力するためには、`io`(入/出力)ライブラリをスコープに導入する必要があります。 `io`ライブラリは、標準ライブラリ(`std`として知られています)に存在します: -======= -Listing 2-1: Code that gets a guess from the user and -prints it - -This code contains a lot of information, so let’s go over it line by line. To -obtain user input and then print the result as output, we need to bring the -`io` (input/output) library into scope. The `io` library comes from the -standard library (which is known as `std`): ->>>>>>> fork_master_master ```rust,ignore use std::io; ``` -<<<<<<< HEAD - + デフォルトでは、[*prelude*][prelude]に存在するいくつかの型のみ使えます。 もし、使用したい型がpreludeにない場合は、`use`文で明示的にその型をスコープに導入する必要があります。 -`std::io`ライブラリを使用することで、ユーザ入力を受け付けるなどの実用的な`入出力`関連の機能を使用することができます。 -======= -By default, Rust brings only a few types into the scope of every program in -[the *prelude*][prelude]. If a type you want to use isn’t in the -prelude, you have to bring that type into scope explicitly with a `use` -statement. Using the `std::io` library provides you with a number of useful -features, including the ability to accept user input. ->>>>>>> fork_master_master +`std::io`ライブラリを使用することで、ユーザ入力を受け付ける能力などの実用的な機能の多くを使用することができます。 [prelude]: ../../std/prelude/index.html @@ -245,15 +190,10 @@ features, including the ability to accept user input. fn main() { ``` -<<<<<<< HEAD - - + + -`fn`構文が関数を新しく宣言し、`()`は引数がないことを示し、`{`が関数本体のスタート地点になります。 -======= -The `fn` syntax declares a new function, the parentheses, `()`, indicate there -are no parameters, and the curly bracket, `{`, starts the body of the function. ->>>>>>> fork_master_master +`fn`構文が関数を新しく宣言し、かっこの`()`は引数がないことを示し、波括弧の`{`が関数本体のスタート地点になります。 @@ -283,57 +223,41 @@ println!("Please input your guess."); let mut guess = String::new(); ``` -<<<<<<< HEAD - - + + さあ、プログラムが面白くなってきましたね。このたった1行でいろんなことが起きています。 これが`let`文であることに注目してください。これを使用して*変数*を生成しています。 こちらは、別の例です: -======= -Now the program is getting interesting! There’s a lot going on in this little -line. Notice that this is a `let` statement, which is used to create a -*variable*. Here’s another example: ->>>>>>> fork_master_master ```rust,ignore let foo = bar; ``` -<<<<<<< HEAD - - - + + + + + この行では、`foo`という名前の新しい変数を作成し、`bar`の値に束縛しています。 -Rustでは、変数は標準で不変(immutable)です。以下の例には、 +Rustでは、変数は標準で不変(immutable)です。この概念について詳しくは、 +第3章の「変数と可変性」節で議論します。以下の例には、 変数名の前に`mut`修飾子をつけて変数を可変にする方法が示されています: -======= -This line creates a new variable named `foo` and bind it to the value `bar`. In -Rust, variables are immutable by default. We’ll be discussing this concept in -detail in the “Variables and Mutability” section in Chapter 3. The following -example shows how to use `mut` before the variable name to make a variable -mutable: ->>>>>>> fork_master_master ```rust,ignore let foo = 5; // immutable let mut bar = 5; // mutable ``` -<<<<<<< HEAD - -======= -> Note: The `//` syntax starts a comment that continues until the end of the -> line. Rust ignores everything in comments, which are discussed in more detail -> in Chapter 3. ->>>>>>> fork_master_master + + > 注釈: `//`という記法は、行末まで続くコメントを記述します。 -> コンパイラは、コメントを一切無視します。 +> コンパイラは、コメントを一切無視し、これについても第3章で詳しく議論します。 @@ -359,18 +283,12 @@ let mut bar = 5; // mutable 関連関数とは、`String`型の特定のオブジェクトよりも型(この場合は`String`)に対して 実装された関数のことであり、*静的メソッド*と呼ばれる言語もあります。 - + -<<<<<<< HEAD -この`new`関数は、新しく空の`String`オブジェクトを生成します。`new`関数は、いろんな型に見られます。 +この`new`関数は、新しく空の文字列を生成します。`new`関数は、いろんな型に見られます。 なぜなら、何らかの新規値を生成する関数にとってありふれた名前だからです。 -======= -This `new` function creates a new, empty string. You’ll find a `new` function -on many types, because it’s a common name for a function that makes a new value -of some kind. ->>>>>>> fork_master_master @@ -390,17 +308,10 @@ io::stdin().read_line(&mut guess) .expect("Failed to read line"); ``` -<<<<<<< HEAD - + -======= -If we hadn’t listed the `use std::io` line at the beginning of the program, we -could have written this function call as `std::io::stdin`. The `stdin` function -returns an instance of [`std::io::Stdin`][iostdin], which is a -type that represents a handle to the standard input for your terminal. ->>>>>>> fork_master_master 仮に、プログラムの冒頭で`use std::io`としていなければ、この関数呼び出しは、`std::io::stdin`と記述していたでしょう。 この`stdin`関数は、 [`std::io::Stdin`][iostdin]オブジェクトを返し、この型は、 @@ -433,40 +344,29 @@ type that represents a handle to the standard input for your terminal. - - - + + + + `&`という記号は、この引数が*参照*であることを表し、これのおかげで、データを複数回メモリにコピーせずとも、 コードの複数箇所で同じデータにアクセスできるようになるわけです。参照は複雑な機能であり、 とても安全かつ簡単に参照を使うことができることは、Rustの主要な利点の一つでもあります。 そのような詳細を知らなくても、このプログラムを完成させることはできます: -第4章で参照について詳しく見ることにしましょう。現時点では、変数のように、参照も標準で不変であることを -知っておけばいいでしょう。故に、`&guess`と書くのではなく、`&mut guess`と書いて、可変にする必要があるのです。 +現時点では、変数のように、参照も標準で不変であることを知っておけばいいでしょう。 +故に、`&guess`と書くのではなく、`&mut guess`と書いて、可変にする必要があるのです。 +(第4章で参照について詳しく説明します) + + - - - +### `Result`型で失敗の可能性を扱う -まだ、この行は終わりではありませんよ。テキストでは1行ですが、コードとしての論理行としては、 + + + + +まだ、この行は終わりではありませんよ。ここまでに議論したのはテキストでは1行ですが、コードとしての論理行としては、 まだ所詮最初の部分でしかないのです。2番目の部分はこのメソッドです: -======= -The `&` indicates that this argument is a *reference*, which gives you a way to -let multiple parts of your code access one piece of data without needing to -copy that data into memory multiple times. References are a complex feature, -and one of Rust’s major advantages is how safe and easy it is to use -references. You don’t need to know a lot of those details to finish this -program. For now, all you need to know is that like variables, references are -immutable by default. Hence, you need to write `&mut guess` rather than -`&guess` to make it mutable. (Chapter 4 will explain references more -thoroughly.) - -### Handling Potential Failure with the `Result` Type - -We’re not quite done with this line of code. Although what we’ve discussed so -far is a single line of text, it’s only the first part of the single logical -line of code. The second part is this method: ->>>>>>> fork_master_master ```rust,ignore .expect("Failed to read line"); @@ -485,19 +385,14 @@ line of code. The second part is this method: io::stdin().read_line(&mut guess).expect("Failed to read line"); ``` -<<<<<<< HEAD - + -しかし、長い行は読みづらいものです。なので、分割しましょう。2回のメソッド呼び出しに、2行です。 +しかし、長い行は読みづらいものです。なので、分割しましょう: 2回のメソッド呼び出しに、2行です。 さて、この行が何をしているのかについて議論しましょうか。 - - -### `Result`型で、失敗する可能性について対処する - - - + + @@ -506,16 +401,6 @@ io::stdin().read_line(&mut guess).expect("Failed to read line"); 値も返します(今回は[`io::Result`][ioresult]です)。 Rustには`Result`と名のついた型が 標準ライブラリにたくさんあります: 汎用の[`Result`][result]の他、 `io::Result`などのサブモジュール用に特化したものまで。 -======= -However, one long line is difficult to read, so it’s best to divide it: two -lines for two method calls. Now let’s discuss what this line does. - -As mentioned earlier, `read_line` puts what the user types into the string -we’re passing it, but it also returns a value—in this case, an -[`io::Result`][ioresult]. Rust has a number of types named -`Result` in its standard library: a generic [`Result`][result] -as well as specific versions for submodules, such as `io::Result`. ->>>>>>> fork_master_master [ioresult]: ../../std/io/type.Result.html [result]: ../../std/result/enum.Result.html @@ -531,14 +416,13 @@ enumについては、第6章で詳しく解説します。 [enums]: ch06-00-enums.html -<<<<<<< HEAD - - - - + + + + -`Result`型に関しては、取りうる型の値(バリアント)は`Ok`か`Err`です。`Ok`は、処理が成功したことを表し、 -中に生成された値を保持します。`Err`は、処理が失敗したことを意味し、`Err`は、処理が失敗した過程や、 +`Result`型に関しては、取りうる型の値(バリアント)は`Ok`か`Err`です。`Ok`列挙子は、処理が成功したことを表し、 +中に生成された値を保持します。`Err`列挙子は、処理が失敗したことを意味し、`Err`は、処理が失敗した過程や、 理由などの情報を保有します。 @@ -564,31 +448,9 @@ enumについては、第6章で詳しく解説します。 [expect]: ../../std/result/enum.Result.html#method.expect - + もし、`expect`メソッドを呼び出さなかったら、コンパイルは通るものの、警告が出るでしょう: -======= -For `Result`, the variants are `Ok` or `Err`. The `Ok` variant indicates the -operation was successful, and inside `Ok` is the successfully generated value. -The `Err` variant means the operation failed, and `Err` contains information -about how or why the operation failed. - -The purpose of these `Result` types is to encode error-handling information. -Values of the `Result` type, like any type, have methods defined on them. An -instance of `io::Result` has an [`expect` method][expect] that -you can call. If this instance of `io::Result` is an `Err` value, `expect` will -cause the program to crash and display the message that you passed as an -argument to `expect`. If the `read_line` method returns an `Err`, it would -likely be the result of an error coming from the underlying operating system. -If this instance of `io::Result` is an `Ok` value, `expect` will take the -return value that `Ok` is holding and return just that value to you so you -can use it. In this case, that value is the number of bytes in what the user -entered into standard input. - -[expect]: ../../std/result/enum.Result.html#method.expect - -If you don’t call `expect`, the program will compile, but you’ll get a warning: ->>>>>>> fork_master_master ```text $ cargo build @@ -603,25 +465,19 @@ warning: unused `std::result::Result` which must be used = note: #[warn(unused_must_use)] on by default ``` -<<<<<<< HEAD - - - - -======= -Rust warns that you haven’t used the `Result` value returned from `read_line`, -indicating that the program hasn’t handled a possible error. - -The right way to suppress the warning is to actually write error handling, but -since you just want to crash this program when a problem occurs, you can use -`expect`. You’ll learn about recovering from errors in Chapter 9. ->>>>>>> fork_master_master + コンパイラは、私たちが`read_line`メソッドから返ってきた`Result`値を使用していないと警告してきており、 -これは、プログラムがエラーの可能性に対処していないことを示します。警告を抑制する正しい手段は、 -実際にエラー対処コードを書くことですが、今は、問題が起きた時にプロラグムをクラッシュさせたいので、 -`expect`を使用できるわけです。エラーから復旧する方法については、第9章で学ぶでしょう。 +これは、プログラムがエラーの可能性に対処していないことを示します。 + + + + + +警告を抑制する正しい手段は、実際にエラー対処コードを書くことですが、今は、 +問題が起きた時にプロラグムをクラッシュさせたいので、`expect`を使用できるわけです。 +エラーから復旧する方法については、第9章で学ぶでしょう。 @@ -636,25 +492,20 @@ since you just want to crash this program when a problem occurs, you can use println!("You guessed: {}", guess); ``` -<<<<<<< HEAD - - - - + + + + + + + -この行は、ユーザ入力を保存した文字列の中身を出力します。1組の`{}`は、値を保持しておくプレースホルダーの役目を果たします。 -`{}`を使って一つ以上の値を出力できます: 最初の`{}`の組は、フォーマット文字列の後に列挙された最初の値に対応し、 +この行は、ユーザ入力を保存した文字列の中身を出力します。1組の波括弧の`{}`は、プレースホルダーの役目を果たします: +`{}`は値を所定の場所に保持する小さなカニのはさみと考えてください。波括弧を使って一つ以上の値を出力できます: +最初の波括弧の組は、フォーマット文字列の後に列挙された最初の値に対応し、 2組目は、2つ目の値、とそんな感じで続いていきます。1回の`println!`の呼び出しで複数値を出力するコードは、 以下のような感じになります: -======= -This line prints the string we saved the user’s input in. The set of curly -brackets, `{}`, is a placeholder: think of `{}` as little crab pincers that -hold a value in place. You can print more than one value using curly brackets: -the first set of curly brackets holds the first value listed after the format -string, the second set holds the second value, and so on. Printing multiple -values in one call to `println!` would look like this: ->>>>>>> fork_master_master ```rust let x = 5; @@ -663,26 +514,17 @@ let y = 10; println!("x = {} and y = {}", x, y); ``` -<<<<<<< HEAD - -======= -This code would print `x = 5 and y = 10`. ->>>>>>> fork_master_master + このコードは、`x = 5 and y = 10`と出力するでしょう. -<<<<<<< HEAD ### 最初の部分をテストする - - + -数当てゲームの最初の部分をテストしてみましょう。`cargo run`でプログラムを走らせることができます: -======= -Let’s test the first part of the guessing game. Run it using `cargo run`: ->>>>>>> fork_master_master +数当てゲームの最初の部分をテストしてみましょう。`cargo run`でプログラムを走らせてください: ```text $ cargo run @@ -721,11 +563,11 @@ Rustの標準ライブラリには、乱数機能はまだ含まれていませ ### クレートを使用して機能を追加する - + -*クレート*はRustコードのパッケージであることを思い出してください。私たちがここまで作ってきたプロジェクトは、 +クレートはRustコードのパッケージであることを思い出してください。私たちがここまで作ってきたプロジェクトは、 *バイナリークレート*であり、これは実行可能形式になります。`rand`クレートは*ライブラリクレート*であり、 他のプログラムで使用するためのコードが含まれています。 @@ -735,17 +577,11 @@ Rustの標準ライブラリには、乱数機能はまだ含まれていませ -<<<<<<< HEAD Cargoを使って外部クレートを使用すると、Cargoがとても輝きます。`rand`を使ったコードを書ける前に、 *Cargo.toml*ファイルを編集して、`rand`クレートを依存ファイルとして取り込む必要があります。 今このファイルを開いて、以下の行をCargoが自動生成した`[dependencies]`セクションヘッダーの一番下に追記しましょう: -======= -Remember that a crate is a package of Rust code. The project we’ve been -building is a *binary crate*, which is an executable. The `rand` crate is a -*library crate*, which contains code intended to be used in other programs. ->>>>>>> fork_master_master @@ -808,7 +644,6 @@ $ cargo build -<<<<<<< HEAD 今や、外部依存を持つようになったので、Cargoは*レジストリ*(registry、登録所)から最新バージョンを拾ってきます。 *レジストリ*とは、[Crates.io][cratesio]のデータのコピーです. Crates.ioとは、Rustのエコシステムにいる人間が、 他の人も使えるように自分のオープンソースのRustプロジェクトを投稿する場所です。 @@ -816,46 +651,32 @@ $ cargo build [cratesio]: https://crates.io - - - - + + + + -レジストリの更新後、Cargoは`[dependencies]`セクションをチェックし、まだ取得していないものを全部ダウンロードします。 +レジストリの更新後、Cargoは`[dependencies]`セクションをチェックし、まだ取得していないクレートを全部ダウンロードします。 今回の場合、`rand`しか依存ファイルには列挙していませんが、Cargoは`libc`のコピーも拾ってきます。 -`rand`クレートが`libc`に依存しているからですね。ダウンロード完了後、コンパイラは依存ファイル、 +`rand`クレートが`libc`に依存しているからですね。クレートのダウンロード完了後、コンパイラは依存ファイル、 そして、依存が利用可能な状態でプロジェクトをコンパイルします。 - - - - - - - - -何も変更せず即座に`cargo build`コマンドを走らせたら、何も出力されないでしょう。 -Cargoは、すでに全ての依存をダウンロードしてコンパイル済みであることも、あなたが -*Cargo.toml*ファイルを弄ってないことも知っているからです。さらに、Cargoはプログラマがコードを変更していないことも検知するので、 + + + + + + + +何も変更せず即座に`cargo build`コマンドを走らせたら、`Finished`行を除いて何も出力されないでしょう。 +Cargoは、すでに全ての依存をダウンロードしてコンパイル済みであることも、 +あなたが*Cargo.toml*ファイルを弄ってないことも知っているからです。さらに、Cargoはプログラマがコードを変更していないことも検知するので、 再度コンパイルすることもありません。することがないので、ただ単に終了します。 -*src/main.rs*ファイルを開き、些細な変更をし、保存して再度ビルドを行えば、1行だけ出力があるでしょう: -======= -After updating the registry, Cargo checks the `[dependencies]` section and -downloads any crates you don’t have yet. In this case, although we only listed -`rand` as a dependency, Cargo also grabbed a copy of `libc`, because `rand` -depends on `libc` to work. After downloading the crates, Rust compiles them and -then compiles the project with the dependencies available. - -If you immediately run `cargo build` again without making any changes, you -won’t get any output aside from the `Finished` line. Cargo knows it has already -downloaded and compiled the dependencies, and you haven’t changed anything -about them in your *Cargo.toml* file. Cargo also knows that you haven’t changed -anything about your code, so it doesn’t recompile that either. With nothing to -do, it simply exits. - -If you open up the *src/main.rs* file, make a trivial change, and then save it -and build again, you’ll only see two lines of output: ->>>>>>> fork_master_master + + + + +*src/main.rs*ファイルを開き、些細な変更をし、保存して再度ビルドを行えば、2行だけ出力があるでしょう: ```text $ cargo build @@ -908,32 +729,18 @@ Cargoは判断基準(criteria)に合致するよう全ての依存のバージ このことにより、自動的に再現可能なビルドを構成できるのです。つまり、明示的にアップグレードしない限り、 プロジェクトが使用するバージョンは`0.3.14`に保たれるのです。*Cargo.lock*ファイルのおかげでね。 -<<<<<<< HEAD - -======= -#### Ensuring Reproducible Builds with the *Cargo.lock* File ->>>>>>> fork_master_master + -#### クレートを更新して新バージョンを取得する +#### *Cargo.lock*ファイルで再現可能なビルドを保証する - + + + -クレートを*本当に*アップグレードする必要が出てきたら、Cargoの別のコマンド(`update`)を使用しましょう。これは: - -<<<<<<< HEAD - - - - -1. *Cargo.lock*ファイルを無視して*Cargo.toml*ファイル内の全ての指定に合致する最新バージョンを計算します -1. それがうまくいったら、Cargoはそれらのバージョンを*Cargo.lock*ファイルに記述します。 -======= -When you *do* want to update a crate, Cargo provides another command, `update`, -which will ignore the *Cargo.lock* file and figure out all the latest versions -that fit your specifications in *Cargo.toml*. If that works, Cargo will write -those versions to the *Cargo.lock* file. ->>>>>>> fork_master_master +クレートを*本当に*アップグレードする必要が出てきたら、Cargoの別のコマンド(`update`)を使用しましょう。 +これは、*Cargo.lock*ファイルを無視して*Cargo.toml*ファイル内の全ての指定に合致する最新バージョンを計算します。 +それがうまくいったら、Cargoはそれらのバージョンを*Cargo.lock*ファイルに記述します。 @@ -971,35 +778,23 @@ $ cargo update rand = "0.4.0" ``` -<<<<<<< HEAD - + 次回、`cargo build`コマンドを走らせたら、Cargoは利用可能なクレートのレジストリを更新し、 `rand`クレートの必要条件を指定した新しいバージョンに再評価します。 - - - - + + + + まだ第14章で議論する[Cargo][doccargo]と[そのエコシステム][doccratesio] については述べたいことが山ほどありますが、とりあえずは、これで知っておくべきことは全てです。 Cargoのおかげでライブラリはとても簡単に再利用ができるので、Rustacean(Rustユーザのこと)は数多くのパッケージから 構成された小規模のプロジェクトを書くことができるのです。 -======= -The next time you run `cargo build`, Cargo will update the registry of crates -available and reevaluate your `rand` requirements according to the new version -you have specified. - -There’s a lot more to say about [Cargo][doccargo] and [its -ecosystem][doccratesio] which we’ll discuss in Chapter 14, but -for now, that’s all you need to know. Cargo makes it very easy to reuse -libraries, so Rustaceans are able to write smaller projects that are assembled -from a number of packages. ->>>>>>> fork_master_master [doccargo]: http://doc.crates.io [doccratesio]: http://doc.crates.io/crates-io.html @@ -1008,15 +803,11 @@ from a number of packages. ### 乱数を生成する - - + + -<<<<<<< HEAD -`rand`クレートを*使用*開始しましょう。次のステップは、リスト2-3のように*src/main.rs*ファイルを更新することです: -======= -Now that you’ve added the `rand` crate to *Cargo.toml*, let’s start using -`rand`. The next step is to update *src/main.rs*, as shown in Listing 2-3: ->>>>>>> fork_master_master +*Cargo.toml*に`rand`クレートを追加したので、`rand`クレートを*使用*開始しましょう。 +次のステップは、リスト2-3のように*src/main.rs*ファイルを更新することです: @@ -1046,26 +837,24 @@ fn main() { } ``` -<<<<<<< HEAD - + -リスト2-3: 乱数を生成するのに必要なコードの変更 +リスト2-3: 乱数を生成するコードの追加 - - - - + + + -冒頭に`extern crate rand;`行を追加して、コンパイラにこの外部依存を使用することを知らせています。 +まず、コンパイラに`rand`クレートを外部依存として使用することを知らせる行を追加しています。 これにより、`use rand`を呼ぶのと同じ効果が得られるので、`rand`クレートのものを`rand::` という接頭辞をつけて呼び出せるようになりました。 - - - + + + -次に、別の`use`行を追加しています: `use rand::Rng`ですね。`Rng`とは乱数生成器が実装するメソッドを定義したトレイトであり、 +次に、別の`use`行を追加しています: `use rand::Rng`ですね。`Rng`トレイトは乱数生成器が実装するメソッドを定義していて、 このトレイトがスコープにないと、メソッドを使用できないのです。トレイトについて詳しくは、 第10章で解説します。 @@ -1086,19 +875,19 @@ fn main() { それらの間の乱数を生成してくれます。範囲は下限値を含み、上限値を含まないため、`1`と`101`と指定しないと 1から100の範囲の数字は得られません。 - - - - - - - + + + + + + + -使用すべきトレイトとクレートから呼び出すべき関数とメソッドを知ることが、単純に*知っている*ことではないでしょう。 -クレートの使用方法は、各クレートのドキュメントにあります。Cargoの別の素晴しい機能は、`cargo doc --open`コマンドを -走らせてローカルに存在する依存すべてのドキュメントをビルドし、ブラウザで閲覧できる機能です。例えば、 -`rand`クレートの他の機能に興味があるなら、`cargo doc --open`コマンドを走らせて、左側のサイドバーから -`rand`をクリックしてください。 +> 単純に使用すべきトレイトとクレートからどの関数とメソッドを呼び出すか知っているわけではないでしょう。 +> クレートの使用方法は、各クレートのドキュメントにあります。Cargoの別の素晴しい機能は、`cargo doc --open`コマンドを +> 走らせてローカルに存在する依存すべてのドキュメントをビルドし、ブラウザで閲覧できる機能です。例えば、 +> `rand`クレートの他の機能に興味があるなら、`cargo doc --open`コマンドを走らせて、左側のサイドバーから +> `rand`をクリックしてください。 @@ -1110,44 +899,7 @@ fn main() { -何回かプログラムを走らせてみてください: -======= -Listing 2-3: Adding code to generate a random -number - -First, we add a line that lets Rust know we’ll be using the `rand` crate as an -external dependency. This also does the equivalent of calling `use rand`, so -now we can call anything in the `rand` crate by placing `rand::` before it. - -Next, we add another `use` line: `use rand::Rng`. The `Rng` trait defines -methods that random number generators implement, and this trait must be in -scope for us to use those methods. Chapter 10 will cover traits in detail. - -Also, we’re adding two more lines in the middle. The `rand::thread_rng` function -will give us the particular random number generator that we’re going to use: -one that is local to the current thread of execution and seeded by the -operating system. Next, we call the `gen_range` method on the random number -generator. This method is defined by the `Rng` trait that we brought into -scope with the `use rand::Rng` statement. The `gen_range` method takes two -numbers as arguments and generates a random number between them. It’s inclusive -on the lower bound but exclusive on the upper bound, so we need to specify `1` -and `101` to request a number between 1 and 100. - -> Note: You won’t just know which traits to use and which methods and functions -> to call from a crate. Instructions for using a crate are in each crate’s -> documentation. Another neat feature of Cargo is that you can run the `cargo -> doc --open` command, which will build documentation provided by all of your -> dependencies locally and open it in your browser. If you’re interested in -> other functionality in the `rand` crate, for example, run `cargo doc --open` -> and click `rand` in the sidebar on the left. - -The second line that we added to the code prints the secret number. This is -useful while we’re developing the program to be able to test it, but we’ll -delete it from the final version. It’s not much of a game if the program prints -the answer as soon as it starts! - -Try running the program a few times: ->>>>>>> fork_master_master +試しに何回かプログラムを走らせてみてください: ```text $ cargo run @@ -1177,19 +929,15 @@ You guessed: 5 ## 予想と秘密の数字を比較する - - + + + 今や、ユーザ入力と乱数生成ができるようになったので、比較することができますね。 -このステップはリスト2-4に示されています: +このステップはリスト2-4に示されています。このコードは現状ではコンパイルできないので、 +説明することに注意してください。 -<<<<<<< HEAD -======= -Now that we have user input and a random number, we can compare them. That step -is shown in Listing 2-4. Note that this code won’t compile quite yet, as we -will explain. ->>>>>>> fork_master_master ファイル名: src/main.rs @@ -1218,20 +966,19 @@ fn main() { リスト2-4: 2値比較の可能性のある返り値を処理する -<<<<<<< HEAD - - - + + + 最初の新しい点は、別の`use`文です。これで、`std::cmp::Ordering`という型を標準ライブラリから -スコープに導入しています。`Result`と同じく`Ordering`もenumです。ただ、`Ordering`が取りうる値は、 +スコープに導入しています。`Result`と同じく`Ordering`もenumです。ただ、`Ordering`の列挙子は、 `Less`、`Greater`そして、`Equal`です。これらは、2値比較した時に発生しうる3種類の結果です。 - + -それから、一番下に5行追加して`Ordering`型を使用しています: +それから、一番下に5行追加して`Ordering`型を使用しています。 ```rust,ignore match guess.cmp(&secret_number) { @@ -1243,7 +990,7 @@ match guess.cmp(&secret_number) { - + @@ -1251,8 +998,8 @@ match guess.cmp(&secret_number) { `cmp`メソッドは、2値を比較し、比較できるものに対してならなんに対しても呼び出せます。このメソッドは、 比較したいものへの参照を取ります: ここでは、`guess`変数と`secret_number`変数を比較しています。 -`cmp`メソッドは`use`文でスコープに導入した`Ordering`列挙型の値を返します。 -[`match`][match]式を使用して、`guess`変数と`secret_number`を`cmp`に渡して返ってきた`Ordering`の値に基づき、 +それからこのメソッドは`use`文でスコープに導入した`Ordering`列挙型の値を返します。 +[`match`][match]式を使用して、`guess`変数と`secret_number`を`cmp`に渡して返ってきた`Ordering`の列挙子に基づき、 次の動作を決定しています。 [match]: ch06-02-match.html @@ -1273,55 +1020,16 @@ match guess.cmp(&secret_number) { これらの機能は、それぞれ、第6章と第18章で詳しく解説することにします。 - + - - - - - - - - - -ここで使われている`match`式でどんなことが起こるかの例をじっくり観察してみましょう!例えば、 -ユーザは50と予想し、ランダム生成された秘密の数字は今回、38だったとしましょう。コードが50と38を比較すると、 -`cmp`メソッドは`Ordering::Greater`を返します。50は38よりも大きいからですね。`Ordering::Greater`が、 -`match`式に渡される値になります。まず、最初のアームのパターンと照合します(`Ordering::Less`ですね)。しかし、 -値の`Ordering::Greater`と`Ordering::Less`はマッチしないため、このアームのコードは無視され、 -次のアームに移ります。次のアームのパターン、`Ordering::Greater`は*見事に*`Ordering::Greater`とマッチします! -このアームに紐づけられたコードが実行され、画面に`Too big!`が表示されます。 -これで`match`式の実行は終わりになります。この筋書きでは、最後のアームと照合する必要はもうないからですね。 - - - -ところが、リスト2-4のコードは、まだコンパイルが通りません。試してみましょう: -======= -The first new bit here is another `use` statement, bringing a type called -`std::cmp::Ordering` into scope from the standard library. Like `Result`, -`Ordering` is another enum, but the variants for `Ordering` are `Less`, -`Greater`, and `Equal`. These are the three outcomes that are possible when you -compare two values. - -Then we add five new lines at the bottom that use the `Ordering` type. - -The `cmp` method compares two values and can be called on anything that can be -compared. It takes a reference to whatever you want to compare with: here it’s -comparing the `guess` to the `secret_number`. Then it returns a variant of the -`Ordering` enum we brought into scope with the `use` statement. We use a -[`match`][match] expression to decide what to do next based on -which variant of `Ordering` was returned from the call to `cmp` with the values -in `guess` and `secret_number`. - -[match]: ch06-02-match.html - -A `match` expression is made up of *arms*. An arm consists of a *pattern* and -the code that should be run if the value given to the beginning of the `match` -expression fits that arm’s pattern. Rust takes the value given to `match` and -looks through each arm’s pattern in turn. The `match` construct and patterns -are powerful features in Rust that let you express a variety of situations your -code might encounter and make sure that you handle them all. These features -will be covered in detail in Chapter 6 and Chapter 18, respectively. + + + + + + + + Let’s walk through an example of what would happen with the `match` expression used here. Say that the user has guessed 50 and the randomly generated secret @@ -1335,8 +1043,19 @@ the code in that arm and moves to the next arm. The next arm’s pattern, that arm will execute and print `Too big!` to the screen. The `match` expression ends because it has no need to look at the last arm in this scenario. -However, the code in Listing 2-4 won’t compile yet. Let’s try it: ->>>>>>> fork_master_master +ここで使われている`match`式でどんなことが起こるかの例をじっくり観察してみましょう!例えば、 +ユーザは50と予想し、ランダム生成された秘密の数字は今回、38だったとしましょう。コードが50と38を比較すると、 +`cmp`メソッドは`Ordering::Greater`を返します。50は38よりも大きいからですね。`match`式に、 +`Ordering::Greater`が与えられ、各アームのパターンを吟味し始めます。まず、 +最初のアームのパターンと照合します(`Ordering::Less`ですね)。しかし、 +値の`Ordering::Greater`と`Ordering::Less`はマッチしないため、このアームのコードは無視され、 +次のアームに移ります。次のアームのパターン、`Ordering::Greater`は*見事に*`Ordering::Greater`とマッチします! +このアームに紐づけられたコードが実行され、画面に`Too big!`が表示されます。 +これで`match`式の実行は終わりになります。この筋書きでは、最後のアームと照合する必要はもうないからですね。 + + + +ところが、リスト2-4のコードは、まだコンパイルが通りません。試してみましょう: ```text $ cargo build @@ -1355,7 +1074,6 @@ error: aborting due to previous error (先のエラーのため、処理を中 Could not compile `guessing_game`. (`guessing_game`をコンパイルできませんでした) ``` -<<<<<<< HEAD @@ -1364,8 +1082,8 @@ Could not compile `guessing_game`. (`guessing_game`をコンパイルでき - - + + このエラーの核は、*型の不一致*があると言っています。Rustは、強い静的型システムを持っています。 しかし、型推論にも対応しています。`let guess = String::new()`と書いた時、コンパイラは、 @@ -1376,24 +1094,8 @@ Rustでの標準は、`i32`型であり、型情報をどこかに追加して `secret_number`の型はこれになります。エラーの原因は、Rustでは、文字列と数値型を比較できないことです。 - - -======= -The core of the error states that there are *mismatched types*. Rust has a -strong, static type system. However, it also has type inference. When we wrote -`let guess = String::new()`, Rust was able to infer that `guess` should be a -`String` and didn’t make us write the type. The `secret_number`, on the other -hand, is a number type. A few number types can have a value between 1 and 100: -`i32`, a 32-bit number; `u32`, an unsigned 32-bit number; `i64`, a 64-bit -number; as well as others. Rust defaults to an `i32`, which is the type of -`secret_number` unless you add type information elsewhere that would cause Rust -to infer a different numerical type. The reason for the error is that Rust -cannot compare a string and a number type. - -Ultimately, we want to convert the `String` the program reads as input into a -real number type so we can compare it numerically to the guess. We can do that -by adding the following two lines to the `main` function body: ->>>>>>> fork_master_master + + 究極的には、プログラムが入力として読み込む`String`型を現実の数値型に変換し、 予想と数値として比較できるようにしたいわけです。これは、以下の2行を`main`関数の本体に追記することでできます: @@ -1432,14 +1134,13 @@ let guess: u32 = guess.trim().parse() .expect("Please type a number!"); ``` -<<<<<<< HEAD - - - - - - - + + + + + + + `guess`という名前の変数を生成しています。あれ、でも待って。もうプログラムには`guess`という名前の変数が ありませんでしたっけ?確かにありますが、Rustでは、新しい値で`guess`の値を*覆い隠す*(shadow)ことが @@ -1450,23 +1151,23 @@ let guess: u32 = guess.trim().parse() - - + + - - - - + + + + `guess`を`guess.trim().parse()`という式に束縛しています。この式中の`guess`は、 入力が入った`String`型の元々の`guess`を指しています。`String`オブジェクトの`trim`メソッドは、 両端の空白をすべて除去します。`u32`型は、数字しか含むことができませんが、ユーザは、 -`read_line`の処理を終えるためにエンターキーを押さなければなりません。 -ユーザがエンターキーを押したら、改行文字が文字列に追加されます。 +`read_line`の処理を終えるためにエンターを押さなければなりません。 +ユーザがエンターを押したら、改行文字が文字列に追加されます。 具体例として、ユーザが5を入力して、 -エンターキーを押せば、`guess`は次のようになります: `5\n`。 -この`\n`が「改行」、つまりエンターキーを表しているわけです。 +エンターを押せば、`guess`は次のようになります: `5\n`。 +この`\n`が「改行」、つまりエンターキーを押した結果を表しているわけです。 `trim`メソッドは、`\n`を削除するので、ただの`5`になります。 @@ -1487,26 +1188,26 @@ Rustには、組み込みの数値型がいくつかあります; ここの`u32` `u32`型は小さな非負整数のデフォルトの選択肢として丁度良いです。他の数値型については、第3章で学ぶでしょう。 付け加えると、このサンプルプログラムの`u32`という注釈と`secret_number`変数との比較は、 `secret_number`変数も`u32`型であるとコンパイラが推論することを意味します。 -さて、従って、比較が同じ型の2つの値で行われることになります。 +従って、今では比較が同じ型の2つの値で行われることになるわけです! [parse]: ../../std/primitive.str.html#method.parse - - - - - - - - + + + + + + + + `parse`メソッドの呼び出しは、エラーになりやすいです。例としては、文字列が`A👍%`を含んでいたら、 数値に変換できるわけがありません。失敗する可能性があるので、`parse`メソッドは、 -`Result`型を返すわけです。ちょうど、「Result型で失敗する可能性に対処する」節で先ほど議論した`read_line`メソッドのようにというわけですね。 -今回も、`expect`メソッドを使用して`Result`型を同じように扱います。 -もし、文字列から数値を生成できなかったために、`parse`メソッドが`Result`型の`Err`値を返したら、 +`Result`型を返すわけです。ちょうど、(「Result型で失敗する可能性に対処する」節で先ほど議論した)`read_line`メソッドのようにというわけですね。 +今回も、`expect`メソッドを使用して`Result`型を同じように扱います。この`Result`を`expect`メソッドを再度使用して、 +同じように扱います。もし、文字列から数値を生成できなかったために、`parse`メソッドが`Result`型の`Err`値を返したら、 `expect`メソッドの呼び出しは、ゲームをクラッシュさせ、与えたメッセージを表示します。 もし、`parse`メソッドが文字列の数値への変換に成功したら、`Result`型の`Ok`値を返し、 `expect`メソッドは、`Ok`値から必要な数値を返してくれます。 @@ -1514,53 +1215,6 @@ Rustには、組み込みの数値型がいくつかあります; ここの`u32` さあ、プログラムを走らせましょう! -======= -We create a variable named `guess`. But wait, doesn’t the program already have -a variable named `guess`? It does, but Rust allows us to *shadow* the previous -value of `guess` with a new one. This feature is often used in situations in -which you want to convert a value from one type to another type. Shadowing lets -us reuse the `guess` variable name rather than forcing us to create two unique -variables, like `guess_str` and `guess` for example. (Chapter 3 covers -shadowing in more detail.) - -We bind `guess` to the expression `guess.trim().parse()`. The `guess` in the -expression refers to the original `guess` that was a `String` with the input in -it. The `trim` method on a `String` instance will eliminate any whitespace at -the beginning and end. Although `u32` can contain only numerical characters, -the user must press enter to satisfy -`read_line`. When the user presses enter, a -newline character is added to the string. For example, if the user types 5 and presses enter, -`guess` looks like this: `5\n`. The `\n` represents “newline,” the result of -pressing enter. The `trim` method eliminates -`\n`, resulting in just `5`. - -The [`parse` method on strings][parse] parses a string into some -kind of number. Because this method can parse a variety of number types, we -need to tell Rust the exact number type we want by using `let guess: u32`. The -colon (`:`) after `guess` tells Rust we’ll annotate the variable’s type. Rust -has a few built-in number types; the `u32` seen here is an unsigned, 32-bit -integer. It’s a good default choice for a small positive number. You’ll learn -about other number types in Chapter 3. Additionally, the `u32` annotation in -this example program and the comparison with `secret_number` means that Rust -will infer that `secret_number` should be a `u32` as well. So now the -comparison will be between two values of the same type! - -[parse]: ../../std/primitive.str.html#method.parse - -The call to `parse` could easily cause an error. If, for example, the string -contained `A👍%`, there would be no way to convert that to a number. Because it -might fail, the `parse` method returns a `Result` type, much as the `read_line` -method does (discussed earlier in “Handling Potential Failure with the Result -Type”). We’ll treat this `Result` the same way by using the `expect` method -again. If `parse` returns an `Err` `Result` variant because it couldn’t create -a number from the string, the `expect` call will crash the game and print the -message we give it. If `parse` can successfully convert the string to a number, -it will return the `Ok` variant of `Result`, and `expect` will return the -number that we want from the `Ok` value. - -Let’s run the program now! ->>>>>>> fork_master_master ```text $ cargo run @@ -1594,15 +1248,10 @@ Too big! ## ループで複数回の予想を可能にする - - + + -<<<<<<< HEAD `loop`キーワードは、無限ループを作り出します。これを追加して、ユーザが何回も予想できるようにしましょう: -======= -The `loop` keyword creates an infinite loop. We’ll add that now to give users -more chances at guessing the number: ->>>>>>> fork_master_master @@ -1627,42 +1276,28 @@ more chances at guessing the number: } ``` -<<<<<<< HEAD - - - - + + + + -見てわかる通り、予想入力部分以降をループに入れ込みました。変更した行にインデントを追加するのを忘れないようにして、 -またプログラムを走らせてみましょう。新たな問題が発生したことに気をつけてください。 +見てわかる通り、予想入力部分以降をループに入れ込みました。ループ内の行にインデントを追加するのを忘れないようにして、 +またプログラムを走らせてみましょう。新たな問題が発生したことに気付いてください。 プログラムが教えた通りに動作しているからですね: 永遠に予想入力を求めるわけです! これでは、ユーザが終了できないようです! - - - - - + + + + + + ユーザは、ctrl-cというキーボードショートカットを使って、いつでもプログラムを強制終了させられます。 -しかし、「予想を秘密の数字と比較する」節の`parse`メソッドに関する議論で触れたこの貪欲なモンスターを -回避する別の方法があります: ユーザが数字以外の答えを入力すれば、プログラムはクラッシュするのです。 +しかし、「予想を秘密の数字と比較する」節の`parse`メソッドに関する議論で触れたように、 +この貪欲なモンスターを回避する別の方法があります: ユーザが数字以外の答えを入力すれば、プログラムはクラッシュするのです。 ユーザは、その利点を活かして、終了することができます。以下のようにね: -======= -As you can see, we’ve moved everything into a loop from the guess input prompt -onward. Be sure to indent the lines inside the loop another four spaces each -and run the program again. Notice that there is a new problem because the -program is doing exactly what we told it to do: ask for another guess forever! -It doesn’t seem like the user can quit! - -The user could always halt 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”: if the user enters a non-number answer, the -program will crash. The user can take advantage of that in order to quit, as -shown here: ->>>>>>> fork_master_master ```text $ cargo run @@ -1702,13 +1337,9 @@ error: Process didn't exit successfully: `target/debug/guess` (exit code: 101) -<<<<<<< HEAD ### 正しい予想をした後に終了する -======= -Let’s program the game to quit when the user wins by adding a `break` statement: ->>>>>>> fork_master_master - + `break`文を追加して、ユーザが勝った時にゲームが終了するようにプログラムしましょう: @@ -1731,39 +1362,26 @@ Let’s program the game to quit when the user wins by adding a `break` statemen } ``` -<<<<<<< HEAD - - + + -`break`文の1行を`You win!`の後に追記することで、ユーザが秘密の数字を正確に予想したら、 +`break`文の1行を`You win!`の後に追記することで、ユーザが秘密の数字を正確に予想した時に、 プログラムはループを抜けるようになりました。ついでに、ループを抜けることは、プログラムを終了することを意味します。 ループが`main`関数の最後の部分だからですね。 -======= -Adding the `break` line after `You win!` makes the program exit the loop when -the user guesses the secret number correctly. Exiting the loop also means -exiting the program, because the loop is the last part of `main`. ->>>>>>> fork_master_master -<<<<<<< HEAD ### 不正な入力を処理する - - + + さらにゲームの振る舞いを改善するために、ユーザが数値以外を入力した時にプログラムをクラッシュさせるのではなく、 非数値を無視してユーザが数当てを続けられるようにしましょう!これは、 `guess`が`String`型から`u32`型に変換される行を改変することで達成できます: -======= -To further refine the game’s behavior, rather than crashing the program when -the user inputs a non-number, let’s make the game ignore a non-number so the -user can continue guessing. We can do that by altering the line where `guess` -is converted from a `String` to a `u32`: ->>>>>>> fork_master_master ```rust,ignore let guess: u32 = match guess.trim().parse() { @@ -1772,37 +1390,36 @@ let guess: u32 = match guess.trim().parse() { }; ``` -<<<<<<< HEAD - - - + + + `expect`メソッドの呼び出しから`match`式に切り替えることは、 -エラーでクラッシュする動作から実際にエラー処理を行う処理へ変更する一般的な手段になります。`parse`メソッドは、 +エラーでクラッシュする動作からエラー処理を行う処理へ変更する一般的な手段になります。`parse`メソッドは、 `Result`型を返し、`Result`は`Ok`か`Err`の値を取りうるenumであることを思い出してください。 ここでは`match`式を使っています。`cmp`メソッドの`Ordering`という結果のような感じですね。 - - - - - + + + + + `parse`メソッドは、文字列から数値への変換に成功したら、結果の数値を保持する`Ok`値を返します。 この`Ok`値は、最初のアームのパターンにマッチし、この`match`式は`parse`メソッドが生成し、 -`Ok`値に格納した`num`の値を返すだけです。その数値が最終的に生成した新しい`guess`変数に含まれます。 +`Ok`値に格納した`num`の値を返すだけです。その数値が最終的に生成した新しい`guess`変数の欲しい場所に含まれます。 - - - - - - + + + + + + `parse`メソッドは、文字列から数値への変換に*失敗*したら、エラーに関する情報を多く含む`Err`値を返します。 この`Err`値は、最初の`match`アームの`Ok(num)`というパターンにはマッチしないものの、 @@ -1812,35 +1429,9 @@ let guess: u32 = match guess.trim().parse() { 次の段階に移り、再度予想入力を求めることを意味します。故に実質的には、プログラムは`parse`メソッドが 遭遇しうる全てのエラーを無視するようになります! - - - -さて、プログラムの全てがうまく予想通りに動くはずです。`cargo run`を走らせて、試してみましょう: -======= -Switching from an `expect` call to a `match` expression is how you generally -move from crashing on an error to handling the error. Remember that `parse` -returns a `Result` type and `Result` is an enum that has the variants `Ok` or -`Err`. We’re using a `match` expression here, as we did with the `Ordering` -result of the `cmp` method. - -If `parse` is able to successfully turn the string into a number, it will -return an `Ok` value that contains the resulting number. That `Ok` value will -match the first arm’s pattern, and the `match` expression will just return the -`num` value that `parse` produced and put inside the `Ok` value. That number -will end up right where we want it in the new `guess` variable we’re creating. - -If `parse` is *not* able to turn the string into a number, it will return an -`Err` value that contains more information about the error. The `Err` value -does not match the `Ok(num)` pattern in the first `match` arm, but it does -match the `Err(_)` pattern in the second arm. The underscore, `_`, is a -catchall value; in this example, we’re saying we want to match all `Err` -values, no matter what information they have inside them. So the program will -execute the second arm’s code, `continue`, which means to go to the next -iteration of the `loop` and ask for another guess. So effectively, the program -ignores all errors that `parse` might encounter! - -Now everything in the program should work as expected. Let’s try it: ->>>>>>> fork_master_master + + +さて、プログラムの全てがうまく予想通りに動くはずです。試しましょう: ```text $ cargo run @@ -1864,24 +1455,17 @@ You guessed: 61 You win! ``` -<<<<<<< HEAD - - + + -素晴らしい!最後にひとつまみ変更を加えて、数当てゲームを完了にしましょう: +素晴らしい!最後にひとつまみ変更を加えて、数当てゲームを完了にしましょう。 プログラムが未だに秘密の数字を出力していることを思い出してください。テスト中はうまく動くけど、 ゲームを台無しにしてしまいます。秘密の数字を出力する`println!`を削除しましょう。 リスト2-5が成果物のコードです: -======= -Awesome! With one tiny final tweak, we will finish the guessing game. Recall -that the program is still printing the secret number. That worked well for -testing, but it ruins the game. Let’s delete the `println!` that outputs the -secret number. Listing 2-5 shows the final code: ->>>>>>> fork_master_master ファイル名: src/main.rs @@ -1924,8 +1508,7 @@ fn main() { } ``` -<<<<<<< HEAD - + リスト2-5: 数当てゲームの完全なコード @@ -1934,36 +1517,22 @@ fn main() { ## まとめ -======= -Listing 2-5: Complete guessing game code ->>>>>>> fork_master_master ここまでで、数当てゲームの作成に成功しました!おめでとうございます! - - - + + + - - - + + + -<<<<<<< HEAD このプロジェクトは、たくさんの新しいRustの概念に触れる実践的な方法でした: `let`文、`match`式、メソッド、関連関数、外部クレートの使用などなど。 以降の数章で、これらの概念についてより深く学ぶことになるでしょう。 第3章では、ほとんどのプログラミング言語が持っている、変数、データ型、関数などの概念について解説し、 それらのRustでの使用方法について示します。 -第4章では、所有権について見ます。所有権は、他の言語とかけ離れているRustの機能の一つです。 -第5章では、構造体とメソッド記法について議論し、第6章ではenumについて説明する努力をしましょう。 -======= -This project was a hands-on way to introduce you to many new Rust concepts: -`let`, `match`, methods, associated functions, the use of external crates, and -more. In the next few chapters, you’ll learn about these concepts in more -detail. Chapter 3 covers concepts that most programming languages have, such as -variables, data types, and functions, and shows how to use them in Rust. -Chapter 4 explores ownership, a feature that makes Rust different from other -languages. Chapter 5 discusses structs and method syntax, and Chapter 6 -explains how enums work. ->>>>>>> fork_master_master +第4章では、所有権について見ます。これにより、Rustは他の言語とかけ離れた存在になっています。 +第5章では、構造体とメソッド記法について議論し、第6章ではenumの動作法を説明します。 diff --git a/second-edition/src/ch03-00-common-programming-concepts.md b/second-edition/src/ch03-00-common-programming-concepts.md index cb707dcd6..31880dd79 100644 --- a/second-edition/src/ch03-00-common-programming-concepts.md +++ b/second-edition/src/ch03-00-common-programming-concepts.md @@ -1,24 +1,17 @@ -<<<<<<< HEAD # 一般的なプログラミングの概念 -======= -This chapter covers concepts that appear in almost every programming language -and how they work in Rust. Many programming languages have much in common at -their core. None of the concepts presented in this chapter are unique to Rust, -but we'll discuss them in the context of Rust and explain the conventions -around using these concepts. ->>>>>>> fork_master_master - + + この章では、ほとんど全てのプログラミング言語で見られる概念を解説し、それらがRustにおいて、 どう動作するかを見ていきます。多くのプログラミング言語は、その核心において、いろいろなものを共有しています。 -この章で提示する概念は、全てRustに固有のものではありませんが、Rustの文脈で議論し、その仕様を -解説していきます。 +この章で提示する概念は、全てRustに固有のものではありませんが、Rustの文脈で議論し、 +これらの概念を使用することにまつわる仕様を説明します。 @@ -31,7 +24,7 @@ around using these concepts. - + @@ -40,19 +33,8 @@ around using these concepts. > ### キーワード > -<<<<<<< HEAD > Rust言語にも他の言語同様、キーワードが存在し、これらは言語だけが使用できるようになっています。 > これらの単語は、変数や関数名には使えないことを弁えておいてください。ほとんどのキーワードは、特別な意味を持っており、 > 自らのRustプログラムにおいて、様々な作業をこなすために使用することができます; > いくつかは、紐付けられた機能がないものの、将来Rustに追加されるかもしれない機能用に予約されています。 > キーワードの一覧は、付録Aで確認できます。 - -======= -> The Rust language has a set of *keywords* that are reserved for use by -> the language only, much as in other languages. Keep in mind that you cannot -> use these words as names of variables or functions. Most of the keywords have -> special meanings, and you’ll be using them to do various tasks in your Rust -> programs; a few have no current functionality associated with them but have -> been reserved for functionality that might be added to Rust in the future. You -> can find a list of the keywords in Appendix A. ->>>>>>> fork_master_master diff --git a/second-edition/src/ch03-01-variables-and-mutability.md b/second-edition/src/ch03-01-variables-and-mutability.md index 728b94632..50ca2863b 100644 --- a/second-edition/src/ch03-01-variables-and-mutability.md +++ b/second-edition/src/ch03-01-variables-and-mutability.md @@ -1,46 +1,32 @@ -<<<<<<< HEAD ## 変数と可変性 - - - - - + + + + + + -第2章で触れた通り、変数は標準で*不変*になります。これは、 -Rustが提供する安全性や簡潔な並列プログラミングの利点を享受する形でコードを書くことを推奨してくれる一押しです。 +第2章で触れた通り、変数は標準で不変になります。これは、 +Rustが提供する安全性や簡潔な並列プログラミングの利点を享受する形でコードを書くために与えられた一押しです。 ところが、まだ変数を可変にするという選択肢も残されています。不変性を好むようコンパイラが推奨する手段と理由および、 それと違う道を選びたくなる理由を見ていきましょう。 -======= -As mentioned in Chapter 2, by default variables are immutable. This is one of -many nudges Rust gives you to write your code in a way that takes advantage of -the safety and easy concurrency that Rust offers. However, you still have the -option to make your variables mutable. Let’s explore how and why Rust -encourages you to favor immutability and why sometimes you might want to opt -out. - -When a variable is immutable, once a value is bound to a name, you can’t change -that value. To illustrate this, let’s generate a new project called *variables* -in your *projects* directory by using `cargo new --bin variables`. - -Then, in your new *variables* directory, open *src/main.rs* and replace its -code with the following code that won’t compile just yet: ->>>>>>> fork_master_master - - - - - -変数が不変であるとは、値が一旦名前に束縛されたら、その値を変えることができないことを意味します。 -具体化するために、*projects*ディレクトリに`cargo new --bin variables`コマンドを使って、 + + + + + +変数が不変であると、値が一旦名前に束縛されたら、その値を変えることができません。 +これを具体化するために、*projects*ディレクトリに`cargo new --bin variables`コマンドを使って、 *variables*という名前のプロジェクトを生成しましょう。 - + -それから、新規作成した*variables*ディレクトリで、*src/main.rs*ファイルを開き、その中身を以下のように置き換えましょう: +それから、新規作成した*variables*ディレクトリで、*src/main.rs*ファイルを開き、 +まだコンパイルできないけれど、その中身を以下のコードに置き換えましょう: @@ -83,11 +69,10 @@ error[E0384]: cannot assgin twice immutable variable `x` エラーが出るからといって、あなたがいいプログラマではないという意味では*ありません*! 経験豊富なRust市民でも、コンパイルエラーを出すことはあります。 - - + + -<<<<<<< HEAD このエラーは、エラーの原因が`不変変数xに2回代入できない`であると示しています。不変な`x`という変数に第2段階の値を代入しようとしたからです。 @@ -95,8 +80,8 @@ error[E0384]: cannot assgin twice immutable variable `x` - - + + 以前に不変と指定された値を変えようとした時に、コンパイルエラーが出るのは重要なことです。 なぜなら、この状況はまさしく、バグに繋がるからです。コードのある部分は、 @@ -105,50 +90,24 @@ error[E0384]: cannot assgin twice immutable variable `x` 事実(`脚注`:実際にプログラムを走らせた結果のことと思われる)の後には追いかけづらいものです。 特に第2のコード破片が、値を*時々*しか変えない場合尚更です。 - + - - + + Rustでは、値が不変であると宣言したら、本当に変わらないことをコンパイラが担保してくれます。 -つまり、コードを読み書きする際に、どこでどうやって値が変化しているかを追いかける必要がなくなり、 -コードが行うことを把握しやすくなります。 -======= -The error indicates that the cause of the error is that you `cannot assign twice -to immutable variable x`, because you tried to assign a second value to the -immutable `x` variable. - -It’s important that we get compile-time errors when we attempt to change a -value that we previously designated as immutable because this very situation -can lead to bugs. If one part of our code operates on the assumption that a -value will never change and another part of our code changes that value, it’s -possible that the first part of the code won’t do what it was designed to do. -The cause of this kind of bug can be difficult to track down after the fact, -especially when the second piece of code changes the value only *sometimes*. - -In Rust, the compiler guarantees that when you state that a value won’t change, -it really won’t change. That means that when you’re reading and writing code, -you don’t have to keep track of how and where a value might change. Your code -is thus easier to reason through. - -But mutability can be very useful. Variables are immutable only by default; as -you did in Chapter 2, you can make them mutable by adding `mut` in front of the -variable name. In addition to allowing this value to change, `mut` conveys -intent to future readers of the code by indicating that other parts of the code -will be changing this variable value. - -For example, let’s change *src/main.rs* to the following: ->>>>>>> fork_master_master - - - - - - +つまり、コードを読み書きする際に、どこでどうやって値が変化しているかを追いかける必要がなくなります。 +故にコードを通して推測することが簡単になるのです。 + + + + + + しかし、可変性は時として非常に有益なこともあります。変数は、標準でのみ、不変です。つまり、 -変数名の前に`mut`キーワードを付ければ、可変にできるわけです。この値が変化できるようにするとともに、 -未来の読者に対してコードの別の部分がこの変数の値を変える可能性を示すことで、その意図を汲ませることができるのです。 +第2章のように変数名の前に`mut`キーワードを付けることで、可変にできるわけです。この値が変化できるようにするとともに、 +`mut`により、未来の読者に対してコードの別の部分がこの変数の値を変える可能性を示すことで、その意図を汲ませることができるのです。 @@ -167,13 +126,9 @@ fn main() { } ``` -<<<<<<< HEAD - + -このプログラムを走らせると、以下のような出力が得られます: -======= -When we run the program now, we get this: ->>>>>>> fork_master_master +今、このプログラムを走らせると、以下のような出力が得られます: ```text $ cargo run @@ -184,79 +139,48 @@ The value of x is: 5 (xの値は5です) The value of x is: 6 ``` -<<<<<<< HEAD - - - - + + + -`mut`キーワードを使うことで、`x`が束縛している値を`5`から`6`に変更できるようになりました。 -変数を可変にする方が、不変変数だけを使う実装よりも書きやすくなるケースもあるので、変数を可変にしたくなることもあるでしょう。 +`mut`キーワードを使われると、`x`が束縛している値を`5`から`6`に変更できます。 +変数を可変にする方が、不変変数だけがあるよりも書きやすくなるので、変数を可変にしたくなることもあるでしょう。 - + 考えるべきトレードオフはバグの阻止以外にも、いくつかあります。例えば、大きなデータ構造を使う場合などです。 インスタンスを可変にして変更できるようにする方が、いちいちインスタンスをコピーして新しくメモリ割り当てされたインスタンスを返すよりも速くなります。 -小規模なデータ構造なら、新規インスタンスを生成して、もっと関数型っぽいコードを書く方が中身を把握しやすくなるため、 +小規模なデータ構造なら、新規インスタンスを生成して、もっと関数型っぽいコードを書く方が通して考えやすくなるため、 低パフォーマンスは、その簡潔性を得るのに足りうるペナルティになるかもしれません。 -======= -We’re allowed to change the value that `x` binds to from `5` to `6` when `mut` -is used. In some cases, you’ll want to make a variable mutable because it makes -the code more convenient to write than if it had only immutable variables. - -There are multiple trade-offs to consider in addition to the prevention of -bugs. For example, in cases where you’re using large data structures, mutating -an instance in place may be faster than copying and returning newly allocated -instances. With smaller data structures, creating new instances and writing in -a more functional programming style may be easier to think through, so lower -performance might be a worthwhile penalty for gaining that clarity. ->>>>>>> fork_master_master ### 変数と定数(constants)の違い -<<<<<<< HEAD - - - + + + 変数の値を変更できないようにするといえば、他の多くの言語も持っている別のプログラミング概念を思い浮かべるかもしれません: -*定数*です。不変変数のように、定数も名前に紐付き、変更することが叶わない値のことですが、 +*定数*です。不変変数のように、定数は名前に紐付き、変更することが叶わない値のことですが、 定数と変数の間にはいくつかの違いがあります。 - - -======= -Being unable to change the value of a variable might have reminded you of -another programming concept that most other languages have: *constants*. Like -immutable variables, constants are values that are bound to a name and are not -allowed to change, but there are a few differences between constants and -variables. - -First, you aren’t allowed to use `mut` with constants. Constants aren’t just -immutable by default—they’re always immutable. - -You declare constants using the `const` keyword instead of the `let` keyword, -and the type of the value *must* be annotated. We’re about to cover types and -type annotations in the next section, “Data Types,” so don’t worry about the -details right now. Just know that you must always annotate the type. ->>>>>>> fork_master_master + + まず、定数には`mut`キーワードは使えません: 定数は標準で不変であるだけでなく、常に不変なのです。 -<<<<<<< HEAD - + - + 定数は`let`キーワードの代わりに、`const`キーワードで宣言し、値の型は*必ず*注釈しなければなりません。 型と型注釈については次のセクション、「データ型」で解説する予定なので、その詳細については気にする必要はありません。 @@ -268,27 +192,18 @@ details right now. Just know that you must always annotate the type. 定数はどんなスコープでも定義できます。グローバルスコープも含めてね。なので、 いろんなところで使用される可能性のある値を定義するのに役に立ちます。 - + 最後の違いは、定数は定数式にしかセットすることが叶わないことです。関数呼び出し結果や、実行時に評価される値にはセットできません。 - - + + 定数の名前が`MAX_POINTS`で、値が100,000にセットされた定数定義の例をご覧ください。(Rustの定数の命名規則は、 全て大文字でアンダースコアで単語区切りすることです): -======= -The last difference is that constants may be set only to a constant expression, -not the result of a function call or any other value that could only be -computed at runtime. - -Here’s an example of a constant declaration where the constant’s name is -`MAX_POINTS` and its value is set to 100,000. (Rust’s constant naming -convention is to use all uppercase with underscores between words): ->>>>>>> fork_master_master ```rust const MAX_POINTS: u32 = 100_000; @@ -317,26 +232,17 @@ const MAX_POINTS: u32 = 100_000; ### (変数の)多重定義(shadowing) -<<<<<<< HEAD - - - - - - -======= -As you saw in the “Comparing the Guess to the Secret Number” section in Chapter -2, you can declare a new variable with the same name as a previous variable, -and the new variable shadows the previous variable. Rustaceans say that the -first variable is *shadowed* by the second, which means that the second -variable’s value is what appears when the variable is used. We can shadow a -variable by using the same variable’s name and repeating the use of the `let` -keyword as follows: ->>>>>>> fork_master_master - -第2章の数当てゲームのチュートリアルで見たように、前に定義した変数と同じ名前の変数を新しく宣言でき、 -新しい変数は、前の変数を*上書き*(shadow)します。Rust市民はこれを最初の変数は、 -2番目の変数に*上書き*されたと言い、この変数を使用した際に、2番目の変数の値が得られるということです。 + + + + + + + + +第2章の「秘密の数字と予想を比較する」節で見たように、前に定義した変数と同じ名前の変数を新しく宣言でき、 +新しい変数は、前の変数を上書き(shadow)します。Rust市民はこれを最初の変数は、 +2番目の変数に*上書き*されたと言い、この変数を使用した際に、2番目の変数の値が現れるということです。 以下のようにして、同じ変数名を用いて変数を上書きし、`let`キーワードの使用を繰り返します: @@ -355,24 +261,16 @@ fn main() { } ``` -<<<<<<< HEAD - - - + + + このプログラムはまず、`x`を`5`という値に束縛します。それから`let x =`を繰り返すことで`x`を上書きし、 元の値に`1`を加えることになるので、`x`の値は、`6`になります。 3番目の`let`文も`x`を上書きし、以前の値に`2`をかけることになるので、`x`の最終的な値は`12`になります。 このプログラムを走らせたら、以下のように出力するでしょう: -======= -This program first binds `x` to a value of `5`. Then it shadows `x` by -repeating `let x =`, taking the original value and adding `1` so the value of -`x` is then `6`. The third `let` statement also shadows `x`, multiplying the -previous value by `2` to give `x` a final value of `12`. When we run this -program, it will output the following: ->>>>>>> fork_master_master ```text $ cargo run @@ -382,19 +280,19 @@ $ cargo run The value of x is: 12 ``` -<<<<<<< HEAD - - - - + + + + + -これは、変数を`mut`にするのとは違います。なぜなら、`let`キーワードを再度使わない限り、 -誤ってこの変数に再代入を試みようものなら、コンパイルエラーが出るからです。値にちょっとした加工は加えられますが、 -その加工が終わったら、変数は不変になるわけです。 +シャドーイングは、変数を`mut`にするのとは違います。なぜなら、`let`キーワードを使わずに、 +誤ってこの変数に再代入を試みようものなら、コンパイルエラーが出るからです。`let`を使うことで、 +値にちょっとした加工は加えられますが、その加工が終わったら、変数は不変になるわけです。 - + @@ -402,27 +300,13 @@ The value of x is: 12 値の型を変えつつ、同じ変数名を使いまわせることです。例えば、 プログラムがユーザに何らかのテキストに対して空白文字を入力することで何個分のスペースを表示したいかを尋ねるとします。 ただ、実際にはこの入力を数値として保持したいとしましょう: -======= -Shadowing is different than marking a variable as `mut`, because we’ll get a -compile-time error if we accidentally try to reassign to this variable without -using the `let` keyword. By using `let`, we can perform a few transformations -on a value but have the variable be immutable after those transformations have -been completed. - -The other difference between `mut` and shadowing is that because we’re -effectively creating a new variable when we use the `let` keyword again, we can -change the type of the value but reuse the same name. For example, say our -program asks a user to show how many spaces they want between some text by -inputting space characters, but we really want to store that input as a number: ->>>>>>> fork_master_master ```rust let spaces = " "; let spaces = spaces.len(); ``` -<<<<<<< HEAD - + @@ -434,14 +318,6 @@ let spaces = spaces.len(); 異なる名前を思いつく必要がなくなるわけです。`spaces_str`と`spaces_num`などですね; 代わりに、 よりシンプルな`spaces`という名前を再利用できるわけです。一方で、この場合に`mut`を使おうとすると、 以下に示した通りですが、コンパイルエラーになるわけです: -======= -This construct is allowed because the first `spaces` variable is a string type -and the second `spaces` variable, which is a brand-new variable that happens to -have the same name as the first one, is a number type. Shadowing thus spares us -from having to come up with different names, such as `spaces_str` and -`spaces_num`; instead, we can reuse the simpler `spaces` name. However, if we -try to use `mut` for this, as shown here, we’ll get a compile-time error: ->>>>>>> fork_master_master ```rust,ignore let mut spaces = " "; diff --git a/second-edition/src/ch03-02-data-types.md b/second-edition/src/ch03-02-data-types.md index d37c7faaa..53a14e0b0 100644 --- a/second-edition/src/ch03-02-data-types.md +++ b/second-edition/src/ch03-02-data-types.md @@ -1,58 +1,37 @@ -<<<<<<< HEAD ## データ型 - - - - + + + Rustにおける値は全て、何らかの*型*になり、コンパイラがどんなデータが指定されているか知れるので、 -そのデータの取り扱い方も把握できるというわけです。この節では、言語に組み込まれている種々の型について、 -見ていきましょう。型を二分割しましょう: スカラー型と複合型です。 +そのデータの取り扱い方も把握できるというわけです。2種のデータ型のサブセットを見ましょう: スカラー型と複合型です。 - - - - - - + + + + + + -この節を通して、Rustは*静的型付け*言語であることを弁えておいてください。つまり、 +Rustは*静的型付け*言語であることを弁えておいてください。つまり、 コンパイル時に全ての変数の型が判明している必要があるということです。コンパイラは通常、値と使用方法に基づいて、 使用したい型を推論してくれます。複数の型が推論される可能性がある場合、そう例えば、 -第2章で`parse`メソッドを使って`String`型を数値型に変換した時のような場合には、型注釈をつけなければいけません。 -以下のようにね: -======= -Every value in Rust is of a certain *data type*, which tells Rust what kind of -data is being specified so it knows how to work with that data. We’ll look at -two data type subsets: scalar and compound. - -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 -Chapter 2, we must add a type annotation, like this: ->>>>>>> fork_master_master +第2章の「秘密の数字と予想を比較する」節で`parse`メソッドを使って`String`型を数値型に変換した時のような場合には、 +型注釈をつけなければいけません。以下のようにね: ```rust let guess: u32 = "42".parse().expect("Not a number!"); // 数字ではありません! ``` -<<<<<<< HEAD - + ここで型注釈を付けなければ、コンパイラは以下のエラーを表示し、これは可能性のある型のうち、 どの型を使用したいのかを知るのに、コンパイラがプログラマからもっと情報を得る必要があることを意味します: -======= -If we don’t add the type annotation here, Rust will display the following -error, which means the compiler needs more information from us to know which -type we want to use: ->>>>>>> fork_master_master ```text error[E0282]: type annotations needed @@ -67,84 +46,62 @@ error[E0282]: type annotations needed (注釈: 型注釈、またはジェネリクス引数束縛が必要です) ``` -<<<<<<< HEAD - + -いろいろなデータ型について議論するにつれて、様々な型注釈を目撃することになるでしょう。 +他のデータ型についても、様々な型注釈を目撃することになるでしょう。 ### スカラー型 -======= -You’ll see different type annotations for other data types. ->>>>>>> fork_master_master - - - + + -<<<<<<< HEAD スカラー型は、単独の値を表します。Rustには主に4つのスカラー型があります: -整数、浮動小数点数、論理値、最後に文字です。他のプログラミング言語でも、これらの型を見かけたことはあるでしょうが、 -Rustでの動作方法について見ていきましょう。 -======= -A *scalar* type represents a single value. Rust has four primary scalar types: -integers, floating-point numbers, Booleans, and characters. You may recognize -these from other programming languages. Let’s jump into how they work in Rust. ->>>>>>> fork_master_master +整数、浮動小数点数、論理値、最後に文字です。他のプログラミング言語でも、これらの型を見かけたことはあるでしょう。 +Rustでの動作方法に飛び込みましょう。 -<<<<<<< HEAD #### 整数型 -======= -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. ->>>>>>> fork_master_master - - - - - - - -<<<<<<< HEAD -整数とは、小数部分のない数値のことです。この章の前半で一つの整数型を使用しました。`u32`型です。 + + + + + + + +整数とは、小数部分のない数値のことです。第2章で一つの整数型を使用しました。`u32`型です。 この型定義は、紐付けられる値が、符号なし整数(符号付き整数は`u`ではなく、`i`で始まります)になり、 これは、32ビット分のサイズを取ります。表3-1は、Rustの組み込み整数型を表示しています。 -符号付きと符号なし欄の各バリアント(例: *i16*)を使用して、整数値の型を宣言することができます。 +符号付きと符号なし欄の各バリアント(例: `i16`)を使用して、整数値の型を宣言することができます。 表3-1: Rustの整数型 - - - - - - - - -| 大きさ | 符号付き | 符号なし | -|--------|--------|----------| -| 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` | +| arch | `isize` | `usize` | - - + + @@ -153,7 +110,7 @@ value. -各バリアントは、符号付きか符号なしかを選べ、明示的なサイズを持ちます。符号付きと符号なしの特性は、 +各バリアントは、符号付きか符号なしかを選べ、明示的なサイズを持ちます。*符号付き*と*符号なし*は、 数値が正負を持つかどうかを示します。つまり、数値が符号を持つ必要があるかどうか(符号付き)、または、 絶対に正数にしかならず符号なしで表現できるかどうか(符号なし)です。これは、数値を紙に書き下すのと似ています: 符号が問題になるなら、数値はプラス記号、またはマイナス記号とともに表示されます; しかしながら、 @@ -162,13 +119,13 @@ value. まあ要するに、この解説は、この本の範疇外というわけです)。 - + 各符号付きバリアントは、-(2n - 1)から2n - 1 - 1までの数値を保持でき、 -ここで`n`はこのバリアントが使用するビット数です。以上から、`i8`型は-(27)から27 - 1まで、 +ここで*n*はこのバリアントが使用するビット数です。以上から、`i8`型は-(27)から27 - 1まで、 つまり、-128から127までを保持できます。符号なしバリアントは、0から2n - 1までを保持できるので、 `u8`型は、0から28 - 1までの値、つまり、0から255までを保持できることになります。 @@ -199,45 +156,7 @@ value. -| 数値リテラル | 例 | -======= -| Length | Signed | Unsigned | -|--------|---------|----------| -| 8-bit | `i8` | `u8` | -| 16-bit | `i16` | `u16` | -| 32-bit | `i32` | `u32` | -| 64-bit | `i64` | `u64` | -| arch | `isize` | `usize` | - -Each variant can be either signed or unsigned and has an explicit size. -*Signed* and *unsigned* refer to whether it’s possible for the number to be -negative or positive—in other words, whether the number needs to have a sign -with it (signed) or whether it will only ever be positive and can therefore be -represented without a sign (unsigned). It’s like writing numbers on paper: when -the sign matters, a number is shown with a plus sign or a minus sign; however, -when it’s safe to assume the number is positive, it’s shown with no sign. -Signed numbers are stored using two’s complement representation (if you’re -unsure what this is, you can search for it online; an explanation is outside -the scope of this book). - -Each signed variant can store numbers from -(2n - 1) to 2n - -1 - 1 inclusive, where *n* is the number of bits that variant uses. So an -`i8` can store numbers from -(27) to 27 - 1, which equals --128 to 127. Unsigned variants can store numbers from 0 to 2n - 1, -so a `u8` can store numbers from 0 to 28 - 1, which equals 0 to 255. - -Additionally, the `isize` and `usize` types depend on the kind of computer your -program is running on: 64 bits if you’re on a 64-bit architecture and 32 bits -if you’re on a 32-bit architecture. - -You can write integer literals in any of the forms shown in Table 3-2. Note -that all number literals except the byte literal allow a type suffix, such as -`57u8`, and `_` as a visual separator, such as `1_000`. - -Table 3-2: Integer Literals in Rust - -| Number literals | Example | ->>>>>>> fork_master_master +| 数値リテラル | 例 | |------------------|---------------| | 10進数 | `98_222` | | 16進数 | `0xff` | @@ -246,30 +165,23 @@ that all number literals except the byte literal allow a type suffix, such as | バイト (`u8`だけ) | `b'A'` | - - - + + + では、どの整数型を使うべきかはどう把握すればいいのでしょうか?もし確信が持てないのならば、 Rustの基準型は一般的にいい選択肢になります。整数型の基準は`i32`型です: 64ビットシステム上でも、 -普通最速になります。`isize`と`usize`を使う主な状況は、何らかのコレクションにアクセスすることです。 +この型が普通最速になります。`isize`と`usize`を使う主な状況は、何らかのコレクションにアクセスすることです。 #### 浮動小数点型 -<<<<<<< HEAD -======= -So how do you know which type of integer to use? If you’re unsure, Rust’s -defaults are generally good choices, and integer types default to `i32`: this -type is generally the fastest, even on 64-bit systems. The primary situation in -which you’d use `isize` or `usize` is when indexing some sort of collection. ->>>>>>> fork_master_master Rustにはさらに、*浮動小数点数*に対しても、2種類の基本型があり、浮動小数点数とは10進小数のことです。 Rustの浮動小数点型は、`f32`と`f64`で、それぞれ32ビットと64ビットサイズです。基準型は`f64`です。 @@ -316,22 +228,16 @@ Rustにも期待されうる標準的な数学演算が全数値型に対して - -<<<<<<< HEAD + -======= -Rust supports the basic mathematical operations you’d expect for all of the -number types: addition, subtraction, multiplication, division, and remainder. -The following code shows how you’d use each one in a `let` statement: ->>>>>>> fork_master_master - + - + - + @@ -401,25 +307,18 @@ fn main() { 論理値を消費する主な手段は、条件式です。例えば、`if`式などですね。`if`式のRustでの動作方法については、 「フロー制御」節で解説します。 -<<<<<<< HEAD -======= -So far we’ve worked only with numbers, but Rust supports letters too. Rust’s -`char` type is the language’s most primitive alphabetic type, and the following -code shows one way to use it. (Note that the `char` type is specified with -single quotes, as opposed to strings, which use double quotes.) ->>>>>>> fork_master_master #### 文字型 - + - - + + ここまで、数値型のみ扱ってきましたが、Rustには文字も用意されています。Rustの`char`型は、 言語の最も基本的なアルファベット型であり、以下のコードでその使用方法の一例を見ることができます。 -`char`は、ダブルクォーテーションマークを使用する文字列に対して、シングルクォートで指定されることに注意してください: +(`char`は、ダブルクォーテーションマークを使用する文字列に対して、シングルクォートで指定されることに注意してください。) @@ -433,52 +332,34 @@ fn main() { } ``` -<<<<<<< HEAD - - - + + + - - + Rustの`char`型は、ユニコードのスカラー値を表します。これはつまり、アスキーよりもずっとたくさんのものを表せるということです。 -アクセント文字、中国語/日本語/韓国語表意文字(`脚注`: 漢字のことだと思われる)、 -絵文字、ゼロ幅スペースは、全てRustでは、有効な`char`型になります。ユニコードスカラー値は、 +アクセント文字、中国語、日本語、韓国語表意文字(`脚注`: 漢字のことだと思われる); +絵文字; ゼロ幅スペースは、全てRustでは、有効な`char`型になります。ユニコードスカラー値は、 `U+0000`から`U+D7FF`までと`U+E0000`から`U+10FFFF`までの範囲になります。 ところが、「文字」は実はユニコードの概念ではないので、文字とは何かという人間としての直観は、 -Rustにおける`char`型が何かとは合致しない可能性があります。この話題については、第8章の「文字列」節で詳しく議論しましょう。 +Rustにおける`char`型が何かとは合致しない可能性があります。この話題については、第8章の「文字列」で詳しく議論しましょう。 ### 複合型 - - -======= -Rust’s `char` type represents a Unicode Scalar Value, which means it can -represent a lot more than just ASCII. Accented letters; Chinese, Japanese, and -Korean ideographs; emoji; and zero-width spaces are all valid `char` types in -Rust. Unicode Scalar Values range from `U+0000` to `U+D7FF` and `U+E000` to -`U+10FFFF` inclusive. However, a “character” isn’t really a concept in Unicode, -so your human intuition for what a “character” is may not match up with what a -`char` is in Rust. We’ll discuss this topic in detail in “Strings” in Chapter 8. ->>>>>>> fork_master_master - -*複合型*により、複数の型の値を一つの型にまとめることができます。Rustには、 -2種類の基本的な複合型があります: タプルと配列です。 + + -<<<<<<< HEAD - +*複合型*により、複数の値を一つの型にまとめることができます。Rustには、 +2種類の基本的な複合型があります: タプルと配列です。 -#### 値をタプルにまとめ上げる -======= -*Compound types* can group multiple values into one type. Rust has two -primitive compound types: tuples and arrays. + -#### The Tuple Type ->>>>>>> fork_master_master +#### タプル型 @@ -503,18 +384,12 @@ fn main() { } ``` -<<<<<<< HEAD - + 変数`tup`は、タプル全体に束縛されています。なぜなら、タプルは、一つの複合要素と考えられるからです。 タプルから個々の値を取り出すには、パターンマッチングを使用して分解することができます。以下のように: -======= -The variable `tup` binds to the entire tuple, because a tuple is considered a -single compound element. To get the individual values out of a tuple, we can -use pattern matching to destructure a tuple value, like this: ->>>>>>> fork_master_master @@ -541,20 +416,14 @@ fn main() { この過程は、*分解*と呼ばれます。単独のタプルを破壊して三分割しているからです。最後に、 プログラムは`y`変数の値を出力し、`6.4`と表示されます。 - - - + + + パターンマッチングを通しての分解の他にも、アクセスしたい値の番号をピリオド(`.`)に続けて書くことで、 タプルの要素に直接アクセスすることもできます。例です: -<<<<<<< HEAD -======= -In addition to destructuring through pattern matching, we can access a tuple -element directly by using a period (`.`) followed by the index of the value we -want to access. For example: ->>>>>>> fork_master_master ファイル名: src/main.rs @@ -574,21 +443,12 @@ fn main() { -<<<<<<< HEAD このプログラムは、新しいタプル`x`を作成し、添え字アクセスで各要素に対して新しい変数も作成しています。 多くのプログラミング言語同様、タプルの最初の添え字は0です。 - -======= -#### The Array Type + -Another way to have a collection of multiple values is with an *array*. Unlike -a tuple, every element of an array must have the same type. Arrays in Rust are -different from arrays in some other languages because arrays in Rust have a -fixed length: once declared, they cannot grow or shrink in size. ->>>>>>> fork_master_master - -#### 配列 +#### 配列型 @@ -614,29 +474,18 @@ fn main() { } ``` -<<<<<<< HEAD - - - - - - -配列は、ヒープよりもスタック(スタックとヒープについては第4章で(つまび)らかに議論します)にデータのメモリを確保したい時、 -または、常に固定長の要素があることを確認したい時に有効です。ただ、配列は、ベクタ型ほど柔軟ではありません。 -ベクタ型も、標準ライブラリによって提供されている似たようなコレクション型で、こちらは、 -サイズを伸縮させることが*できます*。配列とベクタ型、どちらを使うべきか確信が持てない時は、 -おそらくベクタ型を使うべきです: 第8章でベクタ型について詳細に議論します。 -======= -Arrays are useful when you want your data allocated on the stack rather than -the heap (we will discuss the stack and the heap more in Chapter 4), or when -you want to ensure you always have a fixed number of elements. An array isn’t -as flexible as the vector type, though. A vector is a similar collection type -provided by the standard library that *is* allowed to grow or shrink in size. -If you’re unsure whether to use an array or a vector, you should probably use a -vector. Chapter 8 discusses vectors in more detail. ->>>>>>> fork_master_master + + + + + + +配列は、ヒープよりもスタック(スタックとヒープについては第4章で(つまび)らかに議論します)にデータのメモリを確保したい時、または、常に固定長の要素があることを確認したい時に有効です。 +ただ、配列は、ベクタ型ほど柔軟ではありません。ベクタも、標準ライブラリによって提供されている似たようなコレクション型で、 +こちらは、サイズを伸縮させることが*できます*。配列とベクタ型、どちらを使うべきか確信が持てない時は、 +おそらくベクタ型を使うべきです。第8章でベクタについて詳細に議論します。 @@ -655,13 +504,8 @@ let months = ["January", "February", "March", "April", "May", "June", "July", ##### 配列の要素にアクセスする -<<<<<<< HEAD - + -======= -An array is a single chunk of memory allocated on the stack. You can access -elements of an array using indexing, like this: ->>>>>>> fork_master_master 配列は、スタック上に確保される一塊のメモリです。添え字によって、 配列の要素にアクセスすることができます。こんな感じ: @@ -728,7 +572,6 @@ thread '
' panicked at 'index out of bounds: the len is 5 but the index is note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` -<<<<<<< HEAD @@ -749,17 +592,4 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. これは、実際に稼働しているRustの安全機構の最初の例になります。低レベル言語の多くでは、 この種のチェックは行われないため、間違った添え字を与えると、無効なメモリにアクセスできてしまいます。 Rustでは、メモリアクセスを許可し、処理を継続する代わりに即座にプログラムを終了することで、 -この種のエラーからプログラマを保護しています。Rustのエラー処理については、第9章で詳しく議論します。 -======= -The compilation didn’t produce any errors, but the program resulted in a -*runtime* error and didn’t exit successfully. When you attempt to access an -element using indexing, Rust will check that the index you’ve specified is less -than the array length. If the index is greater than the length, Rust will -*panic*, which is the term Rust uses when a program exits with an error. - -This is the first example of Rust’s safety principles in action. In many -low-level languages, this kind of check is not done, and when you provide an -incorrect index, invalid memory can be accessed. Rust protects you against this -kind of error by immediately exiting instead of allowing the memory access and -continuing. Chapter 9 discusses more of Rust’s error handling. ->>>>>>> fork_master_master +この種のエラーからプログラマを保護しています。Rustのエラー処理については、第9章でもっと議論します。 diff --git a/second-edition/src/ch03-03-how-functions-work.md b/second-edition/src/ch03-03-how-functions-work.md index e5c5f8e43..8c3e6ff07 100644 --- a/second-edition/src/ch03-03-how-functions-work.md +++ b/second-edition/src/ch03-03-how-functions-work.md @@ -1,10 +1,6 @@ -<<<<<<< HEAD - -======= -## Functions ->>>>>>> fork_master_master + -## 関数の動作方法 +## 関数 @@ -88,12 +84,12 @@ Another function. ### 関数の引数 - - - - - - + + + + + + 関数は、引数を持つようにも定義できます。引数とは、関数シグニチャの一部になる特別な変数のことです。 関数に引数があると、引数の位置に実際の値を与えることができます。技術的にはこの実際の値は @@ -103,17 +99,7 @@ Another function. -<<<<<<< HEAD 以下の書き直した`another_function`では、Rustの仮引数がどんな見た目なのかを示しています: -======= -Functions can also be defined to have *parameters*, which are special variables -that are part of a function’s signature. When a function has parameters, you -can provide it with concrete values for those parameters. Technically, the -concrete values are called *arguments*, but in casual conversation, people tend -to use the words *parameter* and *argument* interchangeably for either the -variables in a function’s definition or the concrete values passed in when you -call a function. ->>>>>>> fork_master_master @@ -180,32 +166,21 @@ fn another_function(x: i32, y: i32) { } ``` -<<<<<<< HEAD - - - + + + この例では、2引数の関数を生成しています。そして、引数はどちらも`i32`型です。それからこの関数は、 仮引数の値を両方出力します。関数引数は、全てが同じ型である必要はありません。今回は、 偶然同じになっただけです。 - - + + このコードを走らせてみましょう。今、*function*プロジェクトの*src/main.rs*ファイルに記載されているプログラムを先ほどの例と置き換えて、 `cargo run`で走らせてください: -======= -This example creates a function with two parameters, both of which are `i32` -types. The function then prints the values in both of its parameters. Note that -function parameters don’t all need to be the same type, they just happen to be -in this example. - -Let’s try running this code. Replace the program currently in your *functions* -project’s *src/main.rs* file with the preceding example and run it using `cargo -run`: ->>>>>>> fork_master_master ```text $ cargo run @@ -228,7 +203,7 @@ The value of y is: 6 - + @@ -239,17 +214,7 @@ The value of y is: 6 これは理解しておくべき重要な差異になります。他の言語にこの差異はありませんので、文と式がなんなのかと、 その違いが関数本体にどんな影響を与えるかを見ていきましょう。 -<<<<<<< HEAD -======= -Function bodies are made up of a series of statements optionally ending in an -expression. So far, we’ve only covered functions without an ending expression, -but you have seen an expression as part of statements. Because Rust is an -expression-based language, this is an important distinction to understand. -Other languages don’t have the same distinctions, so let’s look at what -statements and expressions are and how their differences affect the bodies of -functions. ->>>>>>> fork_master_master ### 文と式 @@ -276,8 +241,7 @@ fn main() { } ``` -<<<<<<< HEAD - + リスト3-1: 1文を含む`main`関数宣言 @@ -285,9 +249,6 @@ fn main() { 関数定義も文になります。つまり、先の例は全体としても文になるわけです。 -======= -Listing 3-1: A `main` function declaration containing one statement ->>>>>>> fork_master_master @@ -323,12 +284,11 @@ error: expected expression, found statement (`let`) (注釈: `let`を使う変数宣言は、文です) ``` -<<<<<<< HEAD - - - - + + + + この`let y = 6`という文は値を返さないので、`x`を束縛する相手がないわけです。これは、 CやRubyなどの言語とは異なる動作です。CやRubyでは、代入は代入値を返します。これらの言語では、 @@ -338,29 +298,14 @@ CやRubyなどの言語とは異なる動作です。CやRubyでは、代入は - + -======= -The `let y = 6` statement does not return a value, so there isn’t anything for -`x` to bind to. This is different from what happens in other languages, such as -C and Ruby, where the assignment returns the value of the assignment. In those -languages, you can write `x = y = 6` and have both `x` and `y` have the value -`6`; that is not the case in Rust. - -Expressions evaluate to something and make up most of the rest of the code that -you’ll write in Rust. Consider a simple math operation, such as `5 + 6`, which -is an expression that evaluates to the value `11`. Expressions can be part of -statements: in Listing 3-1, the `6` in the statement `let y = 6;` is an -expression that evaluates to the value `6`. Calling a function is an -expression. Calling a macro is an expression. The block that we use to create -new scopes, `{}`, is an expression, for example: ->>>>>>> fork_master_master 式は何かに評価され、これからあなたが書くRustコードの多くを構成します。 簡単な数学演算(`5 + 6`など)を思い浮かべましょう。この例は、値`11`に評価される式です。式は文の一部になりえます: -`let y = 6`という文を含むリスト3-3では、`6`は値`6`に評価される式です。関数呼び出しも式です。マクロ呼び出しも式です。 +リスト3-1において、`let y = 6`という文の`6`は値`6`に評価される式です。関数呼び出しも式です。マクロ呼び出しも式です。 新しいスコープを作る際に使用するブロック(`{}`)も式です: @@ -391,25 +336,16 @@ fn main() { } ``` -<<<<<<< HEAD - - - - -======= -is a block that, in this case, evaluates to `4`. That value gets bound to `y` -as part of the `let` statement. Note the `x + 1` line without a semicolon at -the end, which is unlike most of the lines you’ve seen so far. Expressions do -not include ending semicolons. If you add a semicolon to the end of an -expression, you turn it into a statement, which will then not return a value. -Keep this in mind as you explore function return values and expressions next. ->>>>>>> fork_master_master + + + + 今回の場合、`4`に評価されるブロックです。その値が、`let`文の一部として`y`に束縛されます。 今まで見かけてきた行と異なり、文末にセミコロンがついていない`x + 1`の行に気をつけてください。 -式は終端にセミコロンを、含みません。式の終端にセミコロンを付けたら、文に変えてしまいます。そして、文は値を返しません。 +式は終端にセミコロンを含みません。式の終端にセミコロンを付けたら、文に変えてしまいます。そして、文は値を返しません。 次に関数の戻り値や式を見ていく際にこのことを肝に命じておいてください。 @@ -476,21 +412,16 @@ The value of x is: 5 let x = 5; ``` -<<<<<<< HEAD - - -======= -Second, the `five` function has no parameters and defines the type of the -return value, but the body of the function is a lonely `5` with no semicolon -because it’s an expression whose value we want to return. - -Let’s look at another example: ->>>>>>> fork_master_master + 2番目に、`five`関数は仮引数をもたず、戻り値型を定義していますが、関数本体はセミコロンなしの`5`単独です。 -なぜなら、これが返したい値になる式だからです。もう一つ例を見てみましょう: +なぜなら、これが返したい値になる式だからです。 + + + +もう一つ別の例を見ましょう: @@ -508,19 +439,12 @@ fn plus_one(x: i32) -> i32 { } ``` -<<<<<<< HEAD - + - - -このコードを走らせると、`The value of x is: 6`と出力されるでしょう。では、 -`x + 1`を含む行の終端にセミコロンを付けて、式から文に変えてみたら、どうなるでしょうか? -エラーになるでしょう: -======= -Running this code will print `The value of x is: 6`. But if we place a -semicolon at the end of the line containing `x + 1`, changing it from an -expression to a statement, we’ll get an error. ->>>>>>> fork_master_master + + +このコードを走らせると、`The value of x is: 6`と出力されるでしょう。しかし、 +`x + 1`を含む行の終端にセミコロンを付けて、式から文に変えたら、エラーになるでしょう: diff --git a/second-edition/src/ch03-05-control-flow.md b/second-edition/src/ch03-05-control-flow.md index 29d8b7138..70dc13a9a 100644 --- a/second-edition/src/ch03-05-control-flow.md +++ b/second-edition/src/ch03-05-control-flow.md @@ -1,36 +1,22 @@ -<<<<<<< HEAD ## フロー制御 -======= -Deciding whether or not to run some code depending on if a condition is true -and deciding to run some code repeatedly while a condition is true are basic -building blocks in most programming languages. The most common constructs that -let you control the flow of execution of Rust code are `if` expressions and -loops. ->>>>>>> fork_master_master - - - + + + -<<<<<<< HEAD 条件が真かどうかによってコードを走らせるかどうかを決定したり、 条件が真の間繰り返しコードを走らせるか決定したりすることは、多くのプログラミング言語において、基本的な構成ブロックです。 Rustコードの実行フローを制御する最も一般的な文法要素は、`if`式とループです。 -======= -An `if` expression allows you to branch your code depending on conditions. You -provide a condition and then state, “If this condition is met, run this block -of code. If the condition is not met, do not run this block of code.” ->>>>>>> fork_master_master ### `if`式 - + @@ -61,7 +47,6 @@ fn main() { -<<<<<<< HEAD @@ -69,42 +54,27 @@ fn main() { - - - - - + `if`式は全て、キーワードの`if`から始め、条件式を続けます。今回の場合、 条件式は変数`number`が5未満の値になっているかどうかをチェックします。 条件が真の時に実行したい一連のコードを条件式の直後に波かっこで包んで配置します。`if`式の条件式と紐付けられる一連のコードは、 時として*アーム*と呼ばれることがあります。 -第2章の「予想と秘密の数字を比較する」の節で議論した`match`式のアームのようですね。オプションとして、 -`else`式を含むこともでき(ここではそうしています)、これによりプログラムは、 +第2章の「予想と秘密の数字を比較する」の節で議論した`match`式のアームのようですね。 + + + + + + + +オプションとして、`else`式を含むこともでき(ここではそうしています)、これによりプログラムは、 条件式が偽になった時に実行するコードを与えられることになります。仮に、`else`式を与えずに条件式が偽になったら、 プログラムは単に`if`ブロックを無視して次のコードを実行しにいきます。 このコードを走らせてみましょう; 以下のような出力を目の当たりにするはずです: -======= -All `if` expressions start with the keyword `if`, which is followed by a -condition. In this case, the condition checks whether or not the variable -`number` has a value less than 5. The block of code we want to execute if the -condition is true is placed immediately after the condition inside curly -brackets. Blocks of code associated with the conditions in `if` expressions are -sometimes called *arms*, just like the arms in `match` expressions that we -discussed in the “Comparing the Guess to the Secret Number” section of -Chapter 2. - -Optionally, we can also include an `else` expression, which we chose -to do here, to give the program an alternative block of code to execute should -the condition evaluate to false. If you don’t provide an `else` expression and -the condition is false, the program will just skip the `if` block and move on -to the next bit of code. - -Try running this code; you should see the following output: ->>>>>>> fork_master_master ```text $ cargo run @@ -135,17 +105,11 @@ $ cargo run condition was false ``` -<<<<<<< HEAD - - -======= -It’s also worth noting that the condition in this code *must* be a `bool`. If -the condition isn’t a `bool`, we’ll get an error. For example: ->>>>>>> fork_master_master + このコード内の条件式は、`bool`型で*なければならない*ことにも触れる価値があります。 -条件式が、`bool`型でない時は、エラーになります。例として、以下のコードを走らせてみましょう: +条件式が、`bool`型でない時は、エラーになります。例です: @@ -179,26 +143,17 @@ error[E0308]: mismatched types found type `{integer}` ``` -<<<<<<< HEAD - - - + + + -このエラーは、コンパイラは`bool`型を予期していたのに、整数だったことを示唆しています。Rustでは、 -論理値以外の値が、自動的に論理値に変換されることはありません。 -RubyやJavaScriptなどの言語とは異なります。明示的に必ず`if`には条件式として、`論理値`を与えなければなりません。 +このエラーは、コンパイラは`bool`型を予期していたのに、整数だったことを示唆しています。 +RubyやJavaScriptなどの言語とは異なり、Rustでは、論理値以外の値が、自動的に論理値に変換されることはありません。 +明示的に必ず`if`には条件式として、`論理値`を与えなければなりません。 例えば、数値が`0`以外の時だけ`if`のコードを走らせたいなら、以下のように`if`式を変更することができます: -======= -The error indicates that Rust expected a `bool` but got an integer. Unlike -languages such as Ruby and JavaScript, Rust will not automatically try to -convert non-Boolean types to a Boolean. You must be explicit and always provide -`if` with a Boolean as its condition. If we want the `if` code block to run -only when a number is not equal to `0`, for example, we can change the `if` -expression to the following: ->>>>>>> fork_master_master @@ -218,21 +173,14 @@ fn main() { このコードを実行したら、`number was something other than zero`と表示されるでしょう。 - + -#### `else if`で複数の条件 +#### `else if`で複数の条件を扱う -<<<<<<< HEAD - + `if`と`else`を組み合わせて`else if`式にすることで複数の条件を持たせることもできます。例です: -======= -#### Handling Multiple Conditions with `else if` - -You can have multiple conditions by combining `if` and `else` in an `else if` -expression. For example: ->>>>>>> fork_master_master @@ -271,51 +219,35 @@ $ cargo run number is divisible by 3 ``` -<<<<<<< HEAD - - - + + + このプログラムを実行すると、`if`式が順番に吟味され、最初に条件が真になった本体が実行されます。 6は2で割り切れるものの、`number is devisible by 2`や、 `else`ブロックの`number is not divisible by 4, 3, or 2`という出力はされないことに注目してください。 -その原因は、言語が最初の真条件のブロックのみを実行し、 +それは、言語が最初の真条件のブロックのみを実行し、 条件に合ったものが見つかったら、残りはチェックすらしないからです。 -======= -When this program executes, it checks each `if` expression in turn and executes -the first body for which the condition holds true. Note that even though 6 is -divisible by 2, we don’t see the output `number is divisible by 2`, nor do we -see the `number is not divisible by 4, 3, or 2` text from the `else` block. -That’s because Rust only executes the block for the first true condition, and -once it finds one, it doesn’t even check the rest. ->>>>>>> fork_master_master `else if`式を使いすぎると、コードがめちゃくちゃになってしまうので、1つ以上あるなら、 コードをリファクタリングしたくなるかもしれません。これらのケースに有用な`match`と呼ばれる、 強力なRustの枝分かれ文法要素については第6章で解説します。 -<<<<<<< HEAD - + #### `let`文内で`if`式を使う -======= -#### Using `if` in a `let` Statement - -Because `if` is an expression, we can use it on the right side of a `let` -statement, as in Listing 3-2: ->>>>>>> fork_master_master - + -`if`は式なので、`let`文の右辺に持ってくることができます。例はリスト3-2の通り: +`if`は式なので、`let`文の右辺に持ってくることができます。リスト3-2のようにね: @@ -403,12 +335,8 @@ error[E0308]: if and else have incompatible types 6 | | } else { 7 | | "six" 8 | | }; -<<<<<<< HEAD - | |_____^ expected integral variable, found reference - | (整数変数を予期しましたが、参照が見つかりました) -======= | |_____^ expected integral variable, found &str ->>>>>>> fork_master_master + | (整数変数を予期しましたが、&strが見つかりました) | = note: expected type `{integer}` found type `&str` @@ -517,38 +445,25 @@ again! #### `while`で条件付きループ -<<<<<<< HEAD - - - - + + + + プログラムにとってループ内で条件式を評価できると、有益なことがしばしばあります。条件が真の間、 -ループが走るわけです。条件が真でなくなった時に`break`を呼び出し、ループを終了します。 +ループが走るわけです。条件が真でなくなった時にプログラムは`break`を呼び出し、ループを終了します。 このタイプのループは、`loop`、`if`、`else`、`break`を組み合わせることでも実装できます; お望みなら、プログラムで試してみるのもいいでしょう。 -======= -It’s often useful for a program to evaluate a condition within a loop. While -the condition is true, the loop runs. When the condition ceases to be true, the -program calls `break`, stopping the loop. This loop type could be implemented -using a combination of `loop`, `if`, `else`, and `break`; you could try that -now in a program, if you’d like. - -However, this pattern is so common that Rust has a built-in language construct -for it, called a `while` loop. Listing 3-3 uses `while`: the program loops -three times, counting down each time, and then, after the loop, it prints -another message and exits. ->>>>>>> fork_master_master - - - + + + -しかし、このパターンは頻出するので、Rustにはそれ用の文法要素が用意されており、`while`ループと呼ばれます。 -以下の例では、`while`を使用しています: プログラムは3回ループし、それぞれカウントダウンします。 -そして、ループ後に別のメッセージを表示して終了します: +しかし、このパターンは頻出するので、Rustにはそれ用の文法要素が用意されていて、`while`ループと呼ばれます。 +リスト3-3は、`while`を使用しています: プログラムは3回ループし、それぞれカウントダウンします。 +それから、ループ後に別のメッセージを表示して終了します: @@ -569,35 +484,26 @@ fn main() { } ``` -<<<<<<< HEAD + + + +リスト3-3: 条件が真の間、コードを走らせる`while`ループを使用する + この文法要素により、`loop`、`if`、`else`、`break`を使った時に必要になるネストがなくなり、 より明確になります。条件が真の間、コードは実行されます; そうでなければ、ループを抜けます. -======= -Listing 3-3: Using a `while` loop to run code while a -condition holds true - -This construct eliminates a lot of nesting that would be necessary if you used -`loop`, `if`, `else`, and `break`, and it’s clearer. While a condition holds -true, the code runs; otherwise, it exits the loop. ->>>>>>> fork_master_master -<<<<<<< HEAD #### `for`でコレクションを覗き見る -======= -You could use the `while` construct to loop over the elements of a collection, -such as an array. For example, let’s look at Listing 3-4: ->>>>>>> fork_master_master - + -`while`要素を使って配列などのコレクションの要素を覗き見ることができます。例えば、リスト3-3を見てみましょう: +`while`要素を使って配列などのコレクションの要素を覗き見ることができます。例えば、リスト3-4を見ましょう: @@ -617,29 +523,19 @@ fn main() { } ``` -<<<<<<< HEAD - + -リスト3-3: `while`ループでコレクションの各要素を覗き見る +リスト3-4: `while`ループでコレクションの各要素を覗き見る - - + + ここで、コードは配列の要素を順番にカウントアップして覗いています。番号0から始まり、 配列の最終番号に到達するまでループします(つまり、`index < 5`が真でなくなる時です)。 このコードを走らせると、配列内の全要素が出力されます: -======= -Listing 3-4: Looping through each element of a collection -using a `while` loop - -Here, the code counts up through the elements in the array. It starts at index -`0`, and then loops until it reaches the final index in the array (that is, -when `index < 5` is no longer true). Running this code will print every element -in the array: ->>>>>>> fork_master_master ```text $ cargo run @@ -670,15 +566,10 @@ the value is: 50 コンパイラが実行時にループの各回ごとに境界値チェックを行うようなコードを追加するからです。 - + -<<<<<<< HEAD より効率的な対立案として、`for`ループを使ってコレクションの各アイテムに対してコードを実行することができます。 -`for`ループはリスト3-4のこんな見た目です: -======= -As a more concise alternative, you can use a `for` loop and execute some code -for each item in a collection. A `for` loop looks like this code in Listing 3-5: ->>>>>>> fork_master_master +`for`ループはリスト3-5のこんな見た目です: @@ -695,43 +586,28 @@ fn main() { } ``` -<<<<<<< HEAD - + リスト3-4: `for`ループを使ってコレクションの各要素を覗き見る - + -このコードを走らせたら、リスト3-5と同じ出力が得られるでしょう。より重要なのは、 +このコードを走らせたら、リスト3-4と同じ出力が得られるでしょう。より重要なのは、 コードの安全性を向上させ、配列の終端を超えてアクセスしたり、 終端に届く前にループを終えてアイテムを見逃してしまったりするバグの可能性を完全に排除したことです。 - + -例えば、リスト3-5のコードで、`a`配列からアイテムを1つ削除したのに、条件式を`while index < 4`にするのを忘れていたら、 +例えば、リスト3-4のコードで、`a`配列からアイテムを1つ削除したのに、条件式を`while index < 4`にするのを忘れていたら、 コードはパニックします。`for`ループを使っていれば、配列の要素数を変えても、 他のコードをいじることを覚えておく必要はなくなるわけです。 -======= -Listing 3-5: Looping through each element of a collection -using a `for` loop - -When we run this code, we’ll see the same output as in Listing 3-4. More -importantly, we’ve now increased the safety of the code and eliminated the -chance of bugs that might result from going beyond the end of the array or not -going far enough and missing some items. - -For example, in the code in Listing 3-4, if you removed an item from the `a` -array but forgot to update the condition to `while index < 4`, the code would -panic. Using the `for` loop, you wouldn’t need to remember to change any other -code if you changed the number of values in the array. ->>>>>>> fork_master_master @@ -774,10 +650,11 @@ fn main() { ## まとめ - - + + + -やりましたね!結構長い章でした: 変数とスカラー値、`if`式、そして、ループについて学びました! +やりましたね!結構長い章でした: 変数とスカラー値、複合データ型、関数、コメント、`if`式、そして、ループについて学びました! この章で議論した概念について経験を積みたいのであれば、以下のことをするプログラムを組んでみてください: @@ -785,17 +662,10 @@ fn main() { -<<<<<<< HEAD * 温度を華氏と摂氏で変換する。 * フィボナッチ数列のn番目を生成する。 * クリスマスキャロルの定番、"The Twelve Days of Christmas"の歌詞を、 曲の反復性を利用して出力する。 -======= -You made it! That was a sizable chapter: you learned about variables, scalar -and compound data types, functions, comments, `if` expressions, and loops! If -you want to practice with the concepts discussed in this chapter, try building -programs to do the following: ->>>>>>> fork_master_master diff --git a/second-edition/src/ch04-00-understanding-ownership.md b/second-edition/src/ch04-00-understanding-ownership.md index 6f9e1e511..ec442d52f 100644 --- a/second-edition/src/ch04-00-understanding-ownership.md +++ b/second-edition/src/ch04-00-understanding-ownership.md @@ -1,21 +1,13 @@ -<<<<<<< HEAD # 所有権を理解する - - - + + + 所有権はRustの最もユニークな機能であり、これのおかげでガベージコレクタなしで安全性担保を行うことができるのです。 故に、Rustにおいて、所有権がどう動作するのかを理解するのは重要です。この章では、所有権以外にも、関連する機能を いくつか話していきます: 借用、スライス、そして、コンパイラがデータをメモリにどう配置するかです。 -======= -Ownership is Rust’s most unique feature, and it enables Rust to make memory -safety guarantees without needing a garbage collector. Therefore, it’s -important to understand how ownership works in Rust. In this chapter, we’ll -talk about ownership as well as several related features: borrowing, slices, -and how Rust lays data out in memory. ->>>>>>> fork_master_master diff --git a/second-edition/src/ch04-01-what-is-ownership.md b/second-edition/src/ch04-01-what-is-ownership.md index 30defc14a..185e60075 100644 --- a/second-edition/src/ch04-01-what-is-ownership.md +++ b/second-edition/src/ch04-01-what-is-ownership.md @@ -2,18 +2,8 @@ ## 所有権とは? -<<<<<<< HEAD -======= -All programs have to manage the way they use a computer’s memory while running. -Some languages have garbage collection that constantly looks for no longer used -memory as the program runs; in other languages, the programmer must explicitly -allocate and free the memory. Rust uses a third approach: memory is managed -through a system of ownership with a set of rules that the compiler checks at -compile time. None of the ownership features slow down your program while it's -running. ->>>>>>> fork_master_master Rustの中心的な機能は、*所有権*です。機能は説明するのに単純なのですが、言語の残りの機能全てにかかるほど 深い裏の意味を含んでいるのです。 @@ -23,13 +13,14 @@ Rustの中心的な機能は、*所有権*です。機能は説明するのに - + + 全てのプログラムは、実行中にコンピュータのメモリの使用方法を管理する必要があります。プログラムが動作するにつれて、 定期的に使用されていないメモリを検索するガベージコレクションを持つ言語もありますが、他の言語では、 プログラマが明示的にメモリを確保したり、解放したりしなければなりません。Rustでは第3の選択肢を取っています: メモリは、コンパイラがコンパイル時にチェックする一定の規則とともに所有権システムを通じて管理されています。 -実行コストを、所有権機能のために負担することはありません。 +どの所有権機能も、実行中にプログラムの動作を遅くすることはありません。 @@ -48,18 +39,17 @@ Rustと所有権システムの経験を積むにつれて、自然に安全か 所有権を理解した時、Rustを際立たせる機能の理解に対する強固な礎を得ることになるでしょう。この章では、 非常に一般的なデータ構造に着目した例を取り扱うことで所有権を学んでいくでしょう: 文字列です。 -<<<<<<< HEAD - - - - - - + + + + + + @@ -75,16 +65,15 @@ Rustと所有権システムの経験を積むにつれて、自然に安全か - - - - - - - - - - + + + + + + + + + @@ -92,7 +81,7 @@ Rustと所有権システムの経験を積むにつれて、自然に安全か - + @@ -102,34 +91,24 @@ Rustと所有権システムの経験を積むにつれて、自然に安全か - + - - - - - - + + + + + + > ### スタックとヒープ > > 多くのプログラミング言語において、スタックとヒープについて考える機会はそう多くないでしょう。 > しかし、Rustのようなシステムプログラミング言語においては、値がスタックに載るかヒープに載るかは、 > 言語の振る舞い方や、特定の決断を下す理由などに影響以上のものを与えるのです。 -> この章の後半でスタックとヒープを絡めて所有権について解説するので、ここでちょっと予行演習をしておきましょう。 -======= -> ### The Stack and the Heap -> -> In many programming languages, you don’t have to think about the stack and -> the heap very often. But in a systems programming language like Rust, whether -> a value is on the stack or the heap has more of an effect on how the language -> behaves and why you have to make certain decisions. Parts of ownership will -> be described in relation to the stack and the heap later in this chapter, so -> here is a brief explanation in preparation. ->>>>>>> fork_master_master +> この章の後半でスタックとヒープを絡めて所有権に一部は解説されるので、ここでちょっと予行演習をしておきましょう。 > > スタックもヒープも、実行時にコードが使用できるメモリの一部になりますが、異なる手段で構成されています。 > スタックは、得た順番に値を並べ、逆の順で値を取り除いていきます。これは、 @@ -143,31 +122,18 @@ Rustと所有権システムの経験を積むにつれて、自然に安全か > データを取得する場所を探す必要が絶対にないわけです。というのも、その場所は常に一番上だからですね。スタックを高速にする特性は、 > 他にもあり、それはスタック上のデータは全て既知の固定サイズにならなければならないということです。 > -<<<<<<< HEAD > コンパイル時にサイズがわからなかったり、サイズが可変のデータについては、代わりにヒープに格納することができます。 -> ヒープは、もっとごちゃごちゃしています: ヒープにデータを置く時、私たちは、あるサイズのスペースを求めます。 +> ヒープは、もっとごちゃごちゃしています: ヒープにデータを置く時、あるサイズのスペースを求めます。 > OSはヒープ上に十分な大きさの空の領域を見つけ、使用中にし、*ポインタ*を返してきます。ポインタとは、その場所へのアドレスです。 > この過程は、*ヒープに領域を確保する*と呼ばれ、時としてそのフレーズを単に*allocateする*などと省略したりします。 > (`脚注`: こちらもこなれた日本語訳はないでしょう。allocateはメモリを確保すると訳したいところですが) > スタックに値を載せることは、メモリ確保とは考えられません。ポインタは、既知の固定サイズなので、 > スタックに保管することができますが、実データが必要になったら、ポインタを追いかける必要があります。 -======= -> Data with a size unknown at compile time or a size that might change can be -> stored on the heap instead. The heap is less organized: when you put data on -> the heap, you ask for some amount of space. The operating system finds an -> empty spot somewhere in the heap that is big enough, marks it as being in -> use, and returns a *pointer*, which is the address of that location. This -> process is called *allocating on the heap*, sometimes abbreviated as just -> “allocating.” Pushing values onto the stack is not considered allocating. -> Because the pointer is a known, fixed size, you can store the pointer on the -> stack, but when you want the actual data, you have to follow the pointer. ->>>>>>> fork_master_master > > レストランで席を確保することを考えましょう。入店したら、グループの人数を告げ、 > 店員が全員座れる空いている席を探し、そこまで誘導します。もしグループの誰かが遅れて来るのなら、 > 着いた席の場所を尋ねてあなたを発見することができます。 > -<<<<<<< HEAD > ヒープへのデータアクセスは、スタックのデータへのアクセスよりも低速です。 > ポインタを追って目的の場所に到達しなければならないからです。現代のプロセッサは、メモリをあちこち行き来しなければ、 > より速くなります。似た例えを続けましょう。レストランで多くのテーブルから注文を受ける給仕人を考えましょう。最も効率的なのは、 @@ -187,42 +153,13 @@ Rustと所有権システムの経験を積むにつれて、自然に安全か > 説明するのに役立つこともあります。 > -======= -> Accessing data in the heap is slower than accessing data on the stack because -> you have to follow a pointer to get there. Contemporary processors are faster -> if they jump around less in memory. Continuing the analogy, consider a server -> at a restaurant taking orders from many tables. It’s most efficient to get -> all the orders at one table before moving on to the next table. Taking an -> order from table A, then an order from table B, then one from A again, and -> then one from B again would be a much slower process. By the same token, a -> processor can do its job better if it works on data that’s close to other -> data (as it is on the stack) rather than farther away (as it can be on the -> heap). Allocating a large amount of space on the heap can also take time. -> -> When your code calls a function, the values passed into the function -> (including, potentially, pointers to data on the heap) and the function’s -> local variables get pushed onto the stack. When the function is over, those -> values get popped off the stack. -> -> Keeping track of what parts of code are using what data on the heap, -> minimizing the amount of duplicate data on the heap, and cleaning up unused -> data on the heap so you don’t run out of space are all problems that ownership -> addresses. Once you understand ownership, you won’t need to think about the -> stack and the heap very often, but knowing that managing heap data is why -> ownership exists can help explain why it works the way it does. ->>>>>>> fork_master_master ### 所有権規則 -<<<<<<< HEAD - -======= -First, let’s take a look at the ownership rules. Keep these rules in mind as we -work through the examples that illustrate them: ->>>>>>> fork_master_master + まず、所有権のルールについて見ていきましょう。この規則を具体化する例を 扱っていく間もこれらのルールを肝に命じておいてください: @@ -296,49 +233,31 @@ valid --> 言い換えると、ここまでに重要な点は二つあります: - - + + 1. `s`が*スコープに入る*と、有効になる -1. *スコープを抜ける*まで、それは続く +1. *スコープを抜ける*まで、有効なまま -<<<<<<< HEAD ここで、スコープと変数が有効になる期間の関係は、他の言語に類似しています。さて、この理解のもとに、 `String`型を導入して構築していきましょう。 -======= -* When `s` comes *into scope*, it is valid. -* It remains valid until it goes *out of scope*. - -At this point, the relationship between scopes and when variables are valid is -similar to that in other programming languages. Now we’ll build on top of this -understanding by introducing the `String` type. ->>>>>>> fork_master_master -<<<<<<< HEAD ### `String`型 -======= -To illustrate the rules of ownership, we need a data type that is more complex -than the ones we covered in the “Data Types” section of Chapter 3. The types -covered previously are all stored on the stack and popped off the stack when -their scope is over, but we want to look at data that is stored on the heap and -explore how Rust knows when to clean up that data. ->>>>>>> fork_master_master - - - - - -<<<<<<< HEAD -所有権の規則を具体化するには、第3章で解説したものよりも、より複雑なデータ型が必要になります。 -データ型節で解説した型は全てスタックに保管され、スコープが終わるとスタックから取り除かれますが、 + + + + + +所有権の規則を具体化するには、第3章の「データ型」節で講義したものよりも、より複雑なデータ型が必要になります。 +以前講義した型は全てスタックに保管され、スコープが終わるとスタックから取り除かれますが、 ヒープに確保されるデータ型を観察して、 コンパイラがどうそのデータを掃除すべきタイミングを把握しているかを掘り下げていきたいです。 @@ -352,8 +271,8 @@ explore how Rust knows when to clean up that data. `String`型については、第8章でより深く議論します。 - - + + @@ -362,47 +281,28 @@ explore how Rust knows when to clean up that data. すでに文字列リテラルは見かけましたね。文字列リテラルでは、文字列の値はプログラムにハードコードされます。 -文字列リテラルは便利ですが、テキストを使いたい場面全てに最適なわけではありません。一因は、 +文字列リテラルは便利ですが、テキストを使いたいかもしれない場面全てに最適なわけではありません。一因は、 文字列リテラルが不変であることに起因します。別の原因は、コードを書く際に、全ての文字列値が判明するわけではないからです: 例えば、ユーザ入力を受け付け、それを保持したいとしたらどうでしょうか?このような場面用に、Rustには、 2種類目の文字列型、`String`型があります。この型はヒープにメモリを確保するので、 コンパイル時にはサイズが不明なテキストも保持することができるのです。`from`関数を使用して、 文字列リテラルから`String`型を生成できます。以下のように: -======= -We’ve already seen string literals, where a string value is hardcoded into our -program. String literals are convenient, but they aren’t suitable for every -situation in which we may want to use text. One reason is that they’re -immutable. Another is that not every string value can be known when we write -our code: for example, what if we want to take user input and store it? For -these situations, Rust has a second string type, `String`. This type is -allocated on the heap and as such is able to store an amount of text that is -unknown to us at compile time. You can create a `String` from a string literal -using the `from` function, like so: ->>>>>>> fork_master_master ```rust let s = String::from("hello"); ``` -<<<<<<< HEAD - + この二重コロンは、`string_from`などの名前を使うのではなく、 `String`型直下の`from`関数を特定する働きをする演算子です。この記法について詳しくは、 -第5章の「メソッド記法」節と、第7章のモジュールを使った名前空間分けについて話をするときに議論します。 +第5章の「メソッド記法」節と、第7章の「モジュール定義」でモジュールを使った名前空間分けについて話をするときに議論します。 -======= -The double colon (`::`) is an operator that allows us to namespace this -particular `from` function under the `String` type rather than using some sort -of name like `string_from`. We’ll discuss this syntax more in the “Method -Syntax” section of Chapter 5 and when we talk about namespacing with modules in -“Module Definitions” in Chapter 7. ->>>>>>> fork_master_master この種の文字列は、可変化することが*できます*: @@ -432,16 +332,16 @@ println!("{}", s); // これは`hello, world!`と出力する ### メモリと確保 - - - - - - + + + + + + 文字列リテラルの場合、中身はコンパイル時に判明しているので、テキストは最終的なバイナリファイルに直接ハードコードされます。 -その結果、文字列リテラルは、高速で効率的になるのです。しかし、これらの特性は、 -その不変性にのみ端を発するものです。残念なことに、コンパイル時にサイズが不明だったり、 +このため、文字列リテラルは、高速で効率的になるのです。しかし、これらの特性は、 +その文字列リテラルの不変性にのみ端を発するものです。残念なことに、コンパイル時にサイズが不明だったり、 プログラム実行に合わせてサイズが可変なテキスト片用に一塊のメモリをバイナリに確保しておくことは不可能です。 @@ -451,69 +351,42 @@ println!("{}", s); // これは`hello, world!`と出力する `String`型では、可変かつ伸長可能なテキスト破片をサポートするために、コンパイル時には不明な量のメモリを ヒープに確保して内容を保持します。つまり: - - + + -1. メモリは、実行時にOSに要求される。 -2. `String`型を使用し終わったら、OSにこのメモリを返還する方法が必要である。 +* メモリは、実行時にOSに要求される。 +* `String`型を使用し終わったら、OSにこのメモリを返還する方法が必要である。 -<<<<<<< HEAD この最初の部分は、すでにしています: `String::from`関数を呼んだら、その実装が必要なメモリを要求するのです。 これは、プログラミング言語において、極めて普遍的です。 -======= -In the case of a string literal, we know the contents at compile time, so the -text is hardcoded directly into the final executable. This is why string -literals are fast and efficient. But these properties only come from the string -literal’s immutability. Unfortunately, we can’t put a blob of memory into the -binary for each piece of text whose size is unknown at compile time and whose -size might change while running the program. ->>>>>>> fork_master_master - - - - - - - - -<<<<<<< HEAD + + + + + + + -======= -* The memory must be requested from the operating system at runtime. -* We need a way of returning this memory to the operating system when we’re - done with our `String`. ->>>>>>> fork_master_master しかしながら、2番目の部分は異なります。*ガベージコレクタ*(GC)付きの言語では、GCがこれ以上、 -使用されないメモリを検知して片付けるため、私たちプログラマは、そのことを考慮する必要はありません。 +使用されないメモリを検知して片付けるため、プログラマは、そのことを考慮する必要はありません。 GCがないなら、メモリがもう使用されないことを見計らって、明示的に返還するコードを呼び出すのは、 プログラマの責任になります。ちょうど要求の際にしたようにですね。これを正確にすることは、 歴史的にも難しいプログラミング問題の一つであり続けています。もし、忘れていたら、メモリを無駄にします。 タイミングが早すぎたら、無効な変数を作ってしまいます。2回解放してしまっても、バグになるわけです。 -`allocate`と`free`は1対1対応にしなければならないのです。 +`allocate`と`free`は完璧に1対1対応にしなければならないのです。 -<<<<<<< HEAD -======= -However, the second part is different. In languages with a *garbage collector -(GC)*, the GC keeps track and cleans up memory that isn’t being used anymore, -and we don’t need to think about it. Without a GC, it’s our responsibility to -identify when memory is no longer being used and call code to explicitly return -it, just as we did to request it. Doing this correctly has historically been a -difficult programming problem. If we forget, we’ll waste memory. If we do it -too early, we’ll have an invalid variable. If we do it twice, that’s a bug too. -We need to pair exactly one `allocate` with exactly one `free`. ->>>>>>> fork_master_master Rustは、異なる道を歩んでいます: ひとたび、メモリを所有している変数がスコープを抜けたら、 メモリは自動的に返還されます。こちらの例は、 @@ -585,24 +458,16 @@ to `y` --> リスト4-2: 変数`x`の整数値を`y`に代入する - - - - - + + + + + -<<<<<<< HEAD -もしかしたら、他の言語の経験に基づいて、何をしているのか予想することができるでしょう: +もしかしたら、何をしているのか予想することができるでしょう: 「値`5`を`x`に束縛する; それから`x`の値をコピーして`y`に束縛する。」これで、 二つの変数(`x`と`y`)が存在し、両方、値は`5`になりました。これは確かに起こっている現象を説明しています。 なぜなら、整数は既知の固定サイズの単純な値で、これら二つの`5`という値は、スタックに積まれるからです。 -======= -We can probably guess what this is doing: “bind the value `5` to `x`; then make -a copy of the value in `x` and bind it to `y`.” We now have two variables, `x` -and `y`, and both equal `5`. This is indeed what is happening, because integers -are simple values with a known, fixed size, and these two `5` values are pushed -onto the stack. ->>>>>>> fork_master_master @@ -621,24 +486,16 @@ let s2 = s1; 要するに、2行目で`s1`の値をコピーし、`s2`に束縛するということです。ところが、 これは全く起こることを言い当てていません。 - - - - - + + + + + -<<<<<<< HEAD -これをもっと徹底的に説明するために、図4-3を見て`String`型のベールを剥がしてみましょう。 +図4-1を見て、ベールの下で`String`に何が起きているかを確かめてください。 `String`型は、左側に示されているように、3つの部品でできています: 文字列の中身を保持するメモリへのポインタと長さ、そして、許容量です。この種のデータは、スタックに保持されます。 右側には、中身を保持したヒープ上のメモリがあります。 -======= -Take a look at Figure 4-1 to see what is happening to `String` under the -covers. A `String` is made up of three parts, shown on the left: a pointer to -the memory that holds the contents of the string, a length, and a capacity. -This group of data is stored on the stack. On the right is the memory on the -heap that holds the contents. ->>>>>>> fork_master_master @@ -659,32 +516,19 @@ holding the value `"hello"` bound to `s1` --> `String`型がOSから受け取った全メモリ量をバイトで表したものです。長さと許容量の違いは問題になることですが、 この文脈では違うので、とりあえずは、許容量を無視しても構わないでしょう。 -<<<<<<< HEAD -======= -The representation does *not* look like Figure 4-3, which is what memory would -look like if Rust instead copied the heap data as well. If Rust did this, the -operation `s2 = s1` could be very expensive in terms of runtime performance if -the data on the heap were large. ->>>>>>> fork_master_master `s1`を`s2`に代入すると、`String`型のデータがコピーされます。つまり、スタックにあるポインタ、長さ、 許容量をコピーするということです。ポインタが指すヒープ上のデータはコピーしません。言い換えると、 メモリ上のデータ表現は図4-4のようになるということです。 -<<<<<<< HEAD -======= -Figure 4-3: Another possibility for what `s2 = s1` might -do if Rust copied the heap data as well ->>>>>>> fork_master_master 同じ値を指すs1とs2 -<<<<<<< HEAD @@ -692,8 +536,8 @@ that has a copy of the pointer, length, and capacity of `s1` --> - - + + メモリ上の表現は、図4-5のようにはなり*ません*。これは、 Rustが代わりにヒープデータもコピーするという選択をしていた場合のメモリ表現ですね。Rustがこれをしていたら、 @@ -724,7 +568,7 @@ do if Rust copied the heap data as well --> - + @@ -734,13 +578,6 @@ do if Rust copied the heap data as well --> 確保されたメモリをコピーしようとする代わりに、コンパイラは、`s1`が最早有効ではないと考え、 故に`s1`がスコープを抜けた際に何も解放する必要がなくなるわけです。`s2`の生成後に`s1`を使用しようとしたら、 どうなるかを確認してみましょう。動かないでしょう: -======= -To ensure memory safety, there’s one more detail to what happens in this -situation in Rust. Instead of trying to copy the allocated memory, Rust -considers `s1` to no longer be valid and, therefore, Rust doesn’t need to free -anything when `s1` goes out of scope. Check out what happens when you try to -use `s1` after `s2` is created; it won’t work: ->>>>>>> fork_master_master ```rust,ignore let s1 = String::from("hello"); @@ -772,19 +609,18 @@ error[E0382]: use of moved value: `s1` `Copy`トレイトを実装していない型だからです) ``` -<<<<<<< HEAD - - - - + + + + 他の言語を触っている間に"shallow copy"と"deep copy"という用語を耳にしたことがあるなら、 データのコピーなしにポインタと長さ、許容量をコピーするという概念は、shallow copyのように思えるかもしれません。 -ですが、コンパイラは最初の変数をも無効化するので、これをshallow copyと呼ぶ代わりに、 +ですが、コンパイラは最初の変数をも無効化するので、shallow copyと呼ばれる代わりに、 ムーブとして知られているわけです。ここでは、`s1`は`s2`に*ムーブ*されたと解読します。 -以上より、実際に起きることを図4-6に示してみました。 +以上より、実際に起きることを図4-4に示してみました。 @@ -794,14 +630,6 @@ error[E0382]: use of moved value: `s1` invalidated --> 図4-4: `s1`が無効化された後のメモリ表現 -======= -If you’ve heard the terms *shallow copy* and *deep copy* while working with -other languages, the concept of copying the pointer, length, and capacity -without copying the data probably sounds like making a shallow copy. But -because Rust also invalidates the first variable, instead of being called a -shallow copy, it’s known as a *move*. Here we would read this by saying that -`s1` was *moved* into `s2`. So what actually happens is shown in Figure 4-4. ->>>>>>> fork_master_master @@ -841,11 +669,10 @@ let s2 = s1.clone(); println!("s1 = {}, s2 = {}", s1, s2); ``` -<<<<<<< HEAD - - + + -これは単純にうまく動き、こうして図4-5で示した動作を明示的に生み出すことができます。ここでは、 +これは単純にうまく動き、図4-3で示した動作を明示的に生み出します。ここでは、 ヒープデータが*実際に*コピーされています。 @@ -854,10 +681,6 @@ println!("s1 = {}, s2 = {}", s1, s2); `clone`メソッドの呼び出しを見かけたら、何らかの任意のコードが実行され、その実行コストは高いと把握できます。 何か違うことが起こっているなと見た目でわかるわけです。 -======= -This works just fine and explicitly produces the behavior shown in Figure 4-3, -where the heap data *does* get copied. ->>>>>>> fork_master_master @@ -876,16 +699,15 @@ let y = x; println!("x = {}, y = {}", x, y); ``` -<<<<<<< HEAD ですが、このコードは一見、今学んだことと矛盾しているように見えます: `clone`メソッドの呼び出しがないのに、`x`は有効で、`y`にムーブされませんでした。 - - - + + + @@ -903,15 +725,15 @@ println!("x = {}, y = {}", x, y); - - + + Rustには`Copy`トレイトと呼ばれる特別な注釈があり、 整数のようなスタックに保持される型に対して配置することができます(トレイトについては第10章でもっと詳しく話します)。 型が`Copy`トレイトに適合していれば、代入後も古い変数が使用可能になります。コンパイラは、 型やその一部分でも`Drop`トレイトを実装している場合、`Copy`トレイトによる注釈をさせてくれません。 型の値がスコープを外れた時に何か特別なことを起こす必要がある場合に、`Copy`注釈を追加すると、コンパイルエラーが出ます。 -型に`Copy`注釈をつける方法について学ぶには、付録Cの継承可能トレイト(Derivable Traits)についてをご覧ください。 +型に`Copy`注釈をつける方法について学ぶには、付録Cの「継承可能トレイト」をご覧ください。 @@ -924,26 +746,26 @@ Rustには`Copy`トレイトと呼ばれる特別な注釈があり、 - - - + + + * あらゆる整数型。`u32`など。 * 論理値型、`bool`、`true`と`false`という値がある。 -* 文字型、`char`。 * あらゆる浮動小数点型、`f64`など。 -* タプル。ただ、`Copy`の型だけを含む場合。`(i32, i32)`は`Copy`だが、 +* 文字型、`char`。 +* タプル。ただ、`Copy`の型だけを含む場合。例えば、`(i32, i32)`は`Copy`だが、 `(i32, String)`は違う。 ### 所有権と関数 - - - - + + + + 意味論的に、関数に値を渡すことと、値を変数に代入することは似ています。関数に変数を渡すと、 代入のようにムーブやコピーされます。リスト4-7は変数がスコープに入ったり、 @@ -955,16 +777,16 @@ Rustには`Copy`トレイトと呼ばれる特別な注釈があり、 - + - + - + - + @@ -974,97 +796,33 @@ Rustには`Copy`トレイトと呼ばれる特別な注釈があり、 - + ```rust fn main() { - let s = String::from("hello"); // sがスコープに入る。 + let s = String::from("hello"); // sがスコープに入る takes_ownership(s); // sの値が関数にムーブされ... - // ... ここではもう有効ではない。 + // ... ここではもう有効ではない - let x = 5; // xがスコープに入る。 + let x = 5; // xがスコープに入る makes_copy(x); // xも関数にムーブされるが、 // i32はCopyなので、この後にxを使っても - // 大丈夫。 + // 大丈夫 } // ここでxがスコープを抜け、sも。だけど、sの値はムーブされてるので、何も特別なことはない。 // fn takes_ownership(some_string: String) { // some_stringがスコープに入る。 -======= -But this code seems to contradict what we just learned: we don’t have a call to -`clone`, but `x` is still valid and wasn’t moved into `y`. - -The reason is that types such as integers that have a known size at compile -time are stored entirely on the stack, so copies of the actual values are quick -to make. That means there’s no reason we would want to prevent `x` from being -valid after we create the variable `y`. In other words, there’s no difference -between deep and shallow copying here, so calling `clone` wouldn’t do anything -different from the usual shallow copying and we can leave it out. - -Rust has a special annotation called the `Copy` trait that we can place on -types like integers that are stored on the stack (we’ll talk more about traits -in Chapter 10). If a type has the `Copy` trait, an older variable is still -usable after assignment. Rust won’t let us annotate a type with the `Copy` -trait if the type, or any of its parts, has implemented the `Drop` trait. If -the type needs something special to happen when the value goes out of scope and -we add the `Copy` annotation to that type, we’ll get a compile time error. To -learn about how to add the `Copy` annotation to your type, see “Derivable -Traits” in Appendix C. - -So what types are `Copy`? You can check the documentation for the given type to -be sure, but as a general rule, any group of simple scalar values can be -`Copy`, and nothing that requires allocation or is some form of resource is -`Copy`. Here are some of the types that are `Copy`: - -* All the integer types, such as `u32`. -* The Boolean type, `bool`, with values `true` and `false`. -* All the floating point types, such as `f64`. -* The character type, `char`. -* Tuples, but only if they contain types that are also `Copy`. For example, - `(i32, i32)` is `Copy`, but `(i32, String)` is not. - -### Ownership and Functions - -The semantics for passing a value to a function are similar to those for -assigning a value to a variable. Passing a variable to a function will move or -copy, just as assignment does. Listing 4-3 has an example with some annotations -showing where variables go into and out of scope: - -Filename: src/main.rs - -```rust -fn main() { - let s = String::from("hello"); // s comes into scope - - takes_ownership(s); // s's value moves into the function... - // ... and so is no longer valid here - - let x = 5; // x comes into scope - - makes_copy(x); // x would move into the function, - // but i32 is Copy, so it’s okay to still - // use x afterward - -} // Here, x goes out of scope, then s. But because s's value was moved, nothing - // special happens. - -fn takes_ownership(some_string: String) { // some_string comes into scope ->>>>>>> fork_master_master println!("{}", some_string); } // ここでsome_stringがスコープを抜け、`drop`が呼ばれる。後ろ盾してたメモリが解放される。 // -<<<<<<< HEAD -fn makes_copy(some_integer: i32) { // some_integerがスコープに入る。 -======= -fn makes_copy(some_integer: i32) { // some_integer comes into scope ->>>>>>> fork_master_master +fn makes_copy(some_integer: i32) { // some_integerがスコープに入る println!("{}", some_integer); } // ここでsome_integerがスコープを抜ける。何も特別なことはない。 ``` @@ -1087,10 +845,10 @@ annotated --> ### 戻り値とスコープ - - + + -値を返すことでも、所有権は移動します。リスト4-3と似た注釈のついた例です: +値を返すことでも、所有権は移動します。リスト4-4は、リスト4-3と似た注釈のついた例です: @@ -1099,26 +857,21 @@ annotated --> - + - + - + - + -<<<<<<< HEAD - -======= -Returning values can also transfer ownership. Listing 4-4 is an example with -similar annotations to those in Listing 4-3: ->>>>>>> fork_master_master + @@ -1127,19 +880,18 @@ similar annotations to those in Listing 4-3: - + - + ```rust fn main() { -<<<<<<< HEAD let s1 = gives_ownership(); // gives_ownershipは、戻り値をs1に - // ムーブする。 + // ムーブする - let s2 = String::from("hello"); // s2がスコープに入る。 + let s2 = String::from("hello"); // s2がスコープに入る let s3 = takes_and_gives_back(s2); // s2はtakes_and_gives_backにムーブされ // 戻り値もs3にムーブされる @@ -1149,38 +901,24 @@ fn main() { fn gives_ownership() -> String { // gives_ownershipは、戻り値を // 呼び出した関数にムーブする - let some_string = String::from("hello"); // some_stringがスコープに入る。 -======= - let s1 = gives_ownership(); // gives_ownership moves its return - // value into s1 - - let s2 = String::from("hello"); // s2 comes into scope - - 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. - -fn gives_ownership() -> String { // gives_ownership will move its - // return value into the function - // that calls it - - let some_string = String::from("hello"); // some_string comes into scope ->>>>>>> fork_master_master + let some_string = String::from("hello"); // some_stringがスコープに入る some_string // some_stringが返され、呼び出し元関数に // ムーブされる。 } -<<<<<<< HEAD -// takes_and_gives_backは、Stringを一つ受け取り、返す +// takes_and_gives_backは、Stringを一つ受け取り、返す。 fn takes_and_gives_back(a_string: String) -> String { // a_stringがスコープに入る。 - a_string // a_stringが返され、呼び出し元関数にムーブされる。 + a_string // a_stringが返され、呼び出し元関数にムーブされる } ``` + + + +リスト4-4: 戻り値の所有権を移動する + @@ -1201,32 +939,11 @@ fn takes_and_gives_back(a_string: String) -> String { // a_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 + - a_string // a_string is returned and moves out to the calling function -} -``` - -Listing 4-4: Transferring ownership of return -values - -The ownership of a variable follows the same pattern every time: assigning a -value to another variable moves it. When a variable that includes data on the -heap goes out of scope, the value will be cleaned up by `drop` unless the data -has been moved to be owned by another variable. ->>>>>>> fork_master_master +タプルで、複数の値を返すことは可能です。リスト4-5のようにね: -タプルで、複数の値を返すことは可能です。このように: - -<<<<<<< HEAD -======= -It’s possible to return multiple values using a tuple, as shown in Listing 4-5: ->>>>>>> fork_master_master ファイル名: src/main.rs @@ -1240,7 +957,7 @@ It’s possible to return multiple values using a tuple, as shown in Listing 4-5 - + @@ -1257,27 +974,19 @@ fn main() { } fn calculate_length(s: String) -> (String, usize) { -<<<<<<< HEAD - let length = s.len(); // len()メソッドは、Stringの長さを返します。 -======= - let length = s.len(); // len() returns the length of a String ->>>>>>> fork_master_master + let length = s.len(); // len()メソッドは、Stringの長さを返します (s, length) } ``` -<<<<<<< HEAD + + +リスト4-5: 引数の所有権を返す + - + でも、これでは、大袈裟すぎますし、ありふれているはずの概念に対して、作業量が多すぎます。 -私たちにとって幸運なことに、Rustにはこの概念に対する機能があり、それは*参照*と呼ばれます。 -======= -Listing 4-5: Returning ownership of parameters - -But this is too much ceremony and a lot of work for a concept that should be -common. Luckily for us, Rust has a feature for this concept, called -*references*. ->>>>>>> fork_master_master +私たちにとって幸運なことに、Rustにはこの概念に対する機能があり、*参照*と呼ばれます。 diff --git a/second-edition/src/ch04-02-references-and-borrowing.md b/second-edition/src/ch04-02-references-and-borrowing.md index bde7b6c66..025ba7a70 100644 --- a/second-edition/src/ch04-02-references-and-borrowing.md +++ b/second-edition/src/ch04-02-references-and-borrowing.md @@ -1,31 +1,20 @@ -<<<<<<< HEAD ## 参照と借用 - - - - -======= -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`. - -Here is how you would define and use a `calculate_length` function that has a -reference to an object as a parameter instead of taking ownership of the -value: ->>>>>>> fork_master_master - -前節最後のタプルコードの問題は、`String`型を呼び出し元の関数に戻さないと、`calculate_length`を呼び出した後に、 + + + + + +リスト4-5のタプルコードの問題は、`String`型を呼び出し元の関数に戻さないと、`calculate_length`を呼び出した後に、 `String`オブジェクトが使えなくなることであり、これは`String`オブジェクトが`calculate_length`にムーブされてしまうためでした。 - + -ここで、値の所有権をもらう代わりに引数としてオブジェクトへの*参照*を取る`calculate_length`関数を定義し、 +ここで、値の所有権をもらう代わりに引数としてオブジェクトへの参照を取る`calculate_length`関数を定義し、 使う方法を見てみましょう: @@ -47,10 +36,9 @@ fn calculate_length(s: &String) -> usize { } ``` -<<<<<<< HEAD - + まず、変数宣言と関数の戻り値にあったタプルコードは全てなくなったことに気付いてください。 @@ -63,23 +51,13 @@ fn calculate_length(s: &String) -> usize { 図4-5はその図解です。 -======= -First, notice that all the tuple code in the variable declaration and the -function return value is gone. Second, note that we pass `&s1` into -`calculate_length` and, in its definition, we take `&String` rather than -`String`. ->>>>>>> fork_master_master -文字列s1を指す&String型のs +文字列s1を指す&String型のs - + + -<<<<<<< HEAD -図4-5: `String s1`を指す`&String` -======= -Figure 4-5: A diagram of `&String s` pointing at `String -s1` ->>>>>>> fork_master_master +図4-5: `String s1`を指す`&String`の図表 @@ -129,40 +107,27 @@ fn calculate_length(s: &String) -> usize { // sはStringへの参照 // 何も起こらない ``` -<<<<<<< HEAD - - - + + + 変数`s`が有効なスコープは、あらゆる関数の引数のものと同じですが、所有権はないので、`s`がスコープを抜けても、 -参照が指しているものをドロップすることはありません。実際の値の代わりに参照を引数に取る関数は、 -所有権をもらわないので、所有権を返す目的で値を返す必要はないことを意味します。 +参照が指しているものをドロップすることはありません。関数が実際の値の代わりに参照を引数に取ると、 +所有権をもらわないので、所有権を返す目的で値を返す必要はありません。 -======= -The scope in which the variable `s` is valid is the same as any function -parameter’s scope, but we don’t drop what the reference points to when it goes -out of scope because we don’t have ownership. When functions have references as -parameters instead of the actual values, we won’t need to return the values in -order to give back ownership, because we never had ownership. ->>>>>>> fork_master_master 関数の引数に参照を取ることを*借用*と呼びます。現実生活のように、誰かが何かを所有していたら、 それを借りることができます。用が済んだら、返さなきゃいけないわけです。 -<<<<<<< HEAD - -======= -So what happens if we try to modify something we’re borrowing? Try the code in -Listing 4-6. Spoiler alert: it doesn’t work! ->>>>>>> fork_master_master + -では、借用した何かを変更しようとしたら、どうなるのでしょうか?リスト4-9のコードを試してください。 +では、借用した何かを変更しようとしたら、どうなるのでしょうか?リスト4-6のコードを試してください。 ネタバレ注意: 動きません! @@ -181,15 +146,11 @@ fn change(some_string: &String) { } ``` -<<<<<<< HEAD - + -リスト4-4: 借用した値を変更しようと試みる +リスト4-6: 借用した値を変更しようと試みる -======= -Listing 4-6: Attempting to modify a borrowed value ->>>>>>> fork_master_master これがエラーです: @@ -213,15 +174,11 @@ error[E0596]: cannot borrow immutable borrowed content `*some_string` as mutable ### 可変な参照 - + -一捻り加えるだけでリスト4-9のコードのエラーは解決します: +一捻り加えるだけでリスト4-6のコードのエラーは解決します: -<<<<<<< HEAD -======= -We can fix the error in the code from Listing 4-6 with just a small tweak: ->>>>>>> fork_master_master ファイル名: src/main.rs @@ -282,41 +239,27 @@ error[E0499]: cannot borrow `s` as mutable more than once at a time | (最初の借用はここで終わり) ``` -<<<<<<< HEAD - - + この制約は、可変化を許可するものの、それを非常に統制の取れた形で行えます。これは、新たなRust市民にとっては、 -壁です。なぜなら、多くの言語では、いつでも好きな時に可変化できるからです。この制約がある利点は、 -コンパイラがコンパイル時にデータ競合を防ぐことができる点です。 +壁です。なぜなら、多くの言語では、いつでも好きな時に可変化できるからです。 - - + + + +この制約がある利点は、コンパイラがコンパイル時にデータ競合を防ぐことができる点です。 データ競合とは、競合条件と類似していて、これら3つの振る舞いが起きる時に発生します: - - - - -1. 2つ以上のポインタが同じデータに同時にアクセスする。 -1. 少なくとも一つのポインタがデータに書き込みを行っている。 -1. データへのアクセスを同期する機構が使用されていない。 -======= -This restriction allows for mutation but in a very controlled fashion. It’s -something that new Rustaceans struggle with, because most languages let you -mutate whenever you’d like. - -The benefit of having this restriction is that Rust can prevent data races at -compile time. A *data race* is similar to a race condition and happens when -these three behaviors occur: + + + -* Two or more pointers access the same data at the same time. -* At least one of the pointers is being used to write to the data. -* There’s no mechanism being used to synchronize access to the data. ->>>>>>> fork_master_master +* 2つ以上のポインタが同じデータに同時にアクセスする。 +* 少なくとも一つのポインタがデータに書き込みを行っている。 +* データへのアクセスを同期する機構が使用されていない。 @@ -404,30 +347,23 @@ immutable - - + + これらのエラーは、時としてイライラするものではありますが、Rustコンパイラがバグの可能性を早期に指摘してくれ(それも実行時ではなくコンパイル時に)、 -時々想定通りにデータが変わらない理由を追いかけさせる代わりに、問題の発生箇所をズバリ示してくれるのだと覚えておいてください。 +問題の発生箇所をズバリ示してくれるのだと覚えておいてください。そうして想定通りにデータが変わらない理由を追いかける必要がなくなります。 ### 宙に浮いた参照 -<<<<<<< HEAD - - - -======= -Even though these errors may be frustrating at times, remember that it’s the -Rust compiler pointing out a potential bug early (at compile time rather than -at runtime) and showing you exactly where the problem is. Then you don’t have -to track down why your data isn’t what you thought it was. ->>>>>>> fork_master_master + + + ポインタのある言語では、誤ってダングリングポインタを生成してしまいやすいです。ダングリングポインタとは、 他人に渡されてしまった可能性のあるメモリを指すポインタのことであり、その箇所へのポインタを保持している間に、 @@ -435,18 +371,8 @@ to track down why your data isn’t what you thought it was. 参照がダングリング参照に絶対ならないよう保証してくれます:つまり、何らかのデータへの参照があったら、 コンパイラは参照がスコープを抜けるまで、データがスコープを抜けることがないよう確認してくれるわけです。 -<<<<<<< HEAD -======= -In languages with pointers, it’s easy to erroneously create a *dangling -pointer*, a pointer that references a location in memory that may have been -given to someone else, by freeing some memory while preserving a pointer to -that memory. In Rust, by contrast, the compiler guarantees that references will -never be dangling references: if you have a reference to some data, the -compiler will ensure that the data will not go out of scope before the -reference to the data does. ->>>>>>> fork_master_master ダングリング参照作りを試してみますが、コンパイラはこれをコンパイルエラーで阻止します: @@ -524,21 +450,14 @@ fn dangle() -> &String { // dangleはStringへの参照を返す // 危険だ ``` -<<<<<<< HEAD - + -======= -Because `s` is created inside `dangle`, when the code of `dangle` is finished, -`s` will be deallocated. But we tried to return a reference to it. That means -this reference would be pointing to an invalid `String` That’s no good! Rust -won’t let us do this. ->>>>>>> fork_master_master `s`は、`dangle`内で生成されているので、`dangle`のコードが終わったら、`s`は解放されてしまいますが、 そこへの参照を返そうとしました。つまり、この参照は無効な`String`を指していると思われるのです。 -よくないことです。コンパイラは、これを阻止してくれるのです。 +よくないことです!コンパイラは、これを阻止してくれるのです。 @@ -565,22 +484,13 @@ fn no_dangle() -> String { 参照について議論したことを再確認しましょう: - - - - + + + -1. 任意のタイミングで、以下の両方ではなくどちらかを行える: - * 一つの可変参照 - * 不変な参照いくつでも -2. 参照は常に有効でなければならない +* 任意のタイミングで、一つの可変参照か不変な参照いくつでものどちらかを行える +* 参照は常に有効でなければならない -<<<<<<< HEAD -======= -* At any given time, you can have *either* (but not both of) one mutable - reference or any number of immutable references. -* References must always be valid. ->>>>>>> fork_master_master 次は、違う種類の参照を見ていきましょう: スライスです。 diff --git a/second-edition/src/ch04-03-slices.md b/second-edition/src/ch04-03-slices.md index ed97ef5f4..a5a25beff 100644 --- a/second-edition/src/ch04-03-slices.md +++ b/second-edition/src/ch04-03-slices.md @@ -1,32 +1,21 @@ -<<<<<<< HEAD - -======= -## The Slice Type ->>>>>>> fork_master_master + -## スライス +## スライス型 -<<<<<<< HEAD -======= -Here’s a small programming problem: write a function that takes a string and -returns the first word it finds in that string. If the function doesn’t find a -space in the string, the whole string must be one word, so the entire string -should be returned. ->>>>>>> fork_master_master 所有権のない別のデータ型は、*スライス*です。スライスにより、コレクション全体というより、 その内の一連の要素を参照することができます。 - - + + ここに小さなプログラミング問題があります: 文字列を受け取って、その文字列中の最初の単語を返す関数を書いてください。 -関数が文字列中に空白を見つけなかったら、文字列全体が一つの単語であることになり、文字列全体が返されるはずです。 +関数が文字列中に空白を見つけなかったら、文字列全体が一つの単語に違いないので、文字列全体が返されるべきです。 @@ -36,21 +25,14 @@ should be returned. fn first_word(s: &String) -> ? ``` -<<<<<<< HEAD - -======= -This function, `first_word`, has a `&String` as a parameter. We don’t want -ownership, so this is fine. But what should we return? We don’t really have a -way to talk about *part* of a string. However, we could return the index of the -end of the word. Let’s try that, as shown in Listing 4-7: ->>>>>>> fork_master_master + この関数、`first_word`は引数に`&String`をとります。所有権はいらないので、これで十分です。 ですが、何を返すべきでしょうか?文字列の*一部*について語る方法が全くありません。しかし、 -単語の終端の番号を返すことができますね。リスト4-5に示したように、その方法を試してみましょう: +単語の終端の番号を返すことができますね。リスト4-7に示したように、その方法を試してみましょう: @@ -70,26 +52,17 @@ fn first_word(s: &String) -> usize { } ``` -<<<<<<< HEAD - + -リスト4-5: `String`引数へのバイト数で表された番号を返す`first_word`関数 +リスト4-7: `String`引数へのバイト数で表された番号を返す`first_word`関数 - - - + + + -このコードを少し噛み砕いていきましょう。`String`の値を要素ごとに見て、空白かどうかを確かめる必要があるので、 +`String`の値を要素ごとに見て、空白かどうかを確かめる必要があるので、 `as_bytes`メソッドを使って、`String`オブジェクトをバイト配列に変換しています。 -======= -Listing 4-7: The `first_word` function that returns a -byte index value into the `String` parameter - -Because we need to go through the `String` element by element and check whether -a value is a space, we’ll convert our `String` to an array of bytes using the -`as_bytes` method: ->>>>>>> fork_master_master ```rust,ignore let bytes = s.as_bytes(); @@ -103,17 +76,16 @@ let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { ``` -<<<<<<< HEAD - - - - - + + + + + イテレータについて詳しくは、第13章で議論します。今は、`iter`は、コレクション内の各要素を返すメソッドであること、 `enumerate`が`iter`の結果を包んで、代わりにタプルの一部として各要素を返すことを知っておいてください。 -戻り値のタプルの第1要素は、番号であり、2番目の要素は、(コレクションの)要素への参照になります。 +`enumerate`から返ってくるタプルの第1要素は、番号であり、2番目の要素は、(コレクションの)要素への参照になります。 これは、手動で番号を計算するよりも少しだけ便利です。 @@ -121,31 +93,17 @@ for (i, &item) in bytes.iter().enumerate() { -======= -We’ll discuss iterators in more detail in Chapter 13. For now, know that `iter` -is a method that returns each element in a collection and that `enumerate` -wraps the result of `iter` and returns each element as part of a tuple instead. -The first element of the tuple returned from `enumerate` is the index, and the -second element is a reference to the element. This is a bit more convenient -than calculating the index ourselves. ->>>>>>> fork_master_master `enumerate`メソッドがタプルを返すので、Rustのあらゆる場所同様、パターンを使って、そのタプルを分解できます。 従って、`for`ループ内で、タプルの番号に対する`i`とタプルの1バイトに対応する`&item`を含むパターンを指定しています。 `.iter().enumerate()`から要素への参照を取得するので、パターンに`&`を使っています。 -<<<<<<< HEAD - - - + + + -バイトリテラル表記を使用して空白を表すバイトを検索しています。空白が見つかったら、その位置を返します。 +`for`ループ内で、バイトリテラル表記を使用して空白を表すバイトを検索しています。空白が見つかったら、その位置を返します。 それ以外の場合、`s.len()`を使って文字列の長さを返します。 -======= -Inside the `for` loop, we search for the byte that represents the space by -using the byte literal syntax. If we find a space, we return the position. -Otherwise, we return the length of the string by using `s.len()`: ->>>>>>> fork_master_master ```rust,ignore if item == b' ' { @@ -155,18 +113,17 @@ Otherwise, we return the length of the string by using `s.len()`: s.len() ``` -<<<<<<< HEAD - - + + さて、文字列内の最初の単語の終端の番号を見つけ出せるようになりましたが、問題があります。 `usize`型を単独で返していますが、これは`&String`の文脈でのみ意味を持つ数値です。 言い換えると、`String`から切り離された値なので、将来的にも有効である保証がないのです。 -リスト4-10の`first_word`関数を使用するリスト4-11のプログラムを考えてください: +リスト4-7の`first_word`関数を使用するリスト4-8のプログラムを考えてください: @@ -196,16 +153,6 @@ s.len() -======= -We now have a way to find out the index of the end of the first word in the -string, but there’s a problem. We’re returning a `usize` on its own, but it’s -only a meaningful number in the context of the `&String`. In other words, -because it’s a separate value from the `String`, there’s no guarantee that it -will still be valid in the future. Consider the program in Listing 4-8 that -uses the `first_word` function from Listing 4-7: - -Filename: src/main.rs ->>>>>>> fork_master_master ```rust # fn first_word(s: &String) -> usize { @@ -238,26 +185,15 @@ fn main() { } ``` -<<<<<<< HEAD - + -リスト4-6: `first_word`関数の呼び出し結果を保持し、`String`の中身を変更する -======= -Listing 4-8: Storing the result from calling the -`first_word` function and then changing the `String` contents - -This program compiles without any errors and would also do so if we used `word` -after calling `s.clear()`. Because `word` isn’t connected to the state of `s` -at all, `word` still contains the value `5`. We could use that value `5` with -the variable `s` to try to extract the first word out, but this would be a bug -because the contents of `s` have changed since we saved `5` in `word`. ->>>>>>> fork_master_master +リスト4-8: `first_word`関数の呼び出し結果を保持し、`String`の中身を変更する - - - - + + + + このプログラムは何のエラーもなくコンパイルが通り、`word`を`s.clear()`の呼び出し後に使用しても、 @@ -277,11 +213,10 @@ because the contents of `s` have changed since we saved `5` in `word`. fn second_word(s: &String) -> (usize, usize) { ``` -<<<<<<< HEAD - - - - + + + + 今、私たちは開始*と*終端の番号を追うようになりました。特定の状態のデータから計算されたけど、 その状態に全く紐付かない値が増えました。同期を取る必要のある宙に浮いた関連性のない変数が3つになってしまいました。 @@ -291,22 +226,12 @@ fn second_word(s: &String) -> (usize, usize) { 運のいいことに、Rustにはこの問題への解決策が用意されています: 文字列スライスです。 -======= -Now we’re tracking a starting *and* an ending index, and we have even more -values that were calculated from data in a particular state but aren’t tied to -that state at all. We now have three unrelated variables floating around that -need to be kept in sync. ->>>>>>> fork_master_master ### 文字列スライス - + -<<<<<<< HEAD *文字列スライス*とは、`String`の一部への参照で、こんな見た目をしています: -======= -A *string slice* is a reference to part of a `String`, and it looks like this: ->>>>>>> fork_master_master ```rust let s = String::from("hello world"); @@ -320,30 +245,20 @@ let world = &s[6..11]; -<<<<<<< HEAD これは、`String`全体への参照を取ることに似ていますが、余計な`[0..5]`という部分が付いています。 `String`全体への参照というよりも、`String`の一部への参照です。`開始..終点`という記法は、`開始`から始まり、 `終点`未満までずっと続く範囲です。 -======= -We can create slices using a range within brackets by specifying -`[starting_index..ending_index]`, where `starting_index` is the first position -in the slice and `ending_index` is one more than the last position in the -slice. Internally, the slice data structure stores the starting position and -the length of the slice, which corresponds to `ending_index` minus -`starting_index`. So in the case of `let world = &s[6..11];`, `world` would be -a slice that contains a pointer to the 6th byte of `s` and a length value of 5. ->>>>>>> fork_master_master - - - + + + `[starting_index..ending_index]`と指定することで、角かっこに範囲を使い、スライスを生成できます。 -ここで、`starting_index`はスライスに含まれる最初の位置、`ending_index`はスライスに含まれる終端位置よりも、 +ここで、`starting_index`はスライスの最初の位置、`ending_index`はスライスの終端位置よりも、 1大きくなります。内部的には、スライスデータ構造は、開始地点とスライスの長さを保持しており、 スライスの長さは`ending_index`から`starting_index`を引いたものに対応します。以上より、 `let world = &s[6..11];`の場合には、`world`は`s`の6バイト目へのポインタと5という長さを保持するスライスになるでしょう。 @@ -439,24 +354,17 @@ fn first_word(s: &String) -> &str { } ``` -<<<<<<< HEAD - + -リスト4-5で取った手段と同じ方法で単語の終端番号を取得しています。つまり、最初の空白を探すことです。 +リスト4-7で取った手段と同じ方法で単語の終端番号を取得しています。つまり、最初の空白を探すことです。 空白を発見したら、文字列の最初と、空白の番号を開始、終了地点として使用して文字列スライスを返しています。 -======= -We get the index for the end of the word in the same way as we did in Listing -4-7, by looking for the first occurrence of a space. When we find a space, we -return a string slice using the start of the string and the index of the space -as the starting and ending indices. ->>>>>>> fork_master_master これで、`first_word`を呼び出すと、元のデータに紐付けられた単独の値を得られるようになりました。 この値は、スライスの開始地点への参照とスライス中の要素数から構成されています。 @@ -469,31 +377,19 @@ as the starting and ending indices. fn second_word(s: &String) -> &str { ``` -<<<<<<< HEAD - + - + -======= -We now have a straightforward API that’s much harder to mess up, because the -compiler will ensure the references into the `String` remain valid. Remember -the bug in the program in Listing 4-8, when we got the index to the end of the -first word but then cleared the string so our index was invalid? That code was -logically incorrect but didn’t show any immediate errors. The problems would -show up later if we kept trying to use the first word index with an emptied -string. Slices make this bug impossible and let us know we have a problem with -our code much sooner. Using the slice version of `first_word` will throw a -compile time error: ->>>>>>> fork_master_master これで、ずっと混乱しにくい素直なAPIになりました。なぜなら、`String`への参照が有効なままであることをコンパイラが、 保証してくれるからです。最初の単語の終端番号を得た時に、 -文字列を空っぽにして先ほどの番号が無効になってしまったリスト4-6のプログラムのバグを覚えていますか? +文字列を空っぽにして先ほどの番号が無効になってしまったリスト4-8のプログラムのバグを覚えていますか? そのコードは、論理的に正しくないのですが、即座にエラーにはなりませんでした。問題は後になってから発生し、 それは空の文字列に対して、最初の単語の番号を使用し続けようとした時でした。スライスならこんなバグはあり得ず、 コードに問題があるなら、もっと迅速に判明します。スライスバージョンの`first_word`を使用すると、 @@ -586,21 +482,14 @@ fn first_word(s: &String) -> &str { fn first_word(s: &str) -> &str { ``` -<<<<<<< HEAD - + もし、文字列スライスがあるなら、それを直接渡せます。`String`オブジェクトがあるなら、 -その`String`全体のスライスを渡せます。Stringへの参照の代わりに文字列スライスを取るよう関数を定義すると、 +その`String`全体のスライスを渡せます。`String`への参照の代わりに文字列スライスを取るよう関数を定義すると、 何も機能を失うことなくAPIをより一般的で有益なものにできるのです。 -======= -If we have a string slice, we can pass that directly. If we have a `String`, we -can pass a slice of the entire `String`. Defining a function to take a string -slice instead of a reference to a `String` makes our API more general and useful -without losing any functionality: ->>>>>>> fork_master_master Filename: src/main.rs @@ -627,7 +516,7 @@ without losing any functionality: - + @@ -656,13 +545,8 @@ fn main() { // first_wordは文字列リテラルのスライスに対して機能する let word = first_word(&my_string_literal[..]); -<<<<<<< HEAD // 文字列リテラルは、すでに文字列スライス*な*ので、 // スライス記法なしでも機能するのだ! -======= - // Because string literals *are* string slices already, - // this works too, without the slice syntax! ->>>>>>> fork_master_master let word = first_word(my_string_literal); } ``` @@ -681,16 +565,11 @@ fn main() { let a = [1, 2, 3, 4, 5]; ``` -<<<<<<< HEAD - - + + -文字列の一部を参照したくなる可能性があるのと同様、配列の一部を参照したくなる可能性もあり、 +文字列の一部を参照したくなる可能性があるのと同様、配列の一部を参照したくなる可能性もあります。 以下のようにすれば、参照することができます: -======= -Just as we might want to refer to a part of a string, we might want to refer -to part of an array. We’d do so like this: ->>>>>>> fork_master_master ```rust let a = [1, 2, 3, 4, 5]; @@ -712,32 +591,20 @@ let slice = &a[1..3]; ## まとめ - - - - - + + + + + -所有権、借用、スライスの概念は、コンパイル時にRustプログラムにおいて、メモリ安全性を確保するものです。 -Rust言語も他のシステムプログラミング言語同様、メモリの使用法について制御させてくれるわけですが、 +所有権、借用、スライスの概念は、コンパイル時にRustプログラムにおいて、メモリ安全性を保証します。 +Rust言語も他のシステムプログラミング言語と同じように、メモリの使用法について制御させてくれるわけですが、 所有者がスコープを抜けたときにデータの所有者に自動的にデータを片付けさせることは、この制御を得るために、 余計なコードを書いてデバッグする必要がないことを意味します。 -<<<<<<< HEAD - - + + 所有権は、Rustの他のいろんな部分が動作する方法に影響を与えるので、これ以降もこれらの概念についてさらに語っていく予定です。 -次の章に移って、`struct`でデータをグループ化することについて見ていきましょう。 -======= -The concepts of ownership, borrowing, and slices ensure memory safety in Rust -programs at compile time. The Rust language gives you control over your memory -usage in the same way as other systems programming languages, but having the -owner of data automatically clean up that data when the owner goes out of scope -means you don’t have to write and debug extra code to get this control. - -Ownership affects how lots of other parts of Rust work, so we’ll talk about -these concepts further throughout the rest of the book. Let’s move on to -Chapter 5 and look at grouping pieces of data together in a `struct`. ->>>>>>> fork_master_master +第5章に移って、`struct`でデータをグループ化することについて見ていきましょう。 diff --git a/second-edition/src/ch12-04-testing-the-librarys-functionality.md b/second-edition/src/ch12-04-testing-the-librarys-functionality.md index 36a08f706..e395cf3e5 100644 --- a/second-edition/src/ch12-04-testing-the-librarys-functionality.md +++ b/second-edition/src/ch12-04-testing-the-librarys-functionality.md @@ -1,4 +1,3 @@ -<<<<<<< HEAD ## テスト駆動開発でライブラリの機能を開発する @@ -293,20 +292,13 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { リスト12-17: `contents`の各行を繰り返す -<<<<<<< HEAD - + -======= -The `lines` method returns an iterator. We’ll talk about iterators in depth in -Chapter 13, but recall that you saw this way of using an iterator in Listing -3-5, where we used a `for` loop with an iterator to run some code on each item -in a collection. ->>>>>>> fork_master_master `lines`メソッドはイテレータを返します。イテレータについて詳しくは、第13章で話しますが、 -リスト3-4でこのようなイテレータの使用法は見かけたことを思い出してください。 +リスト3-5でこのようなイテレータの使用法は見かけたことを思い出してください。 そこでは、イテレータに`for`ループを使用してコレクションの各要素に対して何らかのコードを走らせていました。 diff --git a/second-edition/src/ch13-02-iterators.md b/second-edition/src/ch13-02-iterators.md index 2c5215f61..3ece2d6c7 100644 --- a/second-edition/src/ch13-02-iterators.md +++ b/second-edition/src/ch13-02-iterators.md @@ -32,18 +32,12 @@ let v1_iter = v1.iter(); リスト13-13: イテレータを生成する - + -<<<<<<< HEAD -一旦イテレータを生成したら、いろんな手段で使用することができます。第3章のリスト3-4では、 +一旦イテレータを生成したら、いろんな手段で使用することができます。第3章のリスト3-5では、 ここまで`iter`の呼び出しが何をするかごまかしてきましたが、`for`ループでイテレータを使い、 各要素に何かコードを実行しています。 -======= -Once we’ve created an iterator, we can use it in a variety of ways. In Listing -3-5 in Chapter 3, we used iterators with `for` loops to execute some code on -each item, although we glossed over what the call to `iter` did until now. ->>>>>>> fork_master_master From 8ea80816d305f3166097d842faff0e537cb8256a Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 11 Mar 2018 20:21:16 +0900 Subject: [PATCH 120/428] First draft of the chapter 17-0 --- second-edition/src/ch17-00-oop.md | 35 ++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/second-edition/src/ch17-00-oop.md b/second-edition/src/ch17-00-oop.md index 18dffffa6..b3605a97d 100644 --- a/second-edition/src/ch17-00-oop.md +++ b/second-edition/src/ch17-00-oop.md @@ -1,13 +1,24 @@ -# Is Rust an Object-Oriented Programming Language? + -Object-oriented programming (OOP) is a way of modeling programs. Objects came -from Simula in the 1960s. Those objects influenced Alan Kay’s programming -architecture where objects pass messages to each other. He coined the term -object-oriented programming in 1967 to describe this architecture. Many -competing definitions describe what OOP is; some definitions would classify -Rust as object oriented but other definitions would not. In this chapter, we’ll -explore certain characteristics that are commonly considered object oriented -and how those characteristics translate to idiomatic Rust. We’ll then show you -how to implement an object-oriented design pattern in Rust and discuss the -trade-offs of doing so versus implementing a solution using some of Rust’s -strengths instead. +# Rustはオブジェクト指向プログラミング言語なの? + + + + + + + + + + + + + +オブジェクト指向プログラミング(OOP)は、プログラムをモデル化する手段です。オブジェクトは、 +1960年代のSimulaで導入されました。このオブジェクトは、 +お互いにメッセージを渡し合うというアラン・ケイ(Alan Kay)のプログラミングアーキテクチャに影響を及ぼしました。 +彼は、このアーキテクチャを解説するために、オブジェクト指向プログラミングという用語を造語しました。 +多くの競合する定義がOOPが何かを解説しています; Rustをオブジェクト指向と区分する定義もありますし、 +しない定義もあります。この章では、広くオブジェクト指向と捉えられる特定の特徴と、 +それらの特徴がこなれたRustでどう表現されるかを探求します。それからオブジェクト指向のデザインパターンをRustで実装する方法を示し、 +そうすることとRustの強みを活用して代わりに解決策を実装する方法の代償を議論します。 From 2a3bd07c99ca078f353165feba8cc8ebb590d549 Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Sun, 11 Mar 2018 23:01:25 +0900 Subject: [PATCH 121/428] First draft of the chapter 17-1 --- second-edition/Cargo.lock | 16 +- second-edition/src/ch17-01-what-is-oo.md | 375 +++++++++++++++-------- 2 files changed, 251 insertions(+), 140 deletions(-) diff --git a/second-edition/Cargo.lock b/second-edition/Cargo.lock index 928f6b124..1526f081e 100644 --- a/second-edition/Cargo.lock +++ b/second-edition/Cargo.lock @@ -11,7 +11,7 @@ name = "docopt" version = "0.6.86" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -28,12 +28,12 @@ dependencies = [ [[package]] name = "lazy_static" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.33" +version = "0.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -41,7 +41,7 @@ name = "memchr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -66,7 +66,7 @@ name = "rust-book" version = "0.0.1" dependencies = [ "docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -88,7 +88,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -127,8 +127,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "236eb37a62591d4a41a89b7763d7de3e06ca02d5ab2815446a8bae5d2f8c2d57" -"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff" "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" diff --git a/second-edition/src/ch17-01-what-is-oo.md b/second-edition/src/ch17-01-what-is-oo.md index ccb91a08e..9f64945d5 100644 --- a/second-edition/src/ch17-01-what-is-oo.md +++ b/second-edition/src/ch17-01-what-is-oo.md @@ -1,49 +1,91 @@ -## What Does Object Oriented Mean? - -There is no consensus in the programming community about what features a -language needs to be considered object oriented. Rust is influenced by many -different programming paradigms, including OOP; for example, we explored the -features that came from functional programming in Chapter 13. Arguably, OOP -languages share certain common characteristics, namely objects, encapsulation, -and inheritance. Let’s look at what each of those characteristics mean and -whether Rust supports them. - -### Objects Contain Data and Behavior - -The book *Design Patterns: Elements of Reusable Object-Oriented Software*, -colloquially referred to as *The Gang of Four book*, is a catalog of -object-oriented design patterns. It defines OOP this way: - -> Object-oriented programs are made up of objects. An *object* packages both -> data and the procedures that operate on that data. The procedures are -> typically called *methods* or *operations*. - -Using this definition, Rust is object oriented: structs and enums have data, -and `impl` blocks provide methods on structs and enums. Even though structs and -enums with methods aren’t *called* objects, they provide the same -functionality, according to the Gang of Four’s definition of objects. - -### Encapsulation that Hides Implementation Details - -Another aspect commonly associated with OOP is the idea of *encapsulation*, -which means that the implementation details of an object aren’t accessible to -code using that object. Therefore, the only way to interact with an object is -through its public API; code using the object shouldn’t be able to reach into -the object’s internals and change data or behavior directly. This enables the -programmer to change and refactor an object’s internals without needing to -change the code that uses the object. - -We discussed how to control encapsulation in Chapter 7: we can use the `pub` -keyword to decide which modules, types, functions, and methods in our code -should be public, and by default everything else is private. For example, we -can define a struct `AveragedCollection` that has a field containing a vector -of `i32` values. The struct can also have a field that contains the average of -the values in the vector, meaning the average doesn’t have to be computed -on-demand whenever anyone needs it. In other words, `AveragedCollection` will -cache the calculated average for us. Listing 17-1 has the definition of the -`AveragedCollection` struct: - -Filename: src/lib.rs + + +## オブジェクト指向って? + + + + + + + + + +言語がオブジェクト指向と考えられるのに必要な機能について、プログラミングコミュニティ内での総意はありません。 +RustはOOPを含めた様々なプログラミングパラダイムに影響を受けています; 例えば、 +第13章で関数型プログラミングに由来する機能を探求しました。議論はあるかもしれないが、 +OOP言語は特定の一般的な特徴を共有しています。具体的には、オブジェクトやカプセル化、 +継承などです。それらの個々の特徴が意味するものとRustがサポートしているかを見ましょう。 + + + +### オブジェクトは、データと振る舞いを含む + + + + + +*デザインパターン: 再利用可能なオブジェクト指向ソフトウェアの要素*という本は、 +俗に*4冊の本のギャング*と呼ばれ、オブジェクト指向デザインパターンのカタログです。 +そこでは、OOPは以下のように定義されています: + + + + + +> オブジェクト指向プログラムは、オブジェクトで構成される。オブジェクトは、 +> データとそのデータを処理するプロシージャを包含している。このプロシージャは、 +> 典型的に*メソッド*または*オペレーション*と呼ばれる。 + + + + + + +この定義を使用すれば、Rustはオブジェクト指向です: 構造体とenumにはデータがありますし、 +`impl`ブロックが構造体とenumにメソッドを提供します。メソッドのある構造体とenumは、 +オブジェクトとは呼ばれないものの、4冊の本のギャングのオブジェクト定義によると、 +同じ機能を提供します。 + + + +### カプセル化は、実装詳細を隠蔽する + + + + + + + + + +OOPとよく紐づけられる別の側面は、カプセル化の思想です。これは、オブジェクトの実装詳細は、 +そのオブジェクトを使用するコードにはアクセスできないことを意味します。故に、 +オブジェクトと相互作用する唯一の手段は、その公開APIを通してです; オブジェクトを使用するコードは、 +オブジェクトの内部に到達して、データや振る舞いを直接変更できるべきではありません。 +このために、プログラマはオブジェクトの内部をオブジェクトを使用するコードを変更する必要なく、 +変更しリファクタリングできます。 + + + + + + + + + + + +カプセル化を制御する方法は、第7章で議論しました: `pub`キーワードを使用して、 +自分のコードのどのモジュールや型、関数、メソッドを公開するか決められ、 +規定ではそれ以外のものは全て非公開になります。例えば、 +`i32`値のベクタを含むフィールドのある`AveragedCollection`という構造体を定義できます。 +この構造体はさらに、ベクタの値の平均を含むフィールドを持てます。つまり、平均は誰かが必要とする度に、 +オンデマンドで計算する必要はないということです。言い換えれば、`AveragedCollection`は、 +計算した平均をキャッシュしてくれるわけです。リスト17-1には、`AveragedCollection`構造体の定義があります: + + + +ファイル名: src/lib.rs ```rust pub struct AveragedCollection { @@ -52,17 +94,25 @@ pub struct AveragedCollection { } ``` -Listing 17-1: An `AveragedCollection` struct that -maintains a list of integers and the average of the items in the -collection + + + + +リスト17-1: 整数のリストとコレクションの要素の平均を管理する`AveragedCollection`構造体 + + + + + + -The struct is marked `pub` so that other code can use it, but the fields within -the struct remain private. This is important in this case because we want to -ensure that whenever a value is added or removed from the list, the average is -also updated. We do this by implementing `add`, `remove`, and `average` methods -on the struct, as shown in Listing 17-2: +構造体は、他のコードが使用できるように`pub`で印づけされていますが、構造体のフィールドは非公開のままです。 +値が追加されたりリストから削除される度に、平均も更新されることを保証したいので、今回の場合重要です。 +`add`や`remove`、`average`メソッドを構造体に実装することでこれをします。リスト17-2のようにね: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust # pub struct AveragedCollection { @@ -97,82 +147,143 @@ impl AveragedCollection { } ``` -Listing 17-2: Implementations of the public methods -`add`, `remove`, and `average` on `AveragedCollection` - -The public methods `add`, `remove`, and `average` are the only ways to modify -an instance of `AveragedCollection`. When an item is added to `list` using the -`add` method or removed using the `remove` method, the implementations of each -call the private `update_average` method that handles updating the `average` -field as well. - -We leave the `list` and `average` fields private so there is no way for -external code to add or remove items to the `list` field directly; otherwise, -the `average` field might become out of sync when the `list` changes. The -`average` method returns the value in the `average` field, allowing external -code to read the `average` but not modify it. - -Because we’ve encapsulated the implementation details of `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`, `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 different methods for adding and removing items, so the external -code would likely have to change if it was modifying `list` directly. - -If encapsulation is a required aspect for a language to be considered object -oriented, then Rust meets that requirement. The option to use `pub` or not for -different parts of code enables encapsulation of implementation details. - -### Inheritance as a Type System and as Code Sharing - -*Inheritance* is a mechanism whereby an object can inherit from another -object’s definition, thus gaining the parent object’s data and behavior without -you having to define them again. - -If a language must have inheritance to be an object-oriented language, then -Rust is not. There is no way to define a struct that inherits the parent -struct’s fields and method implementations. However, if you’re used to having -inheritance in your programming toolbox, you can use other solutions in Rust -depending on your reason for reaching for inheritance in the first place. - -You choose inheritance for two main reasons. One is for reuse of code: you can -implement particular behavior for one type, and inheritance enables you to -reuse that implementation for a different type. You can share Rust code using -default trait method implementations instead, which you saw in Listing 10-14 -when we added a default implementation of the `summarize` method on the -`Summary` trait. Any type implementing the `Summary` trait would have the -`summarize` method available on it without any further code. This is similar to -a parent class having an implementation of a method and an inheriting child -class also having the implementation of the method. We can also override the -default implementation of the `summarize` method when we implement the -`Summary` trait, which is similar to a child class overriding the -implementation of a method inherited from a parent class. - -The other reason to use inheritance relates to the type system: to enable a -child type to be used in the same places as the parent type. This is also -called *polymorphism*, which means that you can substitute multiple objects for -each other at runtime if they share certain characteristics. - -> ### Polymorphism + + + +リスト17-2: `AveragedCollection`の`add`、`remove`、`average`公開メソッドの実装 + + + + + + + +`add`、`remove`、`average`の公開メソッドが`AveragedCollection`のインスタンスを変更する唯一の方法になります。 +要素が`add`メソッドを使用して`list`に追加されたり、`remove`メソッドを使用して削除されたりすると、 +各メソッドの実装が`average`フィールドの更新を扱う非公開の`update_average`メソッドも呼び出します。 + + + + + + + +`list`と`average`フィールドを非公開のままにしているので、外部コードが要素を`list`フィールドに直接追加したり削除したりする方法はありません; +そうでなければ、`average`フィールドは、`list`が変更された時に同期されなくなる可能性があります。 +`average`メソッドは`average`フィールドの値を返し、外部コードに`average`を読ませるものの、 +変更は許可しません。 + + + + + + + + + + +`AveragedCollection`の実装詳細をカプセル化したので、データ構造などの側面を将来容易に変更することができます。 +例を挙げれば、`list`フィールドに`Vec`ではなく`HashSet`を使うこともできます。 +`add`、`remove`、`average`公開メソッドのシグニチャが同じである限り、`AveragedCollection`を使用するコードは変更する必要がありません。 +代わりに`list`を公開にしたら、必ずしもこうはならないでしょう: `HashSet`と`Vec`は、 +要素の追加と削除に異なるメソッドを持っているので、外部コードが直接`list`を変更しているなら、 +外部コードも変更しなければならない可能性が高いでしょう。 + + + + + +カプセル化が、言語がオブジェクト指向と考えられるのに必要な側面ならば、Rustはその条件を満たしています。 +コードの異なる部分で`pub`を使用するかしないかという選択肢のおかげで、実装詳細をカプセル化することが可能になります。 + + + +### 型システム、およびコード共有としての継承 + + + + + +継承は、それによってオブジェクトが他のオブジェクトの定義から受け継ぐことができる機構であり、 +それ故に、再定義する必要なく、親オブジェクトのデータと振る舞いを得ます。 + + + + + + + +言語がオブジェクト指向言語であるために継承がなければならないのならば、Rustは違います。 +親構造体のフィールドとメソッドの実装を受け継ぐ構造体を定義する方法はありません。しかしながら、 +継承がプログラミング道具箱にあることに慣れていれば、そもそも継承に手を伸ばす理由によって、 +Rustで他の解決策を使用することができます。 + + + + + + + + + + + + + + +継承を選択する理由は2つあります。1つ目は、コードの再利用です: ある型に特定の振る舞いを実装し、 +継承により、その実装を他の型にも再利用できるわけです。デフォルトのトレイトメソッド実装を代わりに使用して、 +Rustコードを共有でき、リスト10-14で`Summary`トレイトに`summarize`メソッドのデフォルト実装を追加した時に見かけました。 +`Summary`トレイトを実装する型は全て、追加のコードなく`summarize`メソッドが使用できます。 +これは、親クラスにメソッドの実装があり、継承した子クラスにもそのメソッドの実装があることと似ています。 +また、`Summary`トレイトを実装する時に、`summarize`メソッドのデフォルト実装を上書きすることもでき、 +これは、親クラスから継承したメソッドの実装を子クラスが上書きすることに似ています。 + + + + + + +継承を使用するもう1つの理由は、型システムに関連しています: 親の型と同じ箇所で子供の型を使用できるようにです。 +これは、*多相性*(polymorphism)とも呼ばれ、複数のオブジェクトが特定の特徴を共有しているなら、 +実行時にお互いに代用できることを意味します。 + + + + + + + + + + + +> ### 多相性 > -> To many people, polymorphism is synonymous with inheritance. But it’s -> actually a more general concept that refers to code that can work with data -> of multiple types. For inheritance, those types are generally subclasses. +> 多くの人にとって、多相性は、継承の同義語です。ですが、実際には複数の型のデータを取り扱えるコードを指すより一般的な概念です。 +> 継承について言えば、それらの型は一般的にはサブクラスです。 > -> Rust instead uses generics to abstract over different possible types and -> trait bounds to impose constraints on what those types must provide. This is -> sometimes called *bounded parametric polymorphism*. - -Inheritance has recently fallen out of favor as a programming design solution -in many programming languages because it’s often at risk of sharing more code -than needs be. 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 and 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. - -For these reasons, Rust takes a different approach, using trait objects instead -of inheritance. Let’s look at how trait objects enable polymorphism in Rust. +> Rustは代わりにジェネリクスを使用して様々な可能性のある型を抽象化し、トレイト境界を使用してそれらの型が提供するものに制約を課します。 +> これは時に、*パラメータ境界多相性*(bounded parametric polymorphism)と呼ばれます。 + + + + + + + + + + +継承は、最近、多くのプログラミング言語において、プログラムの設計解決策としては軽んじられています。 +というのも、しばしば必要以上にコードを共有してしまう危険性があるからです。サブクラスは、 +必ずしも親クラスの特徴を全て共有するべきではないのに、継承ではそうなってしまうのです。 +これにより、プログラムの設計の柔軟性がなくなり、道理に合わなかったり、メソッドがサブクラスには適用されないために、 +エラーを発生させるサブクラスのメソッドの呼び出しを引き起こす可能性が出てくるのです。 +さらに、サブクラスに1つのクラスからだけ継承させる言語もあり、さらにプログラムの設計の柔軟性が制限されます。 + + + + +これらの理由により、継承ではなくトレイトオブジェクトを使用してRustは異なるアプローチを取っています。 +Rustにおいて、トレイトオブジェクトが多相性を可能にする方法を見ましょう。 From ee4960cb2749a261d0ec85584de5a1d4fa9f569b Mon Sep 17 00:00:00 2001 From: HAZAMA Date: Mon, 12 Mar 2018 20:09:23 +0900 Subject: [PATCH 122/428] First draft of the chapter 17-2 --- second-edition/src/ch17-01-what-is-oo.md | 2 +- second-edition/src/ch17-02-trait-objects.md | 647 +++++++++++++------- 2 files changed, 429 insertions(+), 220 deletions(-) diff --git a/second-edition/src/ch17-01-what-is-oo.md b/second-edition/src/ch17-01-what-is-oo.md index 9f64945d5..ac4252915 100644 --- a/second-edition/src/ch17-01-what-is-oo.md +++ b/second-edition/src/ch17-01-what-is-oo.md @@ -233,7 +233,7 @@ Rustで他の解決策を使用することができます。 継承を選択する理由は2つあります。1つ目は、コードの再利用です: ある型に特定の振る舞いを実装し、 継承により、その実装を他の型にも再利用できるわけです。デフォルトのトレイトメソッド実装を代わりに使用して、 -Rustコードを共有でき、リスト10-14で`Summary`トレイトに`summarize`メソッドのデフォルト実装を追加した時に見かけました。 +Rustコードを共有でき、これは、リスト10-14で`Summary`トレイトに`summarize`メソッドのデフォルト実装を追加した時に見かけました。 `Summary`トレイトを実装する型は全て、追加のコードなく`summarize`メソッドが使用できます。 これは、親クラスにメソッドの実装があり、継承した子クラスにもそのメソッドの実装があることと似ています。 また、`Summary`トレイトを実装する時に、`summarize`メソッドのデフォルト実装を上書きすることもでき、 diff --git a/second-edition/src/ch17-02-trait-objects.md b/second-edition/src/ch17-02-trait-objects.md index 90fad14a5..79ba9e91d 100644 --- a/second-edition/src/ch17-02-trait-objects.md +++ b/second-edition/src/ch17-02-trait-objects.md @@ -1,70 +1,122 @@ -## Using Trait Objects that Allow for Values of Different Types - -In Chapter 8, we mentioned that one limitation of vectors is that they can only -store elements of one type. We created a workaround in Listing 8-10 where we -defined a `SpreadsheetCell` enum that had variants to hold integers, floats, -and text. This meant we could store different types of data in each cell and -still have a vector that represented a row of cells. This is a perfectly good -solution when our interchangeable items are a fixed set of types that we know -when our code is compiled. - -However, sometimes we want our library user to be able to extend the set of -types that are valid in a particular situation. To show how we might achieve -this, we’ll create an example graphical user interface (GUI) tool that iterates -through a list of items, calling a `draw` method on each one to draw it to the -screen—a common technique for GUI tools. We’ll create a library crate called -`gui` that contains the structure of a GUI library. This crate might include -some types for people to use, such as `Button` or `TextField`. In addition, -`gui` users will want to create their own types that can be drawn: for -instance, one programmer might add an `Image` and another might add a -`SelectBox`. - -We won’t implement a fully fledged GUI library for this example but will show -how the pieces would fit together. At the time of writing the library, we can’t -know and define all the types other programmers might want to create. But we do -know that `gui` needs to keep track of many values of different types, and it -needs to call a `draw` method on each of these differently typed values. It -doesn’t need to know exactly what will happen when we call the `draw` method, -just that the value will have that method available for us to call. - -To do this in a language with inheritance, we might define a class named -`Component` that has a method named `draw` on it. The other classes, such as -`Button`, `Image`, and `SelectBox`, would inherit from `Component` and thus -inherit the `draw` method. They could each override the `draw` method to define -their custom behavior, but the framework could treat all of the types as if -they were `Component` instances and call `draw` on them. But because Rust -doesn’t have inheritance, we need another way to structure the `gui` library to -allow users to extend it with new types. - -### Defining a Trait for Common Behavior - -To implement the behavior we want `gui` to have, we’ll define a trait named -`Draw` that will have one method named `draw`. Then we can define a vector that -takes a *trait object*. A trait object points to an instance of a type that -implements the trait we specify. We create a trait object by specifying some -sort of pointer, such as a `&` reference or a `Box` smart pointer, and then -specifying the relevant trait (we’ll talk about the reason trait objects must -use a pointer in Chapter 19 in the section “Dynamically Sized Types & Sized”). -We can use trait objects in place of a generic or concrete type. Wherever we -use a trait object, Rust’s type system will ensure at compile time that any -value used in that context will implement the trait object’s trait. -Consequently, we don’t need to know all the possible types at compile time. - -We’ve mentioned that in Rust we refrain from calling structs and enums -“objects” to distinguish them from other languages’ objects. In a struct or -enum, the data in the struct fields and the behavior in `impl` blocks are -separated, whereas in other languages the data and behavior combined into one -concept is often labeled an object. However, trait objects *are* more like -objects in other languages in the sense that they combine data and behavior. -But trait objects differ from traditional objects in that we can’t add data to -a trait object. Trait objects aren’t as generally useful as objects in other -languages: their specific purpose is to allow abstraction across common -behavior. - -Listing 17-3 shows how to define a trait named `Draw` with one method named -`draw`: - -Filename: src/lib.rs + + +## トレイトオブジェクトで異なる型の値を許可する + + + + + + + + + +第8章で、ベクタの1つの制限は、1つの型の要素を保持することしかできないことだと述べました。 +リスト8-10で整数、浮動小数点数、テキストを保持する列挙子のある`SpreadsheetCell`enumを定義して、 +これを回避しました。つまり、各セルに異なる型のデータを格納しつつ、1行のセルを表すベクタを保持するということです。 +コンパイル時にわかるある固定されたセットの型にしか取り替え可能な要素がならない場合には、 +完璧な解決策です。 + + + + + + + + + + + + +ところが、時として、ライブラリの使用者が特定の場面で有効になる型のセットを拡張できるようにしたくなることがあります。 +これをどう実現する可能性があるか示すために、各アイテムに`draw`メソッドを呼び出してスクリーンに描画するという、 +GUIツールで一般的なテクニックをしてあるリストの要素を繰り返すGUIツールの例を作ります。 +GUIライブラリの構造を含む`gui`と呼ばれるライブラリクレートを作成します。 +このクレートには、他人が使用できる`Button`や`TextField`などの型が包含される可能性があります。 +さらに、`gui`の使用者は、描画可能な独自の型を作成したくなるでしょう: 例えば、 +ある人は`Image`を追加し、別の人は`SelectBox`を追加する可能性があります。 + + + + + + + + + +この例のために本格的なGUIライブラリは実装するつもりはありませんが、部品がどう組み合わさるかは示します。 +ライブラリの記述時点では、他のプログラマが作成したくなる可能性のある型全てを知る由も、定義することもできません。 +しかし、`gui`は異なる型の多くの値を追いかけ、この異なる型の値に対して`draw`メソッドを呼び出す必要があることは、 +確かにわかっています。`draw`メソッドを呼び出した時に正確に何が起きるかを知っている必要はありません。 +値にそのメソッドが呼び出せるようあることだけわかっていればいいのです。 + + + + + + + + + + +継承のある言語でこれを行うには、`draw`という名前のメソッドがある`Component`というクラスを定義する可能性があります。 +`Button`、`Image`、`SelectBox`などの他のクラスは、`Component`を継承し、故に`draw`メソッドを継承します。 +個々に`draw`メソッドをオーバーライドして、独自の振る舞いを定義するものの、フレームワークは、 +`Component`インスタンスであるかのようにその型全部を扱い、この型に対して`draw`を呼び出します。 +ですが、Rustに継承は存在しないので、`gui`ライブラリを構成する他の方法を必要として、 +使用者に新しい型で拡張してもらいます。 + + + +### 一般的な振る舞いにトレイトを定義する + + + + + + + + + + + + + +`gui`に欲しい振る舞いを実装するには、`draw`という1つのメソッドを持つ`Draw`というトレイトを定義します。 +それから*トレイトオブジェクト*を取るベクタを定義できます。トレイトオブジェクトは、 +指定したトレイトを実装するある型のインスタンスを指します。`&`参照や`Box`スマートポインタなどの、 +何らかのポインタを指定し、それから関係のあるトレイトを指定する(トレイトオブジェクトがポインタを使用しなければならない理由については、 +第19章の「動的サイズ型とSized」節で語ります)ことでトレイトオブジェクトを作成します。 +ジェネリックまたは具体的な型があるところにトレイトオブジェクトは使用できます。どこでトレイトオブジェクトを使用しようと、 +Rustの型システムは、コンパイル時にその文脈で使用されているあらゆる値がそのトレイトオブジェクトのトレイトを実装していると保証します。 +結果的にコンパイル時に可能性のある型を全て知る必要はなくなるのです。 + + + + + + + + + + + + +Rustでは、構造体とenumを他の言語のオブジェクトと区別するために「オブジェクト」と呼ぶことを避けていることに触れましたね。 +構造体やenumにおいて、構造体のフィールドのデータや`impl`ブロックの振る舞いは区分けされているものの、 +他の言語では1つの概念に押し込められるデータと振る舞いにはしばしばオブジェクトというレッテルが貼られます。 +しかしながら、トレイトオブジェクトは、データと振る舞いをごちゃ混ぜにするという観点で他の言語のオブジェクトに近い*です*。 +しかし、トレイトオブジェクトは、それにデータを追加できないという点で伝統的なオブジェクトと異なっています。 +トレイトオブジェクトは、他の言語のオブジェクトほど一般的に有用ではありません: +その目的は、共通の振る舞いに対して抽象化を行うことです。 + + + + +リスト17-3は、`draw`という1つのメソッドを持つ`Draw`というトレイトを定義する方法を示しています: + + + +ファイル名: src/lib.rs ```rust pub trait Draw { @@ -72,15 +124,24 @@ pub trait Draw { } ``` -Listing 17-3: Definition of the `Draw` trait + -This syntax should look familiar from our discussions on how to define traits -in Chapter 10. Next comes some new syntax: Listing 17-4 defines a struct named -`Screen` that holds a vector named `components`. This vector is of type -`Box`, which is a trait object: it’s a stand-in for any type inside a -`Box` that implements the `Draw` trait. +リスト17-3: `Draw`トレイトの定義 -Filename: src/lib.rs + + + + + + +この記法は、第10章のトレイトの定義方法に関する議論で馴染み深いはずです。その次は、新しい記法です: +リスト17-4では、`components`というベクタを保持する`Screen`という名前の構造体を定義しています。 +このベクタの型は`Box`で、これはトレイトオブジェクトです: `Draw`トレイトを実装する`Box`内部の、 +任意の型に対する代役です。 + + + +ファイル名: src/lib.rs ```rust # pub trait Draw { @@ -92,14 +153,22 @@ pub struct Screen { } ``` -Listing 17-4: Definition of the `Screen` struct with a -`components` field holding a vector of trait objects that implement the `Draw` -trait + + + + +リスト17-4: `Draw`トレイトを実装するトレイトオブジェクトのベクタを保持する`components`フィールドがある +`Screen`構造体の定義 + + + -On the `Screen` struct, we’ll define a method named `run` that will call the -`draw` method on each of its `components`, as shown in Listing 17-5: +`Screen`構造体に、`components`の各要素に対して`draw`メソッドを呼び出す`run`というメソッドを定義します。 +リスト17-5のようにね: -Filename: src/lib.rs + + +ファイル名: src/lib.rs ```rust # pub trait Draw { @@ -119,17 +188,26 @@ impl Screen { } ``` -Listing 17-5: Implementing a `run` method on `Screen` -that calls the `draw` method on each component + + + +リスト17-5: `Screen`に各コンポーネントに対して`draw`メソッドを呼び出す`run`メソッドを実装する + + + + + + + + +これは、トレイト境界を含むジェネリックな型引数を使用する構造体を定義するのとは異なる動作をします。 +ジェネリックな型引数は、一度に1つの型にしか置き換えられないのに対して、トレイトオブジェクトは、 +実行時にトレイトオブジェクトに対して複数の型で埋めることができます。例として、 +ジェネリックな型とトレイト境界を使用してリスト17-6のように`Screen`構造体を定義することもできました: -This works differently than defining a struct that uses a generic type -parameter with trait bounds. A generic type parameter can only be substituted -with one concrete type at a time, whereas trait objects allow for multiple -concrete types to fill in for the trait object at runtime. For example, we -could have defined the `Screen` struct using a generic type and a trait bound -as in Listing 17-6: + -Filename: src/lib.rs +ファイル名: src/lib.rs ```rust # pub trait Draw { @@ -150,28 +228,47 @@ impl Screen } ``` -Listing 17-6: An alternate implementation of the `Screen` -struct and its `run` method using generics and trait bounds + + -This restricts us to a `Screen` instance that has a list of components all of -type `Button` or all of type `TextField`. If you’ll only ever have homogeneous -collections, using generics and trait bounds is preferable because the -definitions will be monomorphized at compile time to use the concrete types. +リスト17-6: ジェネリクスとトレイト境界を使用した`Screen`構造体と`run`メソッドの対立的な実装 -On the other hand, with the method using trait objects, one `Screen` instance -can hold a `Vec` that contains a `Box + + + {{#if search_enabled}} + + {{/if}} + + +

{{ book_title }}

+ +
+ + + +
+ + + + {{#if search_enabled}} + + {{/if}} + + + + +
+
+ {{{ content }}} +
+ + +
+ + + + + + + {{#if livereload}} + + + {{/if}} + + {{#if google_analytics}} + + + {{/if}} + + {{#if playpen_js}} + + + + + + {{/if}} + + {{#if search_enabled}} + + {{/if}} + {{#if search_js}} + + + + {{/if}} + + + + + + + {{#each additional_js}} + + {{/each}} + + {{#if is_print}} + {{#if mathjax_support}} + + {{else}} + + {{/if}} + {{/if}} + + + From 019be9faef1bbcc540422f172cc11f6ec371eb56 Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Mon, 12 Oct 2020 20:00:16 +0800 Subject: [PATCH 428/428] Add meta robots noindex to index.hbs --- second-edition/theme/index.hbs | 1 + 1 file changed, 1 insertion(+) diff --git a/second-edition/theme/index.hbs b/second-edition/theme/index.hbs index 0e5fa009a..66f743e9c 100644 --- a/second-edition/theme/index.hbs +++ b/second-edition/theme/index.hbs @@ -8,6 +8,7 @@ + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy