2017-08-05 166 views
-3

我写了这个简单的输入解析:如何知道什么时候借结束

use std::io; 

fn main() { 
    let mut line = String::new(); 

    io::stdin().read_line(&mut line) 
     .expect("Cannot read line."); 

    let parts = line.split_whitespace(); 

    for p in parts { 
     println!("{}", p); 
    } 

    line.clear(); 
    io::stdin().read_line(&mut line) 
     .expect("Cannot read line."); 

} 

上面的代码创建了一个String对象,读取一行进去,用空白,并打印输出,他分裂了。然后它尝试使用相同的String对象执行相同的操作。在编译时,我得到错误:

--> src/main.rs:15:5 
    | 
9 |  let parts = line.split_whitespace(); 
    |     ---- immutable borrow occurs here 
... 
15 |  line.clear(); 
    |  ^^^^ mutable borrow occurs here 
... 
19 | } 
    | - immutable borrow ends here 

由于Stringowned by an iterator。该解决方案被描述为:

let parts: Vec<String> = line.split_whitespace() 
    .map(|s| String::from(s)) 
    .collect(); 

我有几个问题在这里:

  1. 我已经通过调用每个在它消耗的迭代器。它的借款应该已经结束。
  2. 如何从函数定义中知道借用的生命期?
  3. 如果一个函数是借用一个对象,我怎么知道它释放它?例如在解决方案中使用collect()释放借入。

我想我在这里错过了一个重要的概念。

+1

请仅发布[每个问题一个问题](https://meta.stackexchange.com/q/39223/281829)。 – Shepmaster

+0

这些是与相同概念相关的相关问题,因此发布三个单独的问题并不会富有成效。 – Xolve

回答

1

代码中的问题是,您将line.split_whitespace()的结果绑定到名称(parts)。如果你这样写:

io::stdin().read_line(&mut line) 
    .expect("Cannot read line."); 

for p in line.split_whitespace() { // <-- pass directly into loop 
    println!("{}", p); 
} 

line.clear(); 
io::stdin().read_line(&mut line) 
    .expect("Cannot read line."); 

这样,它只是工作。另一种可能性是,人为地限制parts的寿命,就像这样:

io::stdin().read_line(&mut line) 
    .expect("Cannot read line."); 

{ 
    let parts = line.split_whitespace(); 

    for p in parts { 
     println!("{}", p); 
    } 
} 

line.clear(); 
io::stdin().read_line(&mut line) 
    .expect("Cannot read line."); 

这也适用。


那么,为什么呢?这是由于编译器目前的工作原理,通常称为“词汇借用”。这里的问题是每个包含借款的非暂时性价值都将“活着”直到其范围结束。

对于您的情况:由于您将split_whitespace()(借用该字符串)的结果指定为parts,因此该借入是“存活”的,直到parts的范围结束为止。 不是直到parts的生命周期结束。

在这个答案的第一个版本中,我们没有绑定一个名称的值,因此split_whitespace()的结果只是一个临时的借位并没有扩展到整个范围。这也是为什么你的collect()例子工作原因:不是因为collect(),但因为从来没有一个名字绑定到借用字符串的东西。在我的第二个版本中,我们只是限制了范围。

请注意,这是编译器的一个已知的缺点。你是对的,编译器就是看不到它。

相关问题