借用チェッカのエラーを解消するにはまずエラーメッセージを読もう
from 借用チェッカとの戦いに勝利する
簡単な例
code:rs
let found = find(&format!("{} to search", "Text"), "ex");
if let Some(text) = found {
println!("Found '{text}'!")
}
上記のエラーメッセージ
借用ルール に違反した箇所とその理由
code:_
errorE0716: temporary value dropped while borrowed(一時的な値が使用中にドロップされた)
--> src/main.rs:6:23
|
| let found = find(&format!("{} to search", "Text"), "ex");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| - temporary value is freed at the end of this statement
| (一時的な値はこの文の最後に解放される)
| |
| creates a temporary value which is freed while still in use
| (使用中に解放される一時的な値をここで作成している)
| if let Some(text) = found {
| ----- borrow later used here(ここで後から借用が使われている)
|
何度も同じエラーに遭遇することで、借用チェッカ に関する直感が養われるため重要
回避策
code:_
= note: consider using a let binding to create a longer lived value
(let 束縛を用いて生存期間の長い値を作成することを検討)
上記のエラーメッセージを踏まえた修正
code:rs
let haystack = format!("{} to search", "Text");
let found = find(&haystack, "ex");
上記の修正は借用チェッカをパスするための簡単なコード修正のうちの 1 つ
1. 生存期間 の延長(上記): 一時的な値(生存期間が式の終わりまでしか続かない)を、新しいローカル変数として let 束縛 することで、生存期間をブロックの終わりまで延長する
2. 生存期間の短縮: 参照の使用箇所を {...} で囲み、ブロックの末尾で参照の生存期間が終わるようにする
ノンレキシカル生存期間 があるため、あまり使われることはない
しかし、それでも何度もブロックで囲んでいるのなら、メソッドとして カプセル化 すべきか検討しよう
warning.icon
提案される修正は問題が簡単な場合は有効だが、複雑な変換が絡むと有効でなくなり、説明も分かりづらくなる
code:rs
let x = Some(Rc::new(RefCell::new(Item { contents: 42 })));
check_item(x.as_ref().map(|r| r.borrow().deref()));
code:_
errorE0515: cannot return value referencing temporary value
--> src/main.rs:16:35
|
| check_item(x.as_ref().map(|r| r.borrow().deref()));
| ----------^^^^^^^^
| |
| returns a value referencing data owned
| by the current function temporary value created here
このような場合、複雑な変換の各ステップごとに、ローカル変数を明示的な 型注釈 付きで導入する と良い
code:rs
let x1: Option<&Rc<RefCell<Item>>> = x.as_ref();
let x2: Option<std::cell::Ref<Item>> = x1.map(|r| r.borrow());
let x3: Option<&Item> = x2.map(|r| r.deref());
check_item(x3);
code:_
errorE0515: cannot return value referencing function parameter r
--> src/main.rs:18:40
|
| let x3: Option<&Item> = x2.map(|r| r.deref());
| -^^^^^^^^
| |
| returns a value referencing data owned by
| the current function
| (この関数で所有されているデータの参照を返す)
これにより、コンパイルがどの変換に問題があるかを正確に特定でき、それに応じてコードを修正することができる
code:rs
match x2 {
None => check_item(None),
Some(r) => {
let x3: &Item = r.deref();
check_item(Some(x3));
}
}
修正できたら、ローカル変数を再び統合すれば良い
code:rs
match x.as_ref().map(|r| r.borrow()) {
None => check_item(None),
Some(r) => check_item(Some(r.deref()))
};
#Rust #Effective_Rust_―_Rustコードを改善し、エコシステムを最大限に活用するための35項目