调用`drop`后移动的变量仍在借用?

时间:2017-04-15 17:10:33

标签: rust lifetime

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在一个块中共存。

2 个答案:

答案 0 :(得分:8)

我无法给你一个明确的答案,但我会尝试在这里解释一些事情。让我们先澄清一下:

  

编译器知道drop()丢弃x

事实并非如此。虽然有一些&#34;魔法&#34;编译器知道的标准库中的内容,drop()不是 lang item 。事实上,您可以自己实施drop(),这实际上是最简单的事情:

fn drop<T>(_: T) {}

该函数只是按值取值(因此,它已移入drop())并且由于drop()内部没有任何反应,因此该值在范围的末尾被删除,如在任何其他功能。所以:编译器不知道x被删除,它只知道移动了x

您可能已经注意到,无论我们是否添加drop()调用,编译器错误都保持不变。现在,编译器只会在引用时查看变量的范围。来自Niko Matsakis' intro to NLL

  

编译器当前的工作方式,将引用分配给变量意味着它的生命周期必须与该变量的整个范围一样大。

a later blog post of his

  

特别是今天,一旦一生必须超出单一陈述的范围[...],它必须一直延伸到封闭区块的末尾。

这正是这里发生的事情,所以是的,你的问题与所有这些&#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"时文档中的含义。