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

标签 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();
        }
    }
}

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

最佳答案

[How do I] move [a] non-copyable struct across iterations

没有,至少不是微不足道的。一旦将结构移至函数,它就消失了。取回它的唯一方法是让函数将它还给您。

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

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

关于rust - 跨迭代移动不可复制的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42610685/

相关文章:

enums - 如何为枚举实现 Borrow、ToOwned 或 Deref?

arrays - 初始化固定长度数组的正确方法是什么?

testing - 当 HTTP 服务器在旧服务器关闭后启动时,测试会发生 panic

rust - 如何反序列化包含结构向量的枚举变体?

rust - 接受具有 IntoIterator 特征的切片元组切片的函数

rust - 使用serde_cbor在Rust中将Vec <u8>序列化为CBOR字节字符串

winapi - 使用 CString 时,使用 winapi 将 &str 写入控制台出错

rust - 函数数组类型的 `fn` 和 `||` 之间的差异

generics - 具有通用方法的特征的动态调度

rust - 有什么比在原始套接字上使用 libc 来实现任意协议(protocol)更好的呢?