ローカル変数の借用
- Rustコンパイラは、プログラム中の全ての参照型に対して、その参照の使用方法によって生じる制約を反映した生存期間(lifetime)を割り当てる
- 生存期間とは、プログラム実行中のある参照が安全に利用できる期間
例
fn main() {
let r;
{
let x = 1;
r = &x;
}
assert_eq!(*r, 1);
}
&xの生存期間
rに格納された値に必要な最低限の生存期間
エラーになる原因
改善例
fn main() {
let x = 1;
{
let r = &x;
assert_eq!(*r, 1);
}
}
diff
--- 改善前
+++ 改善後
@@ -1,8 +1,7 @@
fn main() {
- let r;
+ let x = 1;
{
- let x = 1;
- r = &x;
+ let r = &x;
+ assert_eq!(*r, 1);
}
- assert_eq!(*r, 1);
}
仮引数として参照を受け取る場合
- デフォルトでは生存期間の記述は省略されている
fn f<'a>(p: &'a i32)
- この関数が「任意の生存期間'a を持つ i32 への参照 」を引数として取ることを意味
- staticの生存期間はプログラムの開始から終了まで
- 引数の生存期間を合わせるために明示的に生存期間を指定する必要がある場合がある
main.rs
static mut STASH: &i32 = &128;
fn f(p: &'static i32) {
unsafe {
STASH = p;
}
}
fn main() {
unsafe {
println!("{}", STASH);
f(&256);
println!("{}", STASH);
}
}
$ cargo run
128
256
参照を含む構造体
main.rs
struct S<'a> {
r: &'a i32,
}
struct D<'a> {
s: S<'a>,
}
fn main() {
let x = 10;
let s = S { r: &x };
assert_eq!(*s.r, 10);
let d = D { s };
assert_eq!(*d.s.r, 10);
}
個別の生存期間のパラメータ
- s.xの生存期間とs.yの生存期間が異なるので、異なる生存期間を設定する必要がある
- 改善前のコードでは r = s.x により x の方が長い生存期間となっている
- 最も単純な定義から始めて、コンパイルできるまで、徐々に制約を緩めていくアプローチがよい
- 安全でない限りコードがコンパイルできないので、問題が明らかになるまで待つで問題ない
改善前
main.rs
/// xとyに対して同じ生存期間を設定
struct S<'a> {
x: &'a i32,
y: &'a i32,
}
fn main() {
let x = 10;
let r;
{
let y = 20;
{
let s = S { x: &x, y: &y };
r = s.x
}
}
println!("{}", r);
}
改善後
main.rs
/// xとyに対して異なる生存期間を設定
struct S<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
fn main() {
let x = 10;
let r;
{
let y = 20;
{
let s = S { x: &x, y: &y };
r = s.x
}
}
println!("{}", r);
}