Rust 为什么要通过自动删除来访问引用变量?
在这段代码之前,我想我已经有了移动语义的概念Rust 为什么要通过自动删除来访问引用变量?,rust,Rust,在这段代码之前,我想我已经有了移动语义的概念 fn main() { let v = Data { body: vec![10, 40, 30], }; p(&v); } fn p(d: &Data) { for i in d.body { // &d.body, Why d.body move? println!("{}", i); } } struct Data { b
fn main() {
let v = Data {
body: vec![10, 40, 30],
};
p(&v);
}
fn p(d: &Data) {
for i in d.body {
// &d.body, Why d.body move?
println!("{}", i);
}
}
struct Data {
body: Vec<i32>,
}
我传递了一个引用,并通过自动排序功能访问了一个字段,那么为什么这是一个移动?此循环将:
如您所见,它正在使用
进入\u iter
,这将移动向量d.body
您正在访问d
中的字段body
<代码>正文本身是一个Vec
,它不是一个参考。如果要直接使用d
,则无需使用&
,但由于您要访问d
中的字段,因此必须指定要引用该字段
基本上
d
拥有body
。若你们借用d
你们不能窃取正文,它属于d
,但你们可以借用它。你们所做的是在指针上访问字段
检查:
如果点左侧的表达式类型是指针,则
根据需要自动取消引用多次,以使
现场访问是可能的
Rust如何对借用内容计算字段访问表达式的示例:
let d = Data { /*input*/}
let body = (&d).body // -> (*&d).body -> d.body
let ref_body = &(&d).body // -> &(*&).body -> &d.body -> &(d.body)
注意:d仍然是借来的内容,只需自动排序即可访问字段
为什么要搬家?
考虑以下代码:
struct Data {
body: Vec<i32>,
id: i32,
}
fn p(mut d: &Data) {
let id = d.id;
}
fn p(mut d: &Data) {
let id = d.id; // works
let body = d.body; // fails
}
此代码将不起作用,因为:
Rust将尝试复制d。body
但是Vec
没有实现copy
特性李>
Rust将尝试从d
移动正文
,您将得到“无法移出借用内容”错误李>
这对循环有什么影响?
从
for
表达式是一种语法结构,用于在std::iter::IntoIterator的实现提供的元素上循环
for循环等效于以下块表达式
'label: for PATTERN in iter_expr {
/* loop body */
}
相当于
{
let result = match IntoIterator::into_iter(iter_expr) {
mut iter => 'label: loop {
let mut next;
match Iterator::next(&mut iter) {
Option::Some(val) => next = val,
Option::None => break,
};
let PAT = next;
let () = { /* loop body */ };
},
};
result
}
这意味着您的向量必须具有IntoIterator
的实现,因为IntoIterator::into_iter(self)
需要self
作为参数。幸运的是,两者都存在
为什么会发生这种情况?
简单地说:
- 当您使用
&d.body
时,您的循环使用&Vec
实现IntoIterator
此实现返回指向向量切片的迭代器。这意味着您将从向量中获得元素的引用
- 使用
d.body
时,循环使用IntoIterator的Vec
实现
这个实现返回一个迭代器,它是一个使用迭代器。这意味着您的循环将拥有实际元素的所有权,而不是它们的引用。对于消费部分,此实现需要实际向量而不是引用,因此会发生移动。这并不能解决当d
是引用时d.body
移动的原因。如果直接使用d
,则不需要&
,但因为您正在访问d
中的字段,您必须指定希望引用该字段。-这个答案并没有描述为什么会发生这种情况。
{
let result = match IntoIterator::into_iter(iter_expr) {
mut iter => 'label: loop {
let mut next;
match Iterator::next(&mut iter) {
Option::Some(val) => next = val,
Option::None => break,
};
let PAT = next;
let () = { /* loop body */ };
},
};
result
}