2017-03-05 59 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