在结构的字段中使用引用时是否有任何限制?
Are there any restrictions when using a reference in a field of a struct?
我正在尝试了解 Rust 中的生命周期如何影响结构。附件是一个让我感到困惑的最小示例。
我想给一个结构体一个对象的引用,然后需要更改这个对象。由于无法在借用对象时更改对象,因此我认为我必须在更改它时删除引用。所以我的想法是将变量定义为一个选项,并通过将其设置为 None
来在修改对象期间删除引用。对于不使用 Struct 的示例,这似乎可行。
但是,如果我现在将此引用放入 Struct 中,它将不起作用。在我看来,借用检查器忽略了变量 string
不再被借用的事实。有没有办法仍然通过结构实现所需的行为?
这个有效(link to playground):
fn main() {
let mut string = "mutable string".to_string();
let mut ref_to_string: Option<&str> = Some(&string);
ref_to_string = None;
string = "mutated string".to_string();
ref_to_string = Some(&string);
}
然而,这不起作用link to playground:
struct Foo<'a> {
pub ref_data: Option<&'a str>,
}
fn main() {
let mut string = "mutable string".to_string();
let mut foo = Foo{ref_data: Some(&string)};
foo.ref_data = None;
string = "mutated string".to_string();
foo.ref_data = Some(&string);
}
错误信息:
error[E0506]: cannot assign to `string` because it is borrowed
--> src/main.rs:11:5
|
9 | let mut foo = Foo{ref_data: Some(&string)};
| ------- borrow of `string` occurs here
10 | foo.ref_data = None;
11 | string = "mutated string".to_string();
| ^^^^^^ assignment to borrowed `string` occurs here
12 | foo.ref_data = Some(&string);
| ---------------------------- borrow later used here
For more information about this error, try `rustc --explain E0506`.
问题是整个 Foo
在整个生命周期内都是通用的。这样,当您分配 foo = Foo {ref_data: Some(&string)}
时,foo
的类型是 Foo<'lifetime_of_string>
。您可以将 foo.ref_data
设置为 None
任意设置,但就借用检查而言,仍然存在生命周期与 string
重叠的活动对象。为此,只要foo
活着,string
就被借了。唯一的方法是删除整个 foo
:
let mut string = "mutable string".to_string();
let mut foo = Foo{ref_data: Some(&string)};
drop(foo);
foo = Foo { ref_data: None };
string = "mutated string".to_string();
foo.ref_data = Some(&string);
问题是您引用了 string
变量两次。借用第一个时绑定 &str
生命周期至少为 foo
。引用另一个存在于“另一个”变量中的字符串应该没有问题:
fn main() {
let string = "mutable string".to_string();
let mut foo = Foo {
ref_data: Some(&string),
};
foo.ref_data = None;
let string = "mutated string".to_string();
foo.ref_data = Some(&string);
}
注意使用另一个let
绑定而不是改变变量。
秘密在于Foo
结构的定义:
struct Foo<'a> {
pub ref_data: Option<&'a str>,
}
更具体地说,在 'a
生命周期说明符中。通过指定 Foo
的寿命为 'a
并且 ref_data
具有相同的寿命 (&'a str
),您说您的 &str
的寿命与 Foo
。所以只要 Foo
还活着,编译器就不能删除对 string
.
的引用
不幸的是,只有在字段为 Some
.
时,无法指定该结构的生命周期为 'a
要改变结构引用的对象,您可以:
- 将对象的所有权转移到结构,然后从结构中获取对它的可变引用。
- 使用内部可变性(参见
RefCell
)。
- 在变异之前删除你的结构,并在变异完成后重新创建它。
哪种方法更好取决于您的具体用例。
我正在尝试了解 Rust 中的生命周期如何影响结构。附件是一个让我感到困惑的最小示例。
我想给一个结构体一个对象的引用,然后需要更改这个对象。由于无法在借用对象时更改对象,因此我认为我必须在更改它时删除引用。所以我的想法是将变量定义为一个选项,并通过将其设置为 None
来在修改对象期间删除引用。对于不使用 Struct 的示例,这似乎可行。
但是,如果我现在将此引用放入 Struct 中,它将不起作用。在我看来,借用检查器忽略了变量 string
不再被借用的事实。有没有办法仍然通过结构实现所需的行为?
这个有效(link to playground):
fn main() {
let mut string = "mutable string".to_string();
let mut ref_to_string: Option<&str> = Some(&string);
ref_to_string = None;
string = "mutated string".to_string();
ref_to_string = Some(&string);
}
然而,这不起作用link to playground:
struct Foo<'a> {
pub ref_data: Option<&'a str>,
}
fn main() {
let mut string = "mutable string".to_string();
let mut foo = Foo{ref_data: Some(&string)};
foo.ref_data = None;
string = "mutated string".to_string();
foo.ref_data = Some(&string);
}
错误信息:
error[E0506]: cannot assign to `string` because it is borrowed
--> src/main.rs:11:5
|
9 | let mut foo = Foo{ref_data: Some(&string)};
| ------- borrow of `string` occurs here
10 | foo.ref_data = None;
11 | string = "mutated string".to_string();
| ^^^^^^ assignment to borrowed `string` occurs here
12 | foo.ref_data = Some(&string);
| ---------------------------- borrow later used here
For more information about this error, try `rustc --explain E0506`.
问题是整个 Foo
在整个生命周期内都是通用的。这样,当您分配 foo = Foo {ref_data: Some(&string)}
时,foo
的类型是 Foo<'lifetime_of_string>
。您可以将 foo.ref_data
设置为 None
任意设置,但就借用检查而言,仍然存在生命周期与 string
重叠的活动对象。为此,只要foo
活着,string
就被借了。唯一的方法是删除整个 foo
:
let mut string = "mutable string".to_string();
let mut foo = Foo{ref_data: Some(&string)};
drop(foo);
foo = Foo { ref_data: None };
string = "mutated string".to_string();
foo.ref_data = Some(&string);
问题是您引用了 string
变量两次。借用第一个时绑定 &str
生命周期至少为 foo
。引用另一个存在于“另一个”变量中的字符串应该没有问题:
fn main() {
let string = "mutable string".to_string();
let mut foo = Foo {
ref_data: Some(&string),
};
foo.ref_data = None;
let string = "mutated string".to_string();
foo.ref_data = Some(&string);
}
注意使用另一个let
绑定而不是改变变量。
秘密在于Foo
结构的定义:
struct Foo<'a> {
pub ref_data: Option<&'a str>,
}
更具体地说,在 'a
生命周期说明符中。通过指定 Foo
的寿命为 'a
并且 ref_data
具有相同的寿命 (&'a str
),您说您的 &str
的寿命与 Foo
。所以只要 Foo
还活着,编译器就不能删除对 string
.
不幸的是,只有在字段为 Some
.
'a
要改变结构引用的对象,您可以:
- 将对象的所有权转移到结构,然后从结构中获取对它的可变引用。
- 使用内部可变性(参见
RefCell
)。 - 在变异之前删除你的结构,并在变异完成后重新创建它。
哪种方法更好取决于您的具体用例。