关于 rust:如何从函数返回具有 String 类型字段的结构 Vec?

How to return a Vec of structs that have a String type field from a function?

我正在开发一个具有函数 lex 的词法分析器,该函数应该将扫描标记的向量移动到主程序,然后生成一个解析器来解析标记,定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
/// ### lex
/// Pushes the tokens generated by
/// `scan_token` to `self.tokens`
fn lex(&mut self) -> Vec<Token> {
    while !Self::is_at_eof(self) {
        self.lexeme_start = self.lookahead;
        self.tokens.push(Self::scan_token(self).unwrap());
    }
    self.tokens
        .push(Token::new(TokenType::EOF, String::from(""), self.row));
    self.tokens
}

向量 self.tokens: Vec<Token> 应该包含定义为

的标记

1
2
3
4
5
pub struct Token {
    // -- snip of copyable fields --
    lexeme: String, // <-- the issue
    // -- snip of copyable fields --
}

但是,这不会编译,因为 String 类型没有实现 Copy 特征。在将所有权传递给函数调用者时如何返回此向量(如移动它)?

我知道这个函数不是公开的,所以它不能被模块外的任何东西调用,但是一旦我成功测试它就会调用它。


However, this will not compile, as the String type does not implement the Copy trait. How might I return this vector while passing ownership to the function caller (as in move it)?

你……不能吗?这真的没有意义,为什么你们都将令牌流存储在 self 上并返回它?一个或另一个是有意义的(毕竟,如果调用者愿意,调用者可以从标记器中获取标记)。或者,如果您希望能够出于某种原因链接调用,您可以返回对 Self 所拥有的令牌流的引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// Option 0: return a reference to the Vec (could be mutable, so you could push into it)
fn lex0(&mut self) -> &Vec<Token> {
    while !self.is_at_eof() {
        self.lexeme_start = self.lookahead;
        self.scan_token();
    }
    self.tokens.push(Token::new(TokenType::EOF, String::from(""), self.row));
    &self.tokens
}
/// Option 1: return a slice reference (could be mutable, couldn't push into it)
fn lex1(&mut self) -> &[Token] {
    while !self.is_at_eof() {
        self.lexeme_start = self.lookahead;
        self.scan_token();
    }
    self.tokens.push(Token::new(TokenType::EOF, String::from(""), self.row));
    &self.tokens
}

或者,按值取 Self 以使用它,这样您可以在销毁后者时将令牌移出 Self

1
2
3
4
5
6
7
8
9
/// Option 2: consume lexer and return tokens stream
fn lex2(mut self) -> Vec<Token> {
    while !self.is_at_eof() {
        self.lexeme_start = self.lookahead;
        self.scan_token();
    }
    self.tokens.push(Token::new(TokenType::EOF, String::from(""), self.row));
    self.tokens
}

最后你可以在 Token 上实现 Clone 并克隆整个 Vec 以返回它,但这似乎效率低下。

1
2
3
4
5
6
7
8
9
10
11
12
#[derive(Clone)]
struct Token {...}

/// Option 3: copy tokens stream
fn lex3(&mut self) -> Vec<Token> {
    while !self.is_at_eof() {
        self.lexeme_start = self.lookahead;
        self.scan_token();
    }
    self.tokens.push(Token::new(TokenType::EOF, String::from(""), self.row));
    self.tokens.clone()
}

不知道潜在需求是什么,很难提供好的建议。