fn main() {
let mut x: Vec<&i32> = vec![];
let a = 1;
x.push(&a);
drop(x);
// x.len(); // error[E0382]: use of moved value: `x`
} // `a` dropped here while still borrowed
编译器知道drop()
drop x
(从注释掉的代码中的错误中可以看出),但仍然认为变量是从a
借来的!这是不公平的!
这应该被视为rust-lang/rust#6393的众多欺骗之一(现在由rust-lang/rfcs#811跟踪?)但是那里的讨论似乎集中于制作&mut self
和{{1在一个块中共存。
答案 0 :(得分:8)
我无法给你一个明确的答案,但我会尝试在这里解释一些事情。让我们先澄清一下:
编译器知道
drop()
丢弃x
事实并非如此。虽然有一些&#34;魔法&#34;编译器知道的标准库中的内容,drop()
不是 lang item 。事实上,您可以自己实施drop()
,这实际上是最简单的事情:
fn drop<T>(_: T) {}
该函数只是按值取值(因此,它已移入drop()
)并且由于drop()
内部没有任何反应,因此该值在范围的末尾被删除,如在任何其他功能。所以:编译器不知道x
被删除,它只知道移动了x
。
您可能已经注意到,无论我们是否添加drop()
调用,编译器错误都保持不变。现在,编译器只会在引用时查看变量的范围。来自Niko Matsakis' intro to NLL:
编译器当前的工作方式,将引用分配给变量意味着它的生命周期必须与该变量的整个范围一样大。
特别是今天,一旦一生必须超出单一陈述的范围[...],它必须一直延伸到封闭区块的末尾。
这正是这里发生的事情,所以是的,你的问题与所有这些&#34;词汇借用&#34;东西。从当前的编译器角度来看,表达式&a
的生命周期必须至少与x
的范围一样大。但这不起作用,因为引用会比a
更长,因为x
的范围大于编译器指出的a
的范围:
= note: values in a scope are dropped in the opposite order they are created
我猜你已经知道这一切,但你可以通过交换let mut x ...;
和let a ...;
行来修复你的例子。
我不确定这个确切的问题是否可以通过任何当前提出的解决方案来解决。但我希望我们能尽快看到,因为所有这些都是Rust 2017路线图的一部分。阅读更新的好地方是here(其中还包含指向Niko的五篇相关博客文章的链接)。
答案 1 :(得分:5)
编译器知道
[Authorize] [Route("api/[controller]")] public class ApprovalsController : Controller { // POST api/approvals [HttpPost] public IActionResult Post([FromBody]ApprovalViewModel value) { // ... // Incoming approval VM converted here Approval newApproval = TinyMapper.Map<Approval>(value); // Values set server-side here. newApproval.Id = -1; newApproval.Created = DateTime.Now; // Claim queried here newApproval.CreatedBy = User.FindFirst(ClaimTypes.Name).Value; // Submission to context _approvalRepo.Insert(newApproval); _approvalRepo.Update(); // ... }
丢弃drop()
(从注释掉的代码中的错误可以看出)
Rust编译器对x
及其作用一无所知。它只是一个库函数,可以做任何它喜欢的值,因为它现在拥有它。
正如文档所指出的那样,drop
的定义只是:
drop
它起作用,因为它将参数移入函数中,因此在函数完成时由编译器自动删除。
如果您创建自己的功能,您将收到完全相同的错误消息:
fn drop<T>(_x: T) { }
这正是it says drop
"isn't magic"时文档中的含义。