Slide 1

Slide 1 text

1 2019/1/16 その式、値ですか?場所ですか? その式、値ですか? 場所ですか? 原 将己 @qnighy (ウォンテッドリー株式会社) Shinjuku.rs #2 @FORCIA 2019/01/16

Slide 2

Slide 2 text

2 2019/1/16 その式、値ですか?場所ですか? 本LTの目的 値と場所の区別を 意識することで、 より快適なRust生活を 送れるようにする

Slide 3

Slide 3 text

3 2019/1/16 その式、値ですか?場所ですか? 事前クイズ1 • 次の文は正しいでしょうか? 1 = 1;

Slide 4

Slide 4 text

4 2019/1/16 その式、値ですか?場所ですか? 事前クイズ2 • では、次の文は? *&mut 1 = 1;

Slide 5

Slide 5 text

5 2019/1/16 その式、値ですか?場所ですか? 式には値と場所がある • 「右辺値」「左辺値」ともいうお馴染みの概念 x = y; 場所 (左辺値) 値 (左辺値)

Slide 6

Slide 6 text

6 2019/1/16 その式、値ですか?場所ですか? その式、値ですか、場所ですか? • では、次の場合はどうでしょう? let x = y.clone(); 値? 場所? というようなことを考えていくのが本LTの流れです

Slide 7

Slide 7 text

7 2019/1/16 その式、値ですか?場所ですか? Fact1: 式には値と場所がある

Slide 8

Slide 8 text

8 2019/1/16 その式、値ですか?場所ですか? 式には値と場所がある • 「右辺値」「左辺値」ともいうお馴染みの概念 x = y; 場所 (左辺値) 値 (左辺値)

Slide 9

Slide 9 text

9 2019/1/16 その式、値ですか?場所ですか? デフォルトのモード • 以下の式はデフォルトで場所である x X ローカル変数、static変数 *e 参照外し e.x フィールド e[x] インデックス

Slide 10

Slide 10 text

10 2019/1/16 その式、値ですか?場所ですか? デフォルトのモード • 以下の式は透過的に振る舞う (e) 括弧 e: T 型帰属 (RFC2522, nightly)

Slide 11

Slide 11 text

11 2019/1/16 その式、値ですか?場所ですか? デフォルトのモード • 残りの式はデフォルトで値である f 定数、関数、コンストラクタ A 関数・メソッド呼出 e.f() 各種リテラル・クロージャ f() A{} 42 "s" () (e,e) e..e [e;n] [e,e] 代入・複合代入 ||e x = e x += e アドレス演算子 &e 各種演算子 (&, *以外) -e e + e box e インラインアセンブリ e as T asm!() ブロック系構文 制御構文 {} if while for loop match unsafe try async return break continue yield e? このリストのうちいくつかはそもそも戻り値に深い意味 がない (! や () 型になる) let も同様だが、こいつは式ですらない

Slide 12

Slide 12 text

12 2019/1/16 その式、値ですか?場所ですか? デフォルトのモード • たとえば、 {} は () とは異なり、ムーブを強制する fn main() { let x = Box::new(42); println!("{}", {x}); println!("{}", {x}); // ERROR }

Slide 13

Slide 13 text

13 2019/1/16 その式、値ですか?場所ですか? • では、次のような場合は? let x = 42; &42 + x Expect: 場所 Got: 値 Expect:値 Got: 場所 欲しいものが違うときは変換がはさまるはず

Slide 14

Slide 14 text

14 2019/1/16 その式、値ですか?場所ですか? Fact2: 暗黙変換を意識する

Slide 15

Slide 15 text

15 2019/1/16 その式、値ですか?場所ですか? 場所が欲しいときの変換 • 値なのに場所が欲しいときは、一時変数が生成される &42 let tmp = 42; &tmp

Slide 16

Slide 16 text

16 2019/1/16 その式、値ですか?場所ですか? 場所が欲しいときの変換 • ただし、一定条件下では、変数ではなくstatic変数が生成され る (RFC1414, stable) &42 static TMP = 42; &TMP

Slide 17

Slide 17 text

17 2019/1/16 その式、値ですか?場所ですか? 値が欲しいときの変換 • 場所なのに値が欲しいときは、読み取り動作 (コピーまたは ムーブ) が発生する x read(&x) 実際にはムーブ元のインバリデーションが必要なのでこのよう な単純化はできないが、コピーのときはこのように考えてし まって問題ない

Slide 18

Slide 18 text

18 2019/1/16 その式、値ですか?場所ですか? 事前クイズ2の答え • これはコンパイルが通る *&mut 1 = 1; 1が入った一時変数が作られる そこに1を代入する

Slide 19

Slide 19 text

19 2019/1/16 その式、値ですか?場所ですか? 例外 • 代入演算子と複合代入演算子では、左辺を構文的に以下のいず れかに制限している: x X ローカル変数、static変数 *e 参照外し e.x フィールド e[x] インデックス

Slide 20

Slide 20 text

20 2019/1/16 その式、値ですか?場所ですか? 事前クイズ1の答え • 前述の例外条件に引っかかるので、次の文はコンパイルが通ら ない 1 = 1;

Slide 21

Slide 21 text

21 2019/1/16 その式、値ですか?場所ですか? Fact3: パターンマッチにも 値と場所がある

Slide 22

Slide 22 text

22 2019/1/16 その式、値ですか?場所ですか? パターンマッチにも値と場所がある • マッチ対象の式のモード = パターンのモード if let Some(ref mut s) = s { s.push_str("world!"); } if let Some(s) = s { eprintln!("{}", s); } 場所に対するマッチング 値に対するマッチング let, match, if let, while let で共通して現れる現象。 引数と for 文の場合は必ず値が渡ってくる

Slide 23

Slide 23 text

23 2019/1/16 その式、値ですか?場所ですか? 例: Optionの場所マッチ • Optionのヘルパー関数はほとんどが値マッチで、場所マッチを するのは以下の関数のみ get_or_insert_with get_or_insert iter_mut iter as_mut as_ref is_some is_none take, replace はやや特殊で、 こいつらはそもそもマッチングをしていない 普遍的な場所マッチヘルパー

Slide 24

Slide 24 text

24 2019/1/16 その式、値ですか?場所ですか? 例: Optionの場所マッチ • 以下の例では Option の参照に対して処理をしているので、場 所マッチの王様である as_ref が必要、と理解できる let s: Option = /* … */; s.as_ref().map(|s| s.as_str()).unwrap_or("bar");

Slide 25

Slide 25 text

25 2019/1/16 その式、値ですか?場所ですか? Fact4: 字句的にわからないケース

Slide 26

Slide 26 text

26 2019/1/16 その式、値ですか?場所ですか? 字句的にわからないケースもある • 代表的なのがこれ let x = y.clone(); 値? 場所?

Slide 27

Slide 27 text

27 2019/1/16 その式、値ですか?場所ですか? レシーバ • パターン1: autorefする場合 let shared = Arc::new(42); let shared2 = shared.clone(); Clone::clone(&shared)

Slide 28

Slide 28 text

28 2019/1/16 その式、値ですか?場所ですか? レシーバ • パターン2: autorefしない場合 fn foo(app: &Arc) { if app.enabled { let app = app.clone(); // ... } } Clone::clone(app)

Slide 29

Slide 29 text

29 2019/1/16 その式、値ですか?場所ですか? マッチの既定モード (RFC2005) • 参照型の式を参照型でないパターンに入れた場合 fn foo(config: &Option) { if let Some(config) = config { // ... } } &Option Option<_>

Slide 30

Slide 30 text

30 2019/1/16 その式、値ですか?場所ですか? マッチの既定モード (RFC2005) • 以下のように補正されたものとして扱われる fn foo(config: &Option) { if let Some(ref config) = *config { // ... } } 式に参照外しがつく 全ての束縛にrefがつく

Slide 31

Slide 31 text

31 2019/1/16 その式、値ですか?場所ですか? • ボローやムーブの検査は型推論より後に行われるので、構文的 な構造が同じでも推論された型次第で挙動が変わることがある

Slide 32

Slide 32 text

32 2019/1/16 その式、値ですか?場所ですか? Fact5: 場所として脱糖される式

Slide 33

Slide 33 text

33 2019/1/16 その式、値ですか?場所ですか? 場所として脱糖される式 • 場所として脱糖されるやつがいる x X ローカル変数、static変数 *e 参照外し e.x フィールド e[x] インデックス

Slide 34

Slide 34 text

34 2019/1/16 その式、値ですか?場所ですか? 場所として脱糖される式 • 場所として使われる式はunsizedでもいいので、次の文は合法: let s = "あいう"; let ref t = s[3..6]; str 型 (参照束縛なので t は &str 型) str 型 (長さ不定)

Slide 35

Slide 35 text

35 2019/1/16 その式、値ですか?場所ですか? 場所として脱糖される式 • 次のように脱糖される let s = "あいう"; let ref t = *Index::index(s, 3..6); * がつく

Slide 36

Slide 36 text

36 2019/1/16 その式、値ですか?場所ですか? Fact6: unsized

Slide 37

Slide 37 text

37 2019/1/16 その式、値ですか?場所ですか? 再掲 • 場所として使われる式はunsizedでもいいので、次の文は合法: let s = "あいう"; let ref t = s[3..6]; str 型 (参照束縛なので t は &str 型) str 型 (長さ不定)

Slide 38

Slide 38 text

38 2019/1/16 その式、値ですか?場所ですか? Unsized Rvalues (RFC1909, nightly) • 値として使われる式でも、条件次第でunsizedで あることを許す • 主な動機は2つ: • Box 等の値渡しオブジェクトの実 現 • [e; dyn n]: allocaに相当する処理

Slide 39

Slide 39 text

39 2019/1/16 その式、値ですか?場所ですか? Unsized Rvalues (RFC1909, nightly) • qnighyが実装しました! • #51131: 基本的なサポート • #54183: fn(self) をオブジェクト安全にする • まだやることは色々ある • 詳しくはまた別の機会に…… #![feature(unsized_locals)] fn foo(f: dyn FnOnce()) { f(); }

Slide 40

Slide 40 text

40 2019/1/16 その式、値ですか?場所ですか? まとめ • 値/場所にまつわる性質の整理を試みた。 • Fact1: 式には値と場所がある • Fact2: 暗黙変換は意識するに値する • Fact3: パターンマッチにも値と場所がある • Fact4: 字句的にわからないケースもある • Fact5: 場所として脱糖される式がある • Fact6: unsizedな値もある