回答編集履歴
4
CellのsetメソッドはCopyトレイトが不要だったため、それに関する記載を修正しました
test
CHANGED
@@ -63,7 +63,7 @@
|
|
63
63
|
}
|
64
64
|
```
|
65
65
|
|
66
|
-
`Cell`は`
|
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) をコードから削除しました
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
コンパイルエラーが解消する理由について少しだけ追記しました
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を使った方法について追記しました
test
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
Rustではメモリー安全性を保証するために、可変の借用は他の借用(可変・不変を問わず)と同時に存在できません。一方、不変の参照は、他の不変の借用と同時に存在できます。
|
4
4
|
|
5
|
-
エラーメッセージが示しているとおり、
|
5
|
+
エラーメッセージが示しているとおり、`self.card`の不変借用を使用中に、`assign`メソッドのために`self` **全体** の可変借用を作ることはできません。なぜなら`self`全体の可変借用には`self.card`の可変借用が含まれるからです。
|
6
6
|
|
7
|
-
`self.card`
|
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
|
+
|