2017-03-05 7 views
0

forループ内の変数にアクセスしようとしています。私はStringが含まれているので、構造体にCopyを実装できません。どのようにして変数を繰り返し使用しますか?反復でコピーできない構造体を移動

コンパイル時にエラー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

なぜ 'parse'関数がInputParser実装の一部ですか? InputParserを返さず、自己参照もしません。 – SirDarius

+0

なぜ値で '自己 'を取っているのですか(' fn end(mut self) ')どこでも? – Shepmaster

+0

'self.consumed_quote = self.consumed_quote;'は非常に疑わしい行です。 – Shepmaster

答えて

4

[どのようにしてください] [A]あなたがいない、少なくともない自明んの反復

間でコピー不能構造体に移動。構造体を関数に移動すると、になります。それを元に戻す唯一の方法は、それをあなたに返す機能です。

代わりに、ループ内の既存の構造体を変更したい可能性があります。現在の引数を取るの前の道はerror[E0507]: cannot move out of borrowed contentにつながることを注意

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() {} 

ので、私は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

''オプション 'として実装される方が良いでしょうか? – SirDarius

+0

@SirDariusが動作するはずですが、私はそれがあなたが望むセマンティクスになると思います。空の文字列と欠けている文字列を区別することが重要な場合は、確かにそれが使用されているところで迷惑がかかります。しかし、 'Option :: take'に' Option'を使うことを考えているなら、 'mem :: replace'で実装されていることに注意してください!空の 'String'はかなり軽量ですが、ポインタサイズの整数はほんの数あり、ヒープの割り当てはありません。 'mem :: replace'については本当に恐ろしいことは何もありません。 – Shepmaster

+0

これは確かにここで理にかなっています。 – SirDarius

関連する問題