2017-03-05 37 views
0

我试图访问for循环内的变量。我无法在结构上实现Copy,因为它包含String。我将如何在迭代中使用变量?跨迭代移动不可复制的结构

编译时出错E0382。当我查看Rust文档中的错误时,他们提到使用引用计数来解决问题。这是我的情况下唯一的解决方案?

#[derive(Clone)] 
struct InputParser { 
    args: Vec<String>, 
    current: String, 
    consumed_quote: bool, 
} 

impl InputParser { 
    pub fn parse(input: String) -> Vec<String> { 
     let parser = InputParser { 
      args: Vec::new(), 
      current: String::new(), 
      consumed_quote: false, 
     }; 
     for c in input.chars() { 
      match c { 
       '"' => parser.consume_quote(), 
       ' ' => parser.consume_space(), 
       _ => parser.consume_char(c), 
      } 
     } 
     parser.end(); 

     return parser.args; 
    } 

    pub fn consume_space(mut self) { 
     if !self.consumed_quote { 
      self.push_current(); 
     } 
    } 

    pub fn consume_quote(mut self) { 
     self.consumed_quote = self.consumed_quote; 
     if self.consumed_quote { 
      self.push_current(); 
     } 
    } 

    pub fn consume_char(mut self, c: char) { 
     self.current.push(c); 
    } 

    pub fn end(mut self) { 
     self.push_current(); 
    } 

    pub fn push_current(mut self) { 
     if self.current.len() > 0 { 
      self.args.push(self.current); 
      self.current = String::new(); 
     } 
    } 
} 

我想整个for循环迭代访问parser

+1

为什么InputParser实现的'parse'函数部分?它不返回InputParser也不返回自引用。 – SirDarius

+0

你为什么在价值上('fn end(mut self)')到处都是'self'? – Shepmaster

+0

'self.consumed_quote = self.consumed_quote;'是一条非常可疑的线条。 – Shepmaster

回答

4

[如何]移动[A]不可复制的跨迭代

结构你,至少不平凡。一旦你将结构移到一个函数中,它就是不见了。让它恢复的唯一方法就是让功能回馈给你。

相反,你很可能想要修改循环内的现有结构。您需要使用此一可变参考:

use std::mem; 

#[derive(Clone)] 
struct InputParser { 
    args: Vec<String>, 
    current: String, 
    consumed_quote: bool, 
} 

impl InputParser { 
    fn consume_space(&mut self) { 
     if !self.consumed_quote { 
      self.push_current(); 
     } 
    } 

    fn consume_quote(&mut self) { 
     self.consumed_quote = self.consumed_quote; 
     if self.consumed_quote { 
      self.push_current(); 
     } 
    } 

    fn consume_char(&mut self, c: char) { 
     self.current.push(c); 
    } 

    fn end(&mut self) { 
     self.push_current(); 
    } 

    fn push_current(&mut self) { 
     if self.current.len() > 0 { 
      let arg = mem::replace(&mut self.current, String::new()); 
      self.args.push(arg); 
     } 
    } 
} 

fn parse(input: String) -> Vec<String> { 
    let mut parser = InputParser { 
     args: Vec::new(), 
     current: String::new(), 
     consumed_quote: false, 
    }; 
    for c in input.chars() { 
     match c { 
      '"' => parser.consume_quote(), 
      ' ' => parser.consume_space(), 
      _ => parser.consume_char(c), 
     } 
    } 
    parser.end(); 

    parser.args 
} 

fn main() {} 

注意服用的当前参数前面的路会导致error[E0507]: cannot move out of borrowed content,所以我切换到mem::replace。这可以防止self.current永远成为一个未定义的值(这是之前的)。


如果你真的想要通过价值传递一切,你也需要返回值。

#[derive(Clone)] 
struct InputParser { 
    args: Vec<String>, 
    current: String, 
    consumed_quote: bool, 
} 

impl InputParser { 
    fn consume_space(mut self) -> Self { 
     if !self.consumed_quote { 
      return self.push_current(); 
     } 
     self 
    } 

    fn consume_quote(mut self) -> Self { 
     self.consumed_quote = self.consumed_quote; 
     if self.consumed_quote { 
      return self.push_current(); 
     } 
     self 
    } 

    fn consume_char(mut self, c: char) -> Self { 
     self.current.push(c); 
     self 
    } 

    fn end(mut self) -> Self { 
     self.push_current() 
    } 

    fn push_current(mut self) -> Self { 
     if self.current.len() > 0 { 
      self.args.push(self.current); 
      self.current = String::new(); 
     } 
     self 
    } 
} 

fn parse(input: String) -> Vec<String> { 
    let mut parser = InputParser { 
     args: Vec::new(), 
     current: String::new(), 
     consumed_quote: false, 
    }; 
    for c in input.chars() { 
     parser = match c { 
      '"' => parser.consume_quote(), 
      ' ' => parser.consume_space(), 
      _ => parser.consume_char(c), 
     } 
    } 
    parser = parser.end(); 

    parser.args 
} 

fn main() {} 

我相信这会让API在这种情况下客观地变差。但是,您会在制造商中经常看到这种风格。在这种情况下,这些方法往往是链接在一起的,所以你永远不会看到变量的重新分配。

+0

不会'当前'更好地实现为'Option '? – SirDarius

+0

@SirDarius可以工作,但我认为这归结于你希望拥有的语义。如果区分空字符串和缺少字符串很重要,那么当然,但是在使用它的任何地方都会有烦恼。但是,如果你正在考虑使用'Option'作为'Option :: take',注意它是用'mem :: replace'实现的!一个空的'String'也很轻量级,只有几个指针大小的整数,没有堆分配。 'mem :: replace'没有什么可怕的。 – Shepmaster

+0

确实有意义。 – SirDarius