Я пытаюсь реализовать простой интерпретатор в Rust, для которого я создал структуру Tokens
, которая принимает исходные символы и создает либо Token
, либо ScanError
внутри Result
:
pub struct Tokens<'src> {
chars: Chars<'src>,
}
impl<'src> Iterator for Tokens<'src> {
type Item = Result<Token, ScanError>;
fn next(&mut self) -> Option<Result<Token, ScanError>> {
// ...
}
}
Поскольку Result
реализует FromIterator
, просто собрать результат в первый ScanError
или вектор Token
s:
fn scan_tokens(source: &str) -> Result<Vec<Token>, ScanError> {
let iter = Tokens {
chars: source.chars(),
};
iter.collect()
}
В случае нескольких ошибок я действительно хочу вернуть каждую ошибку:
fn scan_tokens(source: &str) -> Result<Vec<Token>, Vec<ScanError>> {
// what goes here?
}
Насколько я знаю, невозможно реализовать мою собственную версию FromIterator
, потому что ни эта черта, ни Result
не являются локальными для моей корзины. Кто-нибудь может предложить чистый способ сделать это?
Я написал реализацию с использованием partition
на итераторе, затем развернул каждый Result
ниже, но читать его неинтересно и не похоже на хорошее использование итераторов:
type T = Vec<Result<Token, ScanError>>;
fn scan_tokens(source: &str) -> Result<Vec<Token>, Vec<ScanError>> {
let iter = Tokens {
chars: source.chars(),
};
let (tokens_results, error_results): (T, T) = iter.partition(|result| result.is_ok());
let errors: Vec<ScanError> = error_results
.into_iter()
.map(|result| result.unwrap_err())
.collect();
if errors.len() > 0 {
return Err(errors);
}
Ok(tokens_results
.into_iter()
.map(|result| result.unwrap())
.collect())
}