第44回です。前回はこちら。
[第44回の様子]
2022/06/22に第44回を開催した。
内容としてはRust By Example 日本語版の「15.3.3. refパターン」、「15.4. ライフタイム」、「15.4.1. 明示的アノテーション」に取り組んだ。
参加者は自分を入れて4人。継続的に参加してくれる皆様に感謝。
[学んだこと]
- 15.3.3. refパターン
- 先週まで、借用の方法として&T型を利用してきた
- 同じようにrefキーワードを利用して借用することもできる
fn main() {
let c = 'Q';
// 借用方法2パターン:どちらも結果は同じ
let ref ref_c1 = c;
let ref_c2 = &c;
// アドレスも出力して値が同じだけでなく参照先が同じことも確認
println!("ref_c1 equals ref_c2: {}, {:p}, {:p}", *ref_c1 == *ref_c2, ref_c1, ref_c2);
// ref_c1 equals ref_c2: true, 0x7ffc11447c14, 0x7ffc11447c14
}
- デストラクトする時など、&が使えないときにrefキーワードを利用する
#[derive(Clone, Copy)]
struct Point { x: i32, y: i32 }
fn main() {
let point = Point { x: 0, y: 0 };
let _copy_of_x = {
// xへの参照を取得
let Point { x: ref ref_to_x, y: _ } = point;
// コピーを返す
*ref_to_x
};
println!("{} {:p}", _copy_of_x, &_copy_of_x);
// 0 0x7ffd09aaee14
// コピーなのでアドレスが変わっている
}
- ミュータブルにrefを取ることもできる
#[derive(Clone, Copy)]
struct Point { x: i32, y: i32 }
fn main() {
let point = Point { x: 0, y: 0 };
let mut mutable_point = point;
{
// yのミュータブルな参照を取得
let Point { x: _, y: ref mut mut_ref_to_y } = mutable_point;
*mut_ref_to_y = 1;
}
println!("point is ({}, {})", point.x, point.y); // 0, 0
println!("mutable_point is ({}, {})", mutable_point.x, mutable_point.y); // 0, 1
}
- 15.4. ライフタイム
- ライフタイムはコンパイラが借用の問題をチェックするための仕組みらしい
- 変数のライフタイムは作成時に開始、破棄されるときに終了
- ライフタイムとスコープは同時に語られるが、同じものではない
- ライフタイムには型や名前がつかない点に注意
- 15.4.1. 明示的アノテーション
- ライフタイムはジェネリクスの形で表現される
// aというライフタイムパラメータをもつfoo // fooのライフタイムはaのライフタイムを超えない foo<'a> // a、bというライフタイムパラメータをもつfoo // fooのライフタイムはaとbのライフタイムを超えない foo<'a, 'b>
- 関数の場合、以下のようになる
// `print_refs`は`i32`への参照を2つとる
// 変数は'aと'bというライフタイムを持つ
fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) {
println!("x is {} and y is {}", x, y);
}
fn main() {
let (four, nine) = (4, 9);
// 2つの変数の借用(`&`)を関数に渡す
print_refs(&four, &nine);
// x is 4 and y is 9
}
- 引数を取らない関数もライフタイムパラメータをもつことがある
- その場合、'staticなライフタイムとなる
fn failed_borrow<a>() {
let _x = 12;
let y: &'a i32 = &_x;
// &_xのライフタイムはこの関数内に限定される
// しかしyはライフタイムパラメータ'aをもつ
// failed_borrowは引数として参照を持たない
// この場合ライフタイム'aはデフォルトで'staticになる
// staticはプログラムの開始から終了までのイメージ(違うかも
// yのライフタイムより&_xのライフタイムの方が短いため代入できない
}
fn main() {
failed_borrow();
}
// 以下のコンパイルエラー
error[E0597]: `_x` does not live long enough
--> src/main.rs:9:22
|
4 | fn failed_borrow<'a>() {
| -- lifetime `'a` defined here
...
9 | let y: &'a i32 = &_x;
| ------- ^^^ borrowed value does not live long enough
| |
| type annotation requires that `_x` is borrowed for `'a`
...
16 | }
| - `_x` dropped here while still borrowed
[まとめ]
モブプログラミングスタイルでRust dojoを開催した。
ライフタイムなんもわからん...。
プルリクエストはこちら。