diff --git a/listings/ch04-understanding-ownership/listing-04-08/src/main.rs b/listings/ch04-understanding-ownership/listing-04-08/src/main.rs index b6182fe2b..481dc9271 100644 --- a/listings/ch04-understanding-ownership/listing-04-08/src/main.rs +++ b/listings/ch04-understanding-ownership/listing-04-08/src/main.rs @@ -15,10 +15,14 @@ fn main() { let mut s = String::from("hello world"); let word = first_word(&s); // word will get the value 5 + // wordの中身は、値5になる s.clear(); // this empties the String, making it equal to "" + // 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は今や完全に無効なのだ! } // ANCHOR_END: here diff --git a/listings/ch04-understanding-ownership/listing-04-09/src/main.rs b/listings/ch04-understanding-ownership/listing-04-09/src/main.rs index 19a9cc74b..b3447e826 100644 --- a/listings/ch04-understanding-ownership/listing-04-09/src/main.rs +++ b/listings/ch04-understanding-ownership/listing-04-09/src/main.rs @@ -17,15 +17,19 @@ 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[..]); // Because string literals *are* string slices already, // this works too, without the slice syntax! + // 文字列リテラルは「それ自体すでに文字列スライスなので」、 + // スライス記法なしでも機能するのだ! let word = first_word(my_string_literal); } // ANCHOR_END: usage diff --git a/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt b/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt index 0e95bb8cd..a1d9caf11 100644 --- a/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt +++ b/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt @@ -1,16 +1,20 @@ $ cargo run Compiling ownership v0.1.0 (file:///projects/ownership) error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable +(エラー: 不変として借用されているので、`s`を可変で借用できません) --> src/main.rs:18:5 | 16 | let word = first_word(&s); | -- immutable borrow occurs here + | (不変借用はここで発生しています) 17 | 18 | s.clear(); // error! | ^^^^^^^^^ mutable borrow occurs here + | (可変借用はここで発生しています) 19 | 20 | println!("the first word is: {}", word); | ---- immutable borrow later used here + (不変借用はその後ここで使われています) error: aborting due to previous error diff --git a/listings/ch04-understanding-ownership/no-listing-19-slice-error/src/main.rs b/listings/ch04-understanding-ownership/no-listing-19-slice-error/src/main.rs index 99e04018d..400d5c897 100644 --- a/listings/ch04-understanding-ownership/no-listing-19-slice-error/src/main.rs +++ b/listings/ch04-understanding-ownership/no-listing-19-slice-error/src/main.rs @@ -16,7 +16,7 @@ fn main() { let word = first_word(&s); - s.clear(); // error! + s.clear(); // error! (エラー!) println!("the first word is: {}", word); } diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index 209610080..28c557028 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -10,7 +10,7 @@ reference a contiguous sequence of elements in a collection rather than the whole collection. --> -所有権のない別のデータ型は、*スライス*です。スライスにより、コレクション全体というより、 +所有権のない別のデータ型は、*スライス*です。スライスにより、コレクション全体ではなく、 その内の一連の要素を参照することができます。 -ここに小さなプログラミング問題があります: 文字列を受け取って、その文字列中の最初の単語を返す関数を書いてください。 -関数が文字列中に空白を見つけなかったら、文字列全体が一つの単語に違いないので、文字列全体が返されるべきです。 +ちょっとしたプログラミングの問題を考えてみましょう: 文字列を受け取って、その文字列中の最初の単語を返す関数を書いてください。 +関数が文字列中に空白を見つけられなかったら、文字列全体が一つの単語に違いないので、文字列全体が返されるべきです。 この関数、`first_word`は引数に`&String`をとります。所有権はいらないので、これで十分です。 @@ -51,17 +51,7 @@ end of the word. Let’s try that as shown in Listing 4-7. ファイル名: src/main.rs ```rust -fn first_word(s: &String) -> usize { - let bytes = s.as_bytes(); - - for (i, &item) in bytes.iter().enumerate() { - if item == b' ' { - return i; - } - } - - s.len() -} +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-07/src/main.rs:here}} ``` イテレータについて詳しくは、第13章で議論します。今は、`iter`は、コレクション内の各要素を返すメソッドであること、 -`enumerate`が`iter`の結果を包んで、代わりにタプルの一部として各要素を返すことを知っておいてください。 -`enumerate`から返ってくるタプルの第1要素は、添え字であり、2番目の要素は、(コレクションの)要素への参照になります。 +`enumerate`が`iter`の結果をラップして、(結果をそのまま返す)代わりにタプルの一部として各要素を返すことを知っておいてください。 +`enumerate`から返ってくるタプルの第1要素は、添え字であり、2番目の要素は、(コレクションの)要素への参照になります。 これは、手動で添え字を計算するよりも少しだけ便利です。 @@ -130,12 +120,7 @@ Otherwise, we return the length of the string by using `s.len()`: それ以外の場合、`s.len()`を使って文字列の長さを返します。 ```rust,ignore - if item == b' ' { - return i; - } -} - -s.len() +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-07/src/main.rs:inside_for}} ``` - - - - - - - -```rust -# fn first_word(s: &String) -> usize { -# let bytes = s.as_bytes(); -# -# for (i, &item) in bytes.iter().enumerate() { -# if item == b' ' { -# return i; -# } -# } -# -# s.len() -# } -# -fn main() { - let mut s = String::from("hello world"); - - let word = first_word(&s); // wordの中身は、値5になる - - s.clear(); // Stringを空にする。つまり、""と等しくする - - // wordはまだ値5を保持しているが、もうこの値を有効に使用できる文字列は存在しない。 - // wordは完全に無効なのだ! -} +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-08/src/main.rs:here}} ``` リスト4-8: `first_word`関数の呼び出し結果を保持し、`String`の中身を変更する -今、私たちは開始*と*終端の添え字を追うようになりました。特定の状態のデータから計算されたけど、 -その状態に全く紐付かない値が増えました。いつの間にか変わってしまうので、同期を取る必要のある、関連性のない変数が3つになってしまいました。 +今、私たちは開始*と*終端の添え字を追うようになりました。特定の状態のデータから計算されたが、 +その状態に全く紐付けられていない値がさらに増えました。いつの間にか変わってしまうので、同期を取る必要のある、関連性のない変数が3つになってしまいました。 これは、`String`全体への参照を取ることに似ていますが、余計な`[0..5]`という部分が付いています。 -`String`全体への参照というよりも、`String`の一部への参照です。`開始..終点`という記法は、`開始`から始まり、 -`終点`未満までずっと続く範囲です。 +`String`全体への参照ではなく、`String`の一部への参照です。 `[starting_index..ending_index]`と指定することで、角かっこに範囲を使い、スライスを生成できます。 ここで、`starting_index`はスライスの最初の位置、`ending_index`はスライスの終端位置よりも、 -1大きくなります。内部的には、スライスデータ構造は、開始地点とスライスの長さを保持しており、 +1大きい値です。内部的には、スライスデータ構造は、開始地点とスライスの長さを保持しており、 スライスの長さは`ending_index`から`starting_index`を引いたものに対応します。以上より、 -`let world = &s[6..11];`の場合には、`world`は`s`の7バイト目へのポインタと5という長さを保持するスライスになるでしょう。 +`let world = &s[6..11];`の場合には、`world`は`s`の(1から数えて)7バイト目へのポインタと5という長さを保持するスライスになるでしょう。 -Rustの`..`という範囲記法で、最初の番号(ゼロ)から始めたければ、2連ピリオドの前に値を書かなければいいのです。 +Rustの`..`という範囲記法で、最初の番号(ゼロ)から始めたければ、2連ピリオドの前に値を書かなければいいです。 換言すれば、これらは等価です: ```rust @@ -351,7 +277,7 @@ 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`の最後のバイトをスライスが含むのならば、末尾の数値を書かなければいいのです。 +同様の意味で、`String`の最後のバイトをスライスが含むのならば、末尾の数値を書かなければいいです。 つまり、これらは等価になります: ```rust @@ -380,25 +306,25 @@ let slice = &s[..]; ``` > 注釈: 文字列スライスの範囲添え字は、有効なUTF-8文字境界に置かなければなりません。 > マルチバイト文字の真ん中で文字列スライスを生成しようとしたら、エラーでプログラムは落ちるでしょう。 -> 文字列スライスを導入する目的で、この節ではASCIIのみを想定しています; UTF-8に関するより徹底した議論は、 -> 第8章の「文字列でUTF-8エンコードされたテキストを格納する」節で行います。 +> この節では文字列スライスを導入することが目的なので、ASCIIのみを想定しています; UTF-8に関するより徹底した議論は、 +> 第8章の[「文字列でUTF-8エンコードされたテキストを格納する」][strings]節で行います。 -これら全ての情報を心に留めて、`first_word`を書き直してスライスを返すようにしましょう。 +これらの情報を念頭に、`first_word`を書き直してスライスを返すようにしましょう。 文字列スライスを意味する型は、`&str`と記述します: -リスト4-7で取った手段と同じ方法で単語の終端添え字を取得しています。つまり、最初の空白を探すことです。 +リスト4-7で取った方法と同じように、最初の空白を探すことで単語の終端の添え字を取得しています。 空白を発見したら、文字列の最初を開始地点、空白の添え字を終了地点として使用して文字列スライスを返しています。 src/main.rs:18:5 - | -16 | let word = first_word(&s); - | -- immutable borrow occurs here (不変借用はここで発生しています) -17 | -18 | s.clear(); // error! (エラー!) - | ^^^^^^^^^ mutable borrow occurs here (可変借用はここで発生しています) -19 | -20 | println!("the first word is: {}", word); - | ---- immutable borrow later used here - (不変借用はその後ここで使われています) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. -error: could not compile `ownership`. - -To learn more, run the command again with --verbose. +```console +{{#include ../listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt}} ``` 借用規則から、何かへの不変な参照がある時、さらに可変な参照を得ることはできないことを思い出してください。 -`clear`は`String`を切り詰める必要があるので、可変な参照を得ようとして失敗しているわけです。 +`clear`は`String`を切り詰める必要があるので、可変な参照を得る必要があります。Rustはこれを認めないので、コンパイルが失敗します。 RustのおかげでAPIが使いやすくなるだけでなく、ある種のエラー全てを完全にコンパイル時に排除してくれるのです! もっと経験を積んだRustaceanなら、代わりにリスト4-9のようなシグニチャを書くでしょう。というのも、こうすると、 -同じ関数を`String`値と`&str`値両方に使えるようになるからです。 +同じ関数を`&String`値と`&str`値両方に使えるようになるからです。 ```rust,ignore -fn first_word(s: &str) -> &str { +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-09/src/main.rs:here}} ``` - - - - - - - - - ```rust -# fn first_word(s: &str) -> &str { -# let bytes = s.as_bytes(); -# -# for (i, &item) in bytes.iter().enumerate() { -# if item == b' ' { -# return &s[0..i]; -# } -# } -# -# &s[..] -# } -fn main() { - let my_string = String::from("hello world"); - - // first_wordは`String`のスライスに対して機能する - let word = first_word(&my_string[..]); - - let my_string_literal = "hello world"; - - // first_wordは文字列リテラルのスライスに対して機能する - let word = first_word(&my_string_literal[..]); - - // 文字列リテラルは、すでに文字列スライス*な*ので、 - // スライス記法なしでも機能するのだ! - let word = first_word(my_string_literal); -} +{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-09/src/main.rs:usage}} ``` 文字列の一部を参照したくなる可能性があるのと同様、配列の一部を参照したくなる可能性もあります。 @@ -717,9 +540,9 @@ detail when we talk about vectors in Chapter 8. --> このスライスは、`&[i32]`という型になります。これも文字列スライスと同じように動作します。 -つまり、最初の要素への参照と長さを保持することです。他のすべての種類のコレクションに対して、 -この種のスライスは使用するでしょう。これらのコレクションについて詳しくは、 -第8章でベクタについて話すときに議論します。 +つまり、最初の要素への参照と長さを保持するのです。 +この種のスライスは、他のすべての種類のコレクションに対して使用することになるでしょう。 +それらのコレクションについて、詳しくは、第8章でベクタについて話すときに議論します。 -所有権、借用、スライスの概念は、コンパイル時にRustプログラムにおいて、メモリ安全性を保証します。 +所有権、借用、スライスの概念は、Rustプログラムにおいて、コンパイル時にメモリ安全性を保証します。 Rust言語も他のシステムプログラミング言語と同じように、メモリの使用法について制御させてくれるわけですが、 -所有者がスコープを抜けたときにデータの所有者に自動的にデータを片付けさせることは、この制御を得るために、 -余計なコードを書いてデバッグする必要がないことを意味します。 +データの所有者がスコープを抜けたときに、所有者に自動的にデータを片付けさせることは、この制御をするために、 +余計なコードを書いたりデバッグしたりする必要がないことを意味します。 +[strings]: ch08-02-strings.html#文字列でutf-8でエンコードされたテキストを保持する