跨迭代移动不可复制的结构

时间:2017-03-05 16:10:18

标签: rust

我正在尝试访问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();
        }
    }
}

我希望在parser循环的迭代中访问for

1 个答案:

答案 0 :(得分: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在这种情况下客观上更糟。但是,您会在构建器中经常看到此样式。在这种情况下,方法往往被链接在一起,因此您永远不会看到对变量的重新分配。