如何静态地将 `chrono::format::strftime` 转换为 `chrono::format::Item`?

How to transform `chrono::format::strftime` to `chrono::format::Item` statically?

我有一个我的应用程序支持的 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 似乎可行,但克隆在这里似乎是多余的,我想避免它。

这是正确的方法吗?或者使用宏可能是更好的选择?

StrftimeItems 是一个迭代器,而不是一个可迭代的容器(就像 Vec 是)。当你推进一个迭代器时,你不能倒带它。 parse 必须按值接收一个迭代器,这意味着您必须获取一个 StrftimeItems 我们的向量(这意味着您不能在之后重用它)或克隆 StrftimeItems 存储在向量。通过克隆 StrftimeItems,您可以生成一个新的迭代器,其状态与原始状态不同(即推进一个不会推进另一个)。

I'd like to avoid parsing them during run time

但是,StrftimeItems不会让你达到目的,因为StrftimeItems lazily parses the format string as the iterator advances

相反,我建议您将该迭代器的结果收集到 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 引用)。