Как статически преобразовать `chrono::format::strftime` в`chrono::format::Item`?
У меня есть статический массив chrono::format::strftime
форматы, которые поддерживает мое приложение. Я хотел бы избежать их анализа во время выполнения, поэтому я определил lazy_static!
блок, который анализирует их в коллекцию chrono::format::Item
,
Однако, когда я пытаюсь перебрать разобранную коллекцию, я получаю сообщение об ошибке:
the trait bound `&chrono::format::StrftimeItems<'_>: std::iter::Iterator` is not satisfied
Вот короткая репродукция:
#[macro_use]
extern crate lazy_static;
extern crate chrono;
use chrono::DateTime;
use chrono::offset::FixedOffset;
use chrono::format::{Parsed, parse};
use chrono::format::strftime::StrftimeItems;
static FORMATS : &[&'static str] = &["%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S%.f"];
lazy_static! {
static ref PARSED_FORMATS : Vec<StrftimeItems<'static>> = FORMATS
.iter()
.map(|format| StrftimeItems::new(format))
.collect();
}
fn parse_datetime(s: &str) -> Option<DateTime<FixedOffset>> {
for format in PARSED_FORMATS.iter() {
let mut parsed = Parsed::new();
let dt = parse(&mut parsed, &s, format)
.and_then(|_| parsed.to_datetime() );
if dt.is_ok() {
return dt.ok()
}
}
return None
}
Попытка отмены ссылки format
в цикле выдает эту ошибку:
error[E0507]: cannot move out of borrowed content
--> src\main.rs:21:35
|
21 | let dt = parse(&mut parsed, &s, *format)
| ^^^^^^^ cannot move out of borrowed content
error: aborting due to previous error
Попытка клонировать format
кажется, работает, однако клонирование здесь кажется излишним, и я хотел бы избежать этого.
Это правильный подход здесь? или, возможно, использование макроса является лучшим вариантом?
1 ответ
StrftimeItems
это итератор, а не итеративный контейнер (как Vec
является). Когда вы продвигаете итератор, вы не можете перемотать его. parse
должен получить итератор по значению, что означает, что вы должны взять StrftimeItems
наш ваш вектор (что означает, что вы не можете использовать его впоследствии) или клонировать StrftimeItems
хранится в векторе. Клонируя StrftimeItems
Вы можете создать новый итератор, состояние которого отличается от исходного (то есть продвижение одного не продвигает другого).
Я хотел бы избежать их анализа во время выполнения
Тем не мение, StrftimeItems
не позволяет вам достичь своей цели, потому что StrftimeItems
лениво разбирает строку формата по мере продвижения итератора.
Вместо этого я бы предложил вам собрать результаты этого итератора в Vec<Item<'static>>
,
#[macro_use]
extern crate lazy_static;
extern crate chrono;
use chrono::DateTime;
use chrono::offset::FixedOffset;
use chrono::format::{Item, Parsed, parse};
use chrono::format::strftime::StrftimeItems;
static FORMATS : &[&'static str] = &["%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S%.f"];
lazy_static! {
static ref PARSED_FORMATS : Vec<Vec<Item<'static>>> = FORMATS
.iter()
.map(|format| StrftimeItems::new(format).collect())
.collect();
}
fn parse_datetime(s: &str) -> Option<DateTime<FixedOffset>> {
for format in PARSED_FORMATS.iter() {
let mut parsed = Parsed::new();
let dt = parse(&mut parsed, &s, format.iter().cloned())
.and_then(|_| parsed.to_datetime() );
if dt.is_ok() {
return dt.ok()
}
}
return None
}
Теперь, когда мы звоним parse
мы проходим format.iter().cloned()
, format
это Vec<Item<'static>>
, iter()
производит свежий итератор по ссылкам на Item
с и cloned()
адаптирует итератор так, чтобы каждый Item
возвращается по значению (достигается путем их клонирования), а не по ссылке (потому что parse
ожидает итератор Item
ценности, а не Item
Рекомендации).