diff --git a/1.6/ja/book/glossary.md b/1.6/ja/book/glossary.md index 3afbaea5..d71ca264 100644 --- a/1.6/ja/book/glossary.md +++ b/1.6/ja/book/glossary.md @@ -38,11 +38,13 @@ let z = (8, 2, 6); In the example above `x` and `y` have arity 2. `z` has arity 3. -### Bounds + +### 境界 -Bounds are constraints on a type or [trait][traits]. For example, if a bound + +境界(Bounds)とはある1つの型または [トレイト][traits] における制約のことです。例えば、ある関数がとる引数に境界が設定されたとすると、その関数に渡される型は設定された制約に必ず従わなければなりません。 [traits]: traits.html diff --git a/1.6/ja/book/traits.md b/1.6/ja/book/traits.md index f9e3299f..e60916fb 100644 --- a/1.6/ja/book/traits.md +++ b/1.6/ja/book/traits.md @@ -1,10 +1,13 @@ -% Traits +% トレイト + -A trait is a language feature that tells the Rust compiler about -functionality a type must provide. + +トレイトはある型が提供しなければならない機能をRustのコンパイラに伝える言語機能です。 -Recall the `impl` keyword, used to call a function with [method -syntax][methodsyntax]: + +[メソッド構文][methodsyntax]で関数を呼び出すのに用いていた、 `impl` キーワードを思い出して下さい。 ```rust struct Circle { @@ -22,8 +25,10 @@ impl Circle { [methodsyntax]: method-syntax.html -Traits are similar, except that we first define a trait with a method -signature, then implement the trait for a type. In this example, we implement the trait `HasArea` for `Circle`: + +始めにトレイトをメソッドのシグネチャと共に定義し、続いてある型のためにトレイトを実装するという流れを除けばトレイトはメソッド構文に似ています。 +この例では、 `Circle` に `HasArea` トレイトを実装しています。 ```rust struct Circle { @@ -43,15 +48,18 @@ impl HasArea for Circle { } ``` -As you can see, the `trait` block looks very similar to the `impl` block, + +このように、 `trait` ブロックは `impl` ブロックにとても似ているように見えますが、関数本体を定義せず、型シグネチャだけを定義しています。トレイトを `impl` するときは、ただ `impl Item` とするのではなく、 `impl Trait for Item` と記述します。 -## Trait bounds on generic functions + +## ジェネリック関数におけるトレイト境界 -Traits are useful because they allow a type to make certain promises about its + +トレイトはある型の振る舞いを確約できるため有用です。ジェネリック関数は制約、あるいは [境界][bounds] が許容する型のみを受け取るためにトレイトを利用できます。以下の関数を考えて下さい、これはコンパイルできません。 [bounds]: glossary.html#bounds @@ -61,15 +69,17 @@ fn print_area(shape: T) { } ``` -Rust complains: + +Rustは以下のエラーを吐きます。 ```text error: no method named `area` found for type `T` in the current scope ``` -Because `T` can be any type, we can’t be sure that it implements the `area` + +`T` はあらゆる型になれるため、 `area` メソッドが実装されているか確認できません。ですがジェネリックな `T` にはトレイト境界を追加でき、境界が実装を保証してくれます。 ```rust # trait HasArea { @@ -80,11 +90,13 @@ fn print_area(shape: T) { } ``` -The syntax `` means “any type that implements the `HasArea` trait.” + +`` 構文は「 `HasArea` トレイトを実装するあらゆる型」という意味です。トレイトは関数の型シグネチャを定義しているため、 `HasArea` を実装するあらゆる型が `.area()` メソッドを持っていることを確認できます。 -Here’s an extended example of how this works: + +トレイトの動作を確認するために拡張した例が以下になります。 ```rust trait HasArea { @@ -137,31 +149,36 @@ fn main() { } ``` -This program outputs: + +このプログラムの出力は、 ```text This shape has an area of 3.141593 This shape has an area of 1 ``` -As you can see, `print_area` is now generic, but also ensures that we have -passed in the correct types. If we pass in an incorrect type: + +見ての通り、上記の `print_area` はジェネリックですが、適切な型が渡されることを保証しています。もし不適切な型を渡すと、 ```rust,ignore print_area(5); ``` -We get a compile-time error: + +コンパイル時エラーが発生します。 ```text error: the trait `HasArea` is not implemented for the type `_` [E0277] ``` -## Trait bounds on generic structs + +## ジェネリック構造体におけるトレイト境界 -Your generic structs can also benefit from trait bounds. All you need to + +ジェネリック構造体もトレイト境界による恩恵を受けることができます。型パラメータを宣言する際に境界を追加するだけで良いのです。以下が新しい型 `Rectangle` とそのメソッド `is_square()` です。 ```rust struct Rectangle { @@ -192,31 +209,36 @@ fn main() { } ``` -`is_square()` needs to check that the sides are equal, so the sides must be of -a type that implements the [`core::cmp::PartialEq`][PartialEq] trait: + +`is_square()` は両辺が等しいかチェックする必要があるため、両辺の型は [`core::cmp::PartialEq`][PartialEq] トレイトを実装しなければなりません。 ```ignore impl Rectangle { ... } ``` -Now, a rectangle can be defined in terms of any type that can be compared for -equality. + +これで、長方形を等値性の比較できる任意の型として定義できました。 [PartialEq]: ../core/cmp/trait.PartialEq.html -Here we defined a new struct `Rectangle` that accepts numbers of any + +上記の例では任意の精度の数値を受け入れる `Rectangle` 構造体を新たに定義しました-実は、等値性を比較できるほぼ全ての型に対して利用可能なオブジェクトです。同じことを `Square` や `Circle` のような `HasArea` を実装する構造体に対してできるでしょうか?可能では有りますが乗算が必要になるため、それをするには [オペレータトレイト][operators-and-overloading] についてより詳しく知らなければなりません。 [operators-and-overloading]: operators-and-overloading.html -# Rules for implementing traits + +# トレイト実装のルール -So far, we’ve only added trait implementations to structs, but you can + +ここまでで、構造体へトレイトの実装を追加することだけを説明してきましたが、あらゆる型についてトレイトを実装することもできます。技術的には、 `i32` に `HasArea` を実装することも _できなくはない_ です。 ```rust trait HasArea { @@ -234,26 +256,31 @@ impl HasArea for i32 { 5.area(); ``` -It is considered poor style to implement methods on such primitive types, even -though it is possible. + +しかし例え可能であったとしても、そのようなプリミティブ型のメソッドを実装するのは適切でない手法だと考えられています。 -This may seem like the Wild West, but there are two restrictions around + +ここまでくると世紀末感漂いますが、手が負えなくなることを防ぐためにトレイトの実装周りには2つの制限が設けられています。第1に、あなたのスコープ内で定義されていないトレイトは適用されません。例えば、標準ライブラリは `File` にI/O機能を追加するための `Write` トレイトを提供しています。デフォルトでは、 `File` は `Writes` で定義されるメソッド群を持っていません。 [write]: ../std/io/trait.Write.html ```rust,ignore let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); -let buf = b"whatever"; // byte string literal. buf: &[u8; 8] +# // let buf = b"whatever"; // byte string literal. buf: &[u8; 8] +let buf = b"whatever"; // buf: &[u8; 8] はバイト文字列リテラルです。 let result = f.write(buf); -# result.unwrap(); // ignore the error +# // result.unwrap(); // ignore the error +# // result.unwrap(); // エラーを無視します。 ``` -Here’s the error: + +エラーは以下のようになります。 ```text error: type `std::fs::File` does not implement any method in scope named `write` @@ -261,7 +288,8 @@ let result = f.write(buf); ^~~~~~~~~~ ``` -We need to `use` the `Write` trait first: + +始めに `Write` トレイトを `use` する必要があります。 ```rust,ignore use std::io::Write; @@ -269,29 +297,36 @@ use std::io::Write; let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); let buf = b"whatever"; let result = f.write(buf); -# result.unwrap(); // ignore the error +# // result.unwrap(); // ignore the error +# // result.unwrap(); // エラーを無視します。 ``` -This will compile without error. + +これはエラー無しでコンパイルされます。 -This means that even if someone does something bad like add methods to `i32`, -it won’t affect you, unless you `use` that trait. + +これは、例え誰かが `i32` へメソッドを追加するような望ましくない何かを行ったとしても、あなたがトレイトを `use` しない限り、影響はないことを意味します。 -There’s one more restriction on implementing traits: either the trait, or the + +トレイトの実装における制限はもう1つあります。トレイト、またはあなたが書いている `impl` の対象となる型は、あなた自身によって実装されなければなりません。 `HasArea` は私たちが記述したコードであるため、 `i32` のための `HasArea` を実装することができます。しかし、 `i32` のためにRustによって提供されている `ToString` トレイトを実装したいとしても、トレイトと型が共に私たちの記述したコードでないため、それはできません。 -One last thing about traits: generic functions with a trait bound use + +トレイトに関して最後に1つ。トレイト境界が設定されたジェネリック関数は「モノモーフィゼーション」(monomorphization)(mono:単一の、morph:様相)されるため、静的ディスパッチが行われます。一体どういう意味でしょうか?詳細については、 [トレイトオブジェクト][to] の章をチェックしてください。 [to]: trait-objects.html -# Multiple trait bounds + +# 複数のトレイト境界 -You’ve seen that you can bound a generic type parameter with a trait: + +トレイトによってジェネリックな型パラメータに境界が与えられることを見てきました。 ```rust fn foo(x: T) { @@ -299,7 +334,8 @@ fn foo(x: T) { } ``` -If you need more than one bound, you can use `+`: + +1つ以上の境界を与えたい場合、 `+` を使えます。 ```rust use std::fmt::Debug; @@ -310,13 +346,16 @@ fn foo(x: T) { } ``` -`T` now needs to be both `Clone` as well as `Debug`. + +この `T` 型は `Clone` と `Debug` 両方が必要です。 -# Where clause + +# Where 節 -Writing functions with only a few generic types and a small number of trait + +ジェネリック型もトレイト境界の数も少ない関数を書いているうちは悪く無いのですが、数が増えるとこの構文ではいよいよ不便になってきます。 ```rust use std::fmt::Debug; @@ -328,10 +367,13 @@ fn foo(x: T, y: K) { } ``` -The name of the function is on the far left, and the parameter list is on the -far right. The bounds are getting in the way. + +関数名は左端にあり、引数リストは右端にあります。境界を記述する部分が邪魔になっているのです。 -Rust has a solution, and it’s called a ‘`where` clause’: + + +Rustは「 `where` 節」と呼ばれる解決策を持っています。 ```rust use std::fmt::Debug; @@ -354,10 +396,11 @@ fn main() { } ``` -`foo()` uses the syntax we showed earlier, and `bar()` uses a `where` clause. + +`foo()` は先程見せたままの構文で、 `bar()` は `where` 節を用いています。型パラメータを定義する際に境界の設定をせず、引数リストの後ろに `where` を追加するだけで良いのです。長いリストであれば、空白を加えることもできます。 ```rust use std::fmt::Debug; @@ -372,9 +415,11 @@ fn bar(x: T, y: K) } ``` -This flexibility can add clarity in complex situations. + +この柔軟性により複雑な状況であっても可読性を改善できます。 -`where` is also more powerful than the simpler syntax. For example: + +また、`where` は基本の構文よりも強力です。例えば、 ```rust trait ConvertTo { @@ -385,27 +430,33 @@ impl ConvertTo for i32 { fn convert(&self) -> i64 { *self as i64 } } -// can be called with T == i32 +# // can be called with T == i32 +// T == i32の時に呼び出せる fn normal>(x: &T) -> i64 { x.convert() } -// can be called with T == i64 +# // can be called with T == i64 +// T == i64の時に呼び出せる fn inverse() -> T - // this is using ConvertTo as if it were "ConvertTo" +# // this is using ConvertTo as if it were "ConvertTo" + // これは「ConvertTo」であるかのようにConvertToを用いている where i32: ConvertTo { 42.convert() } ``` -This shows off the additional feature of `where` clauses: they allow bounds + +ここでは `where` 節の追加機能を披露しています。この節は左辺に型パラメータ `T` だけでなく具体的な型(このケースでは `i32` )を指定できます。この例だと、 `i32` は `ConvertTo` を実装していなければなりません。(それは明らかですから)ここの `where` 節は `i32` が何であるか定義しているというよりも、 `T` に対して制約を設定しているといえるでしょう。 -# Default methods + +# デフォルトメソッド -A default method can be added to a trait definition if it is already known how a typical implementor will define a method. For example, `is_invalid()` is defined as the opposite of `is_valid()`: + +典型的な実装者がどうメソッドを定義するか既に分かっているならば、トレイトの定義にデフォルトメソッドを加えることができます。例えば、以下の `is_invalid()` は `is_valid()` の反対として定義されます。 ```rust trait Foo { @@ -415,7 +466,8 @@ trait Foo { } ``` -Implementors of the `Foo` trait need to implement `is_valid()` but not `is_invalid()` due to the added default behavior. This default behavior can still be overridden as in: + +`Foo` トレイトの実装者は `is_valid()` を実装する必要がありますが、デフォルトの動作が加えられている `is_invalid()` には必要ありません。 ```rust # trait Foo { @@ -442,20 +494,25 @@ impl Foo for OverrideDefault { fn is_invalid(&self) -> bool { println!("Called OverrideDefault.is_invalid!"); - true // overrides the expected value of is_invalid() +# // true // overrides the expected value of is_invalid() + true // 予期されるis_invalid()の値をオーバーライドする } } let default = UseDefault; -assert!(!default.is_invalid()); // prints "Called UseDefault.is_valid." +# // assert!(!default.is_invalid()); // prints "Called UseDefault.is_valid." +assert!(!default.is_invalid()); // 「Called UseDefault.is_valid.」を表示 let over = OverrideDefault; -assert!(over.is_invalid()); // prints "Called OverrideDefault.is_invalid!" +# // assert!(over.is_invalid()); // prints "Called OverrideDefault.is_invalid!" +assert!(over.is_invalid()); // 「Called OverrideDefault.is_invalid!」を表示 ``` -# Inheritance + +# 継承 -Sometimes, implementing a trait requires implementing another trait: + +時々、1つのトレイトの実装に他のトレイトの実装が必要になります。 ```rust trait Foo { @@ -467,7 +524,8 @@ trait FooBar : Foo { } ``` -Implementors of `FooBar` must also implement `Foo`, like this: + +`FooBar` の実装者は `Foo` も実装しなければなりません。以下のようになります。 ```rust # trait Foo { @@ -487,17 +545,20 @@ impl FooBar for Baz { } ``` -If we forget to implement `Foo`, Rust will tell us: + +`Foo` の実装を忘れると、Rustは以下のように伝えるでしょう。 ```text error: the trait `main::Foo` is not implemented for the type `main::Baz` [E0277] ``` -# Deriving + +# Derive -Implementing traits like `Debug` and `Default` repeatedly can become + +繰り返し`Debug` や `Default` のようなトレイトを実装するのは非常にうんざりさせられます。そのような理由から、Rustは自動的にトレイトを実装するための [アトリビュート][attributes] を提供しています。 ```rust #[derive(Debug)] @@ -510,7 +571,8 @@ fn main() { [attributes]: attributes.html -However, deriving is limited to a certain set of traits: + +ただし、deriveは以下の特定のトレイトに制限されています。 - [`Clone`](../core/clone/trait.Clone.html) - [`Copy`](../core/marker/trait.Copy.html)