Reputation: 1603
I'm working on a lexer that has the function lex
that should move a vector of scanned tokens to a main program that would then generate a parser to parse the tokens, defined as follows:
/// ### 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
}
The vector self.tokens: Vec<Token>
should contain tokens defined as
pub struct Token {
// -- snip of copyable fields --
lexeme: String, // <-- the issue
// -- snip of copyable fields --
}
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)?
I know the function isn't public, so it can't be called by anything outside the module, but it will be once I've tested it successfully.
Upvotes: 0
Views: 571
Reputation: 42462
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)?
You... can't? It doesn't really make sense, why are you both storing the token stream on self and returning it? One or the other would make sense (after all the caller could just get the tokens from the tokenizer if it wanted to). Or if you want the ability to, say, chain calls for some reason you could return a reference to the token stream owned by whatever Self
is.
/// 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
}
Alternatively, take self
by value in order to consume it, that way you can move the tokens out of self
as you destroy the latter.
/// 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
}
Finally you could implement Clone
on Token
and clone the entire Vec to return it, but that seems inefficient.
#[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()
}
Not really knowing what the underlying need is, it's hard to provide good recommendations.
Upvotes: 3