我怀疑答案与“macro_rules!impl_format”有关,但这正是我头疼的地方。
impl_format! 宏用于实现各种格式化特征。
impl_format!{Display Debug
UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer}
作者选择编写宏是因为实现看起来都一样。重复在宏中的工作方式意味着宏即使只使用一次也会非常有用(在这里,我们可以通过为每个特征调用一次宏来做到这一点,但通常情况并非如此)。
我们把LowerHex的实现扩展为Format看看:
impl<'a, I> fmt::LowerHex for Format<'a, I>
where I: Iterator,
I::Item: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f, fmt::LowerHex::fmt)
}
}
fmt 方法调用在同一模块中定义的另一个方法 format。
impl<'a, I> Format<'a, I>
where I: Iterator,
{
fn format<F>(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result
where F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result,
{
let mut iter = match self.inner.borrow_mut().take() {
Some(t) => t,
None => panic!("Format: was already formatted once"),
};
if let Some(fst) = iter.next() {
cb(&fst, f)?;
for elt in iter {
if self.sep.len() > 0 {
f.write_str(self.sep)?;
}
cb(&elt, f)?;
}
}
Ok(())
}
}
format 有两个参数:格式化程序(f)和格式化函数(cb 用于回调)。这里的格式化函数是fmt::LowerHex::fmt。这是来自 LowerHex 特征的 fmt 方法;编译器如何确定使用哪个LowerHex 实现?它是从format 的类型签名推断出来的。 cb的类型为F,F必须实现FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result。注意第一个参数的类型:&I::Item(I 是传递给format 的迭代器的类型)。 LowerHex::fmt'签名是:
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
对于实现LowerHex的任何类型Self,此函数将实现FnMut(&Self, &mut fmt::Formatter) -> fmt::Result。因此,编译器推断出Self == I::Item。
这里需要注意的重要一点是格式化属性(例如,格式化字符串中的02)存储在Formatter 中。例如的实现LowerHex 将使用诸如Formatter::width 之类的方法来检索属性。这里的技巧是使用相同的格式化程序来格式化多个值(具有相同的属性)。
在 Rust 中,可以通过两种方式调用方法:使用方法语法和使用函数语法。这两个函数是等价的:
use std::fmt;
pub fn method_syntax(f: &mut fmt::Formatter) -> fmt::Result {
use fmt::LowerHex;
let x = 42u8;
x.fmt(f)
}
pub fn function_syntax(f: &mut fmt::Formatter) -> fmt::Result {
let x = 42u8;
fmt::LowerHex::fmt(&x, f)
}
当format 与fmt::LowerHex::fmt 一起调用时,这意味着cb 引用fmt::LowerHex::fmt。 format 必须使用函数调用,因为无法保证回调甚至是方法!
我是不是在滥用 itertools
一点也不;事实上,这正是 format 的用途。
也许有更好、更简单的方法来解决这个问题
当然有更简单的方法,但是使用format 非常有效,因为它不分配动态内存。