<style>
/* basic design */
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6,
.reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {
font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic';
text-align: left;
line-height: 1.6;
letter-spacing: normal;
text-shadow: none;
word-wrap: break-word;
color: #444;
}
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {font-weight: bold;}
.reveal h1, .reveal h2, .reveal h3 {color: #2980b9;}
.reveal th {background: #DDD;}
.reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;}
.reveal blockquote {width: 90%; padding: 0.5vw 3.0vw;}
.reveal table {margin: 1.0vw auto;}
.reveal code {line-height: 1.2;}
.reveal p, .reveal li {padding: 0vw; margin: 0vw;}
.reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #EEE; border-radius: 1.5vw;}
/* table design */
.reveal table {background: #f5f5f5;}
.reveal th {background: #444; color: #fff;}
.reveal td {position: relative; transition: all 300ms;}
.reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #aaa;}
.reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #fff;}
/* blockquote design */
.reveal blockquote {
width: 90%;
padding: 0.5vw 0 0.5vw 6.0vw;
font-style: italic;
background: #f5f5f5;
}
.reveal blockquote:before{
position: absolute;
top: 0.1vw;
left: 1vw;
content: "\f10d";
font-family: FontAwesome;
color: #2980b9;
font-size: 3.0vw;
}
/* font size */
.reveal h1 {font-size: 5.0vw;}
.reveal h2 {font-size: 4.0vw;}
.reveal h3 {font-size: 2.8vw;}
.reveal h4 {font-size: 2.6vw;}
.reveal h5 {font-size: 2.4vw;}
.reveal h6 {font-size: 2.2vw;}
.reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.2vw;}
.reveal code {font-size: 1.6vw;}
/* new color */
.red {color: #EE6557;}
.blue {color: #16A6B6;}
/* split slide */
#right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;}
#left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;}
</style>
<style>
/* specific design */
.reveal h2 {
padding: 0 1.5vw;
margin: 0.0vw 0 2.0vw -2.0vw;
border-left: solid 1.2vw #2980b9;
border-bottom: solid 0.8vw #d7d7d7;
}
</style>
# Rust勉強会 第16回
## 15章 後半
### 2020/11/20 岡本拓海
---
## 本日のメニュー
* ```REfCell<T>```と内部可変性パターン
* 循環参照について
プレゼン20分くらい+議論10分位で18:30前後終了を目指します。
---
## RefCell\<T\>で実行時に借用規則を強制する
第4章で学んだ借用規則:
* いかなる時も(以下の両方ではなく、)1つの可変参照かいくつもの不変参照のどちらかが可能になる
* 参照は常に有効でなければならない。
---
## RefCell\<T\>で実行時に借用規則を強制する
* Rc\<T\>は、同じデータに複数の所有者を持たせてくれる; Box\<T\>とRefCell\<T\>は単独の所有者。
* Box\<T\>では、不変借用も可変借用もコンパイル時に精査できる; Rc\<T\>では不変借用のみがコンパイル時に精査できる; RefCell\<T\>では、不変借用も可変借用も実行時に精査される。
* RefCell\<T\>は実行時に精査される可変借用を許可するので、RefCell\<T\>が不変でも、 RefCell\<T\>内の値を可変化できる。
----
## 内部可変性:不変値への可変借用
これは動かない
```rust=
fn main() {
let x = 5;
let y = &mut x;
}
```
----
## 内部可変性のユースケース: モックオブジェクト
```rust=
pub trait Messenger {
fn send(&self, msg: &str);
}
pub struct LimitTracker<'a, T: 'a + Messenger> {
messenger: &'a T,
value: usize,
max: usize,
}
impl<'a, T> LimitTracker<'a, T>
where T: Messenger {
pub fn new(messenger: &T, max: usize) -> LimitTracker<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 >= 0.75 && percentage_of_max < 0.9 {
// 警告: 割り当ての75%以上を使用してしまいました
self.messenger.send("Warning: You've used up over 75% of your quota!");
} else if percentage_of_max >= 0.9 && percentage_of_max < 1.0 {
// 切迫した警告: 割り当ての90%以上を使用してしまいました
self.messenger.send("Urgent warning: You've used up over 90% of your quota!");
} else if percentage_of_max >= 1.0 {
// エラー: 割り当てを超えています
self.messenger.send("Error: You are over your quota!");
}
}
}
```
---
## 循環参照
----
## 循環参照させる
```rust=
use std::rc::Rc;
use std::cell::RefCell;
use List::{Cons, Nil};
#[derive(Debug)]
enum List {
Cons(i32, RefCell<Rc<List>>),
Nil,
}
impl List {
fn tail(&self) -> Option<&RefCell<Rc<List>>> {
match *self {
Cons(_, ref item) => Some(item),
Nil => None,
}
}
}
```
----
## 循環参照させる
```rust=
fn main() {
let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
// aの最初の参照カウント = {}
println!("a initial rc count = {}", Rc::strong_count(&a));
// aの次の要素は = {:?}
println!("a next item = {:?}", a.tail());
let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));
// b作成後のaの参照カウント = {}
println!("a rc count after b creation = {}", Rc::strong_count(&a));
// bの最初の参照カウント = {}
println!("b initial rc count = {}", Rc::strong_count(&b));
// bの次の要素 = {:?}
println!("b next item = {:?}", b.tail());
if let Some(link) = a.tail() {
*link.borrow_mut() = Rc::clone(&b);
}
// aを変更後のbの参照カウント = {}
println!("b rc count after changing a = {}", Rc::strong_count(&b));
// aを変更後のaの参照カウント = {}
println!("a rc count after changing a = {}", Rc::strong_count(&a));
// Uncomment the next line to see that we have a cycle;
// it will overflow the stack
// 次の行のコメントを外して循環していると確認してください; スタックオーバーフローします
// println!("a next item = {:?}", a.tail()); // aの次の要素 = {:?}
}
```
----
## 循環参照させる
![](https://i.imgur.com/ZuQQ0rH.png)
----
## 循環参照を回避する: Rc\<T\>をWeak\<T\>に変換する
----
----
----
## 子供から親に参照を追加する
----
## 木データ構造を作る: 子ノードのあるNode
```rust=
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
children: RefCell<Vec<Rc<Node>>>,
}
```
----
## strong_countとweak_countへの変更を可視化する
```rust=
fn main() {
let leaf = Rc::new(Node {
value: 3,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![]),
});
println!(
// leafのstrong_count = {}, weak_count = {}
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
{
let branch = Rc::new(Node {
value: 5,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
println!(
// branchのstrong_count = {}, weak_count = {}
"branch strong = {}, weak = {}",
Rc::strong_count(&branch),
Rc::weak_count(&branch),
);
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
}
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
}
```
----
----
----
----
----
----
----
----
---
## 参考資料
https://doc.rust-jp.rs/book-ja/ch12-00-an-io-project.html
---
# ご清聴ありがとうございました
{"metaMigratedAt":"2023-06-15T16:00:33.726Z","metaMigratedFrom":"YAML","title":"第16回 15章 後半","breaks":true,"description":"Rust勉強会第7回のスライド","slideOptions":"{\"theme\":\"white\",\"slideNumber\":\"c/t\",\"center\":false,\"transition\":\"none\",\"keyboard\":true}","contributors":"[{\"id\":\"610cfd52-ad2b-46e8-81e2-a79a85a7f06f\",\"add\":7877,\"del\":304}]"}