teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

値をbox化するメソッドについて追記しました

2020/03/03 23:42

投稿

tatsuya6502
tatsuya6502

スコア2055

answer CHANGED
@@ -54,4 +54,29 @@
54
54
  }
55
55
  ```
56
56
 
57
- このように引数をとらないコンストラクタなら`Default`トレイトで実現できます。もしいくつかの共通の引数をとるようなコンストラクタが必要なら、`TraitB`とは別のトレイトを定義してみてください。
57
+ このように引数をとらないコンストラクタなら`Default`トレイトで実現できます。もしいくつかの共通の引数をとるようなコンストラクタが必要なら、`TraitB`とは別のトレイトを定義してみてください。
58
+
59
+ **追記**
60
+
61
+ 質問からは逸れますが `Box::new(StructB::default())`のような値をbox化するコードを頻繁に書く場合は、`StructB`にbox化するメソッド(またはトレイトメソッド)を実装すると少し書きやすくなりそうです。([こちら](https://keens.github.io/blog/2019/12/23/jisakulintru_rutocargo_fixderustnoko_doworifakutasuru/index.html#%E5%AE%9F%E8%B7%B5lint-fix)で紹介されているアイデアです)
62
+
63
+ ```rust
64
+ impl StructB {
65
+ fn boxed(self) -> Box<Self> {
66
+ Box::new(self)
67
+ }
68
+
69
+ fn boxed_new() -> Box<Self> {
70
+ Self::default().boxed()
71
+ }
72
+ }
73
+
74
+ fn main() {
75
+ let mut y: Box<dyn TraitB>;
76
+ // y = Box::new(StructB::default()) の代わりに以下のように書ける
77
+ y = StructB::default().boxed();
78
+ y = StructB::boxed_new();
79
+ }
80
+ ```
81
+
82
+ この例では`boxed(self)`と`boxed_new()`を何かのトレイトのメソッドにする理由は特になかったので、`Struct`のメソッドや関連関数として実装しました。もしトレイトのメソッドにする必要があれば、(`TraitB`とは別にトレイトを定義すれば)そうすることも可能です。

1

わかりやすさのために文章を修正しました(特に冒頭の部分)

2020/03/03 23:42

投稿

tatsuya6502
tatsuya6502

スコア2055

answer CHANGED
@@ -1,14 +1,18 @@
1
- > `error[E0038]: the trait \`TraitB\` cannot be made into an object`
1
+ > 下記コードのStructAがOKで、StructBがNGである理由がなかなか理解できず…。
2
2
 
3
- Rustのエラーメッセージがよくわからないときは、まずエラーの説を読のがおすすめです。Webブラウザで [https://doc.rust-lang.org/error-index.html#E0038](https://doc.rust-lang.org/error-index.html#E0038) にアクセスするか、ターミナルから `rustc --explain 38` を実行します。(38のところを実際のエラー番号で置き換えます) 説明は英語ですが、最近は機械翻訳が高性能化してきているので、それらを活用すればなんとかなると思います。(例:[https://cn.bing.com/translator?from=&to=ja](https://cn.bing.com/translator?from=&to=ja))
3
+ こうときは、まずエラーの説を読んでみるのがおすすめです。
4
4
 
5
- E0038のところでは、トレイトオブジェクトにできないトレイトの条件が書かれています。その中で今回の`TraitB`が当てはまるのは以下の項目です。
5
+ > error[E0038]: the trait `TraitB` cannot be made into an object
6
6
 
7
- - トレトメソッド`Self`型引数たり、`Self`型の戻り値たり(メソッドレシーバ`&self`どは問題
8
- - トレイトメソッドがメソッドレシーバ(`&self`, `&muf self`, `self`)を持たない
7
+ コンパ出力する多くエラーにはE0038のような番号がついています。この番号使エラーの詳細な解説を表示できます。Webブラウザで [https://doc.rust-lang.org/error-index.html#E0038](https://doc.rust-lang.org/error-index.html#E0038) を開くか、ターミナルから `rustc --explain 38` 実行す。英語による説明ですが、最近は機械翻訳の性能向上が著しいので、それら活用ればんとかりそうです。(例:[https://www.bing.com/translator?from=&to=ja](https://www.bing.com/translator?from=&to=ja)
9
8
 
10
- 理由を明すると長くなるので、ここは省略します。エラー説明を機械翻訳にけてみてください。また、いくつかの項目については、[ここ](https://doc.rust-jp.rs/book/second-edition/ch17-02-trait-objects.html?highlight=trait,obje#a%E3%83%88%E3%83%AC%E3%82%A4%E3%83%88%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AB%E3%81%AF%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E5%AE%89%E5%85%A8%E6%80%A7%E3%81%8C%E5%BF%85%E8%A6%81) で和訳されています。
9
+ E0038説でどういうトレイトがトレイトオブジェクトにきないのか、いくつかの条件が書かれています。今回の`TraitB`が当てはまるのは以下の条件です。
11
10
 
11
+ - `Self`型の引数をとったり、`Self`型の戻り値を返したりするトレイトメソッドがある。(メソッドレシーバを示す`&self`などは問題ない)
12
+ - メソッドレシーバ(`&self`, `&muf self`, `self`)を持たないトレイトメソッドがある
13
+
14
+ これらがなぜダメなのかの理由を説明しだすと長くなるので、ここでは省略します。エラーの解説を機械翻訳にかけてみてください。また、いくつかの項目については、[ここ](https://doc.rust-jp.rs/book/second-edition/ch17-02-trait-objects.html?highlight=trait,obje#a%E3%83%88%E3%83%AC%E3%82%A4%E3%83%88%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AB%E3%81%AF%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E5%AE%89%E5%85%A8%E6%80%A7%E3%81%8C%E5%BF%85%E8%A6%81) で和訳されています。
15
+
12
16
  > 定番の書き方があれば教えて頂けないでしょうか。
13
17
 
14
18
  定番かどうかはわかりませんが、`TraitB`にコンストラクタにあたるトレイトメソッドを定義するのではなく、別のトレイトを使用する方法があります。ご質問のコードの`new()`に該当するトレイトメソッドは、標準ライブラリの`Default`トレイトですでに定義されていますので、それを使うといいでしょう。`Default`トレイトの定義は以下の通りです。
@@ -48,4 +52,6 @@
48
52
  // default()メソッドを使う
49
53
  let y: Box<dyn TraitB> = Box::new( StructB::default() );
50
54
  }
51
- ```
55
+ ```
56
+
57
+ このように引数をとらないコンストラクタなら`Default`トレイトで実現できます。もしいくつかの共通の引数をとるようなコンストラクタが必要なら、`TraitB`とは別のトレイトを定義してみてください。