我正在做一个词典,其中有一个函数是 lex
应将扫描的标记向量移动到主程序中,然后生成一个解析器来解析这些标记,定义如下。
/// ### 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>
应包含定义为
pub struct Token {
// -- snip of copyable fields --
lexeme: String, // <-- the issue
// -- snip of copyable fields --
}
然而,这将无法编译,因为 String
类型没有实现 Copy
特质。我怎样才能在将所有权传递给函数调用者的同时返回这个向量(比如移动它)?
我知道这个函数不是公开的,所以它不能被模块之外的任何东西调用,但是一旦我测试成功,它就会被调用。
然而,这将无法编译,因为String类型没有实现Copy特征。我怎样才能在将所有权传递给函数调用者的同时返回这个向量(比如移动它)?
你...不能?这真的没有意义,为什么你既要把token流存储在self上,又要返回它?其中之一是有意义的(毕竟如果调用者想的话,可以直接从tokenizer中获取token)。或者,如果你想要的能力,比如说,出于某种原因,你可以返回一个 参考 所拥有的令牌流。Self
是。
/// 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
因为你破坏了后者。
/// 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
}
最后,你可以实现 Clone
关于 Token
并克隆整个Vec来返回,但这样似乎效率很低。
#[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()
}
由于不知道底层需求是什么,很难提供好的建议。