回答編集履歴

4

CellのsetメソッドはCopyトレイトが不要だったため、それに関する記載を修正しました

2022/03/31 00:54

投稿

tatsuya6502
tatsuya6502

スコア2035

test CHANGED
@@ -63,7 +63,7 @@
63
63
  }
64
64
  ```
65
65
 
66
- `Cell`は`set`や`get`のたびに値をコピーします。そのため`i32`のような`Copy`トレイトを実装した型でのみ利用可能です。なお、`Copy`トレイトを実装しない型については`RefCell`が使用できます。どちらのコンテナーも、実行時に性能上のオーバーヘッドが多少あります。
66
+ `Cell`は`get`のたびに値をコピーします。そのため`get`メソッドは`i32`のような`Copy`トレイトを実装した型でのみ利用可能です。なお、`Copy`トレイトを実装しない型については`RefCell`が使用できます。どちらのコンテナーも、実行時に性能上のオーバーヘッドが多少あります。
67
67
 
68
68
  内部可変性について、詳しくは [こちら](https://doc.rust-jp.rs/book-ja/ch15-05-interior-mutability.html) を参照してください。
69
69
 

3

不要な let (card, v) をコードから削除しました

2022/03/30 23:25

投稿

tatsuya6502
tatsuya6502

スコア2035

test CHANGED
@@ -53,9 +53,7 @@
53
53
  }
54
54
 
55
55
  pub fn update(&mut self) {
56
- let (card, v) = (&self.card, &mut self.value);
57
-
58
- card.run(|value| {
56
+ self.card.run(|value| {
59
57
  self.assign(value);
60
58
  });
61
59
 

2

コンパイルエラーが解消する理由について少しだけ追記しました

2022/03/30 23:22

投稿

tatsuya6502
tatsuya6502

スコア2035

test CHANGED
@@ -28,7 +28,7 @@
28
28
 
29
29
  `Cell`や`RefCell`などの、内部可変性(interior mutability)を実現するコンテナーを使う方法があります。
30
30
 
31
- `value`の型を`i32`から`std::cell::Cell<i32>`型へ変えることで、`value`の不変借用を通じて`Cell`内の値を変更できるようになります。`self`の可変借用が不要になりますので、`assign`メソッドの引数を`(&mut self, value: i32)`から`(&self, value: i32)`へ変更できます。これより、コンパイルエラーを解消できます。
31
+ `value`の型を`i32`から`std::cell::Cell<i32>`型へ変えることで、`value`の不変借用を通じて`Cell`内の値を変更できるようになります。`self`の可変借用が不要になりますので、`assign`メソッドの引数を`(&mut self, value: i32)`から`(&self, value: i32)`へ変更できます。不変借用は同時複数存在できますので、コンパイルエラーを解消できます。
32
32
 
33
33
  ```rust
34
34
  use std::cell::Cell;

1

Cellを使った方法について追記しました

2022/03/30 23:09

投稿

tatsuya6502
tatsuya6502

スコア2035

test CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  Rustではメモリー安全性を保証するために、可変の借用は他の借用(可変・不変を問わず)と同時に存在できません。一方、不変の参照は、他の不変の借用と同時に存在できます。
4
4
 
5
- エラーメッセージが示しているとおり、 `self.card` の不変借用を使用中に、 `assign` メソッドのために `self` **全体** の可変借用を作ることはできません。なぜなら `self` 全体の可変借用には `self.card` の可変借用が含まれるからです。
5
+ エラーメッセージが示しているとおり、`self.card`の不変借用を使用中に、`assign`メソッドのために`self` **全体** の可変借用を作ることはできません。なぜなら`self`全体の可変借用には`self.card`の可変借用が含まれるからです。
6
6
 
7
- `self.card` の借用と `self.value` の借用なら、お互いを含んでいませんので同時に存在できます。 `assign` メソッドを使わず、以下のようにすればコンパイルエラーが解消します。
7
+ `self.card`の借用と`self.value`の借用なら、お互いを含んでいませんので同時に存在できます。`assign`メソッドを使わず、以下のようにすればコンパイルエラーが解消します。
8
8
 
9
9
  ```rust
10
10
  pub fn update(&mut self) {
@@ -20,3 +20,52 @@
20
20
  }
21
21
  ```
22
22
 
23
+ **追記**
24
+
25
+ > `assign`メソッドをなぜ使いたいかというと、本当は`assign`メソッド内でしている処理がもう少し複雑で、さらに今回のようなクロージャ内での処理が何度か似たような形で存在し、`assign`メソッドにまとめることでDRYにしたかったからです。
26
+ > ...
27
+ > 他に代替案などあれば幸いです。
28
+
29
+ `Cell`や`RefCell`などの、内部可変性(interior mutability)を実現するコンテナーを使う方法があります。
30
+
31
+ `value`の型を`i32`から`std::cell::Cell<i32>`型へ変えることで、`value`の不変借用を通じて`Cell`内の値を変更できるようになります。`self`の可変借用が不要になりますので、`assign`メソッドの引数を`(&mut self, value: i32)`から`(&self, value: i32)`へ変更できます。これにより、コンパイルエラーを解消できます。
32
+
33
+ ```rust
34
+ use std::cell::Cell;
35
+
36
+ #[derive(Default)]
37
+ struct App {
38
+ // Cell<i32>に変更
39
+ value: Cell<i32>,
40
+ card: Card,
41
+ }
42
+
43
+ impl App {
44
+ // &mut self → &selfに変更
45
+ fn assign(&self, value: i32) {
46
+ // Cellのsetメソッドを使用する
47
+ self.value.set(value);
48
+ }
49
+
50
+ pub fn setup(&mut self) {
51
+ self.value.set(42);
52
+ self.card = Card::new();
53
+ }
54
+
55
+ pub fn update(&mut self) {
56
+ let (card, v) = (&self.card, &mut self.value);
57
+
58
+ card.run(|value| {
59
+ self.assign(value);
60
+ });
61
+
62
+ // Cellのgetメソッドを使用する
63
+ println!("{}", self.value.get());
64
+ }
65
+ }
66
+ ```
67
+
68
+ `Cell`は`set`や`get`のたびに値をコピーします。そのため`i32`のような`Copy`トレイトを実装した型でのみ利用可能です。なお、`Copy`トレイトを実装しない型については`RefCell`が使用できます。どちらのコンテナーも、実行時に性能上のオーバーヘッドが多少あります。
69
+
70
+ 内部可変性について、詳しくは [こちら](https://doc.rust-jp.rs/book-ja/ch15-05-interior-mutability.html) を参照してください。
71
+