error[E0506]: cannot assign to `var` because it is borrowed
参照中の変数への書込を行った。
このエラー自体のルールは単純である。
しかし、エラーを読み解くには、参照まわりのその他の知識も必要になる事がある。
例えば、『ライフタイムの延長』の影響があると、初見では納得しにくいエラーになる。
メッセージの構成はだいたい以下のようになる。
最も単純なパターン。
fn main() {
let mut var = 0;
let var_ref = &var;
var = 1;
println!("{var}, {var_ref}");
}
error[E0506]: cannot assign to `var` because it is borrowed --> src\main.rs:4:5 | 3 | let var_ref = &var; | ---- `var` is borrowed here 4 | var = 1; | ^^^^^^^ `var` is assigned to here but it was already borrowed 5 | println!("{var}, {var_ref}"); | ------- borrow later used here
Drop
トレイトの影響 (通常版)
詳しくは『Drop トレイトのライフタイムへの影響 - ライフタイムの延長』を参照。
(注: Drop
トレイトを直接的に扱っていなくても考慮が必要。)
fn main() {
let mut var = 1;
let _refs = MyRef(&var);
var = 2;
dbg!(var);
}
struct MyRef<'a>(&'a i32);
impl Drop for MyRef<'_> {
fn drop(&mut self) {
println!("ID [{}] is drpoped.", self.0)
}
}
error[E0506]: cannot assign to `var` because it is borrowed --> src\main.rs:4:5 | 3 | let _refs = MyRef(&var); | ---- `var` is borrowed here 4 | var = 2; | ^^^^^^^ `var` is assigned to here but it was already borrowed 5 | dbg!(var); 6 | } | - borrow might be used here, when `_refs` is dropped and runs the `Drop` code for type `MyRef`
Drop
トレイトの影響 (複数の文での自己更新)
これは前のパターンの特殊版で、Drop
トレイトでライフタイムが延長された参照元が残った状態で、その参照元を更新すると発生する。
fn main() {
let mut var = MyType(1);
let refs = var.refs();
var = refs.new_value();
dbg!(var.0);
}
struct MyType(i32);
impl MyType {
fn refs(&self) -> MyRef<'_> {
MyRef(&self.0)
}
}
struct MyRef<'a>(&'a i32);
impl MyRef<'_> {
fn new_value(&self) -> MyType {
MyType(self.0 + 1)
}
}
impl Drop for MyRef<'_> {
fn drop(&mut self) {
println!("ID [{}] is drpoped.", self.0);
}
}
error[E0506]: cannot assign to `var` because it is borrowed --> src\main.rs:4:5 | 3 | let refs = var.refs(); | --- `var` is borrowed here 4 | var = refs.new_value(); | ^^^^^^^^^^^^^^^^^^^^^^ `var` is assigned to here but it was already borrowed 5 | dbg!(var.0); 6 | } | - borrow might be used here, when `refs` is dropped and runs the `Drop` code for type `MyRef`
更新値の導出と設定を分けると良い。
fn main() {
let mut var = MyType(1);
let refs = var.refs();
let new_value = refs.new_value();
drop(refs);
var = new_value;
dbg!(var.0);
}
struct MyType(i32);
impl MyType {
fn refs(&self) -> MyRef<'_> {
MyRef(&self.0)
}
}
struct MyRef<'a>(&'a i32);
impl MyRef<'_> {
fn new_value(&self) -> MyType {
MyType(self.0 + 1)
}
}
impl Drop for MyRef<'_> {
fn drop(&mut self) {
println!("ID [{}] is drpoped.", self.0);
}
}
Drop
トレイトの影響 (一つの文での自己更新)これは前のパターンの特殊版で、問題となる処理が一文に短縮されている。これにより、文内での一時的な値が絡むため、メッセージが少しだけ変化する。
fn main() {
let mut var = MyType(1);
var = var.refs().new_value();
dbg!(var.0);
}
struct MyType(i32);
impl MyType {
fn refs(&self) -> MyRef<'_> {
MyRef(&self.0)
}
}
struct MyRef<'a>(&'a i32);
impl MyRef<'_> {
fn new_value(&self) -> MyType {
MyType(self.0 + 1)
}
}
impl Drop for MyRef<'_> {
fn drop(&mut self) {
println!("ID [{}] is drpoped.", self.0);
}
}
error[E0506]: cannot assign to `var` because it is borrowed --> src\main.rs:3:5 | 3 | var = var.refs().new_value(); | ^^^^^^----------^^^^^^^^^^^^- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MyRef` | | | | | `var` is borrowed here | | a temporary with access to the borrow is created here ... | `var` is assigned to here but it was already borrowed
前のパターンと同様、更新値の導出と設定を分けると良い。
fn main() {
let mut var = MyType(1);
let new_value = var.refs().new_value();
var = new_value;
dbg!(var.0);
}
struct MyType(i32);
impl MyType {
fn refs(&self) -> MyRef<'_> {
MyRef(&self.0)
}
}
struct MyRef<'a>(&'a i32);
impl MyRef<'_> {
fn new_value(&self) -> MyType {
MyType(self.0 + 1)
}
}
impl Drop for MyRef<'_> {
fn drop(&mut self) {
println!("ID [{}] is drpoped.", self.0);
}
}