はじめに
#NO IMAGEThe Rust Programming Language 日本語版 - The Rust Programming Language 日本語版
を読んでいる
- 光らせるのを習慣化したい
- 前回の振り返りテスト作るか
- ごちゃごちゃやったが、ひとつの値に対して複数のポインタを当てることができないので、
Rcとできるという話だった
お勉強
#NO IMAGERefCell<T>と内部可変性パターン - The Rust Programming Language 日本語版
- 今日はここ
メモ
#- とりあえずざっくり読む
- そこそこ文章量がある
- んーとりあえず借用を規制するらしい
このパターンは、データ構造内で
unsafeコードを使用して、 可変性と借用を支配するRustの通常の規則を捻じ曲げています。
- なんか基本使っちゃダメそう
たとえ、コンパイラが保証できなくても、借用規則に実行時に従うことが保証できる時に限り、 内部可変性パターンを使用した型を使用できます。
- んーどうなんだろう、グレー
Rc<T>と異なり、RefCell<T>型は、保持するデータに対して単独の所有権を表します。
- とりあえず所有権は複数持たないので、
moveはしそう
参照でこれらの規則を破ったら、コンパイルエラーになりました。
RefCell<T>でこれらの規則を破ったら、プログラムはパニックし、終了します。
- 駄目じゃん
- と思ったけど処置はできるのか
- うーん、使える。。。?
Rc<T>と類似して、RefCell<T>もシングルスレッドの筋書きで使用するためのもの
- いろいろあるな
fn main() {
let x = 5;
let y = &mut x;
}
$ cargo run
Compiling borrowing v0.1.0 (file:///projects/borrowing)
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
(エラー: `x`は可変として宣言されていないので、可変として借用することはできません)
--> src/main.rs:3:13
|
3 | let y = &mut x;
| ^^^^^^ cannot borrow as mutable
| (可変として借用できません)
|
help: consider changing this to be mutable
(ヘルプ: これを可変に変更することを考慮してください)
|
2 | let mut x = 5;
| +++
For more information about this error, try `rustc --explain E0596`.
error: could not compile `borrowing` (bin "borrowing") due to 1 previous error
-
そのまんまの意味だな
mutだし
-
んーなるほど
-
ここでは借用チェッカーに引っかからないから
panic!が発生する状況を教えてくれそうだな
pub trait Messenger {
fn send(&self, msg: &str);
}
pub struct LimitTracker<'a, T: Messenger> {
messenger: &'a T,
value: usize,
max: usize,
}
impl<'a, T> LimitTracker<'a, T>
where
T: Messenger,
{
pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> {
LimitTracker {
messenger,
value: 0,
max,
}
}
pub fn set_value(&mut self, value: usize) {
self.value = value;
let percentage_of_max = self.value as f64 / self.max as f64;
if percentage_of_max >= 1.0 {
// "エラー: 割り当てを超えています!"
self.messenger.send("Error: You are over your quota!");
} else if percentage_of_max >= 0.9 {
// "緊急警告: 割り当ての90%以上を使用してしまいました!"
self.messenger
.send("Urgent warning: You've used up over 90% of your quota!");
} else if percentage_of_max >= 0.75 {
// "警告: 割り当ての75%以上を使用してしまいました!"
self.messenger
.send("Warning: You've used up over 75% of your quota!");
}
}
}
-
お、ユースケースがテストなのか
-
flaykyにならなければいいかもね
#[cfg(test)]
mod tests {
use super::*;
struct MockMessenger {
sent_messages: Vec<String>,
}
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
sent_messages: vec![],
}
}
}
impl Messenger for MockMessenger {
fn send(&self, message: &str) {
self.sent_messages.push(String::from(message));
}
}
#[test]
fn it_sends_an_over_75_percent_warning_message() {
let mock_messenger = MockMessenger::new();
let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
limit_tracker.set_value(80);
assert_eq!(mock_messenger.sent_messages.len(), 1);
}
}
- これがテストか
- エラーが起きるらしい、どこだ
$ cargo test
Compiling limit-tracker v0.1.0 (file:///projects/limit-tracker)
error[E0596]: cannot borrow `self.sent_messages` as mutable, as it is behind a `&` reference
(エラー: `self.sent_messages`は`&`参照の後ろにあるので、可変として借用できません)
--> src/lib.rs:58:13
|
58 | self.sent_messages.push(String::from(message));
| ^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
| (`self`は`&`参照なので、それが参照するデータは可変として借用できません)
|
help: consider changing this to be a mutable reference
(ヘルプ: 可変参照に変更することを検討してください)
|
2 | fn send(&mut self, msg: &str);
| ~~~~~~~~~
For more information about this error, try `rustc --explain E0596`.
error: could not compile `limit-tracker` (lib test) due to 1 previous error
まとめ
#- 時間切れ
- 不変の借用を可変に参照したい
- 借用チェッカーに引っかからないけどミスると
panic!する - シングルスレッドのみ
- というところまでわかった
- あと
Rcと違って所有権をもつらしい
次はエラーの理解から
NO IMAGERefCell<T>と内部可変性パターン - The Rust Programming Language 日本語版
もんだい、RefCellの特徴2つ