我有一个由多个条件组件组成的格式字符串,我正在寻找一种不需要为中间步骤多次分配字符串的解决方案。如果我使用 -macro 创建最终格式字符串的每个单独组件,format!
那么它可以工作,但我需要为每个组件进行分配。
我尝试尝试仅使用宏来生成复杂的格式字符串及其参数。但是,这总是会导致“在此语句结束时释放临时值”错误。我尝试使用单一类型的缓冲区impl core::fmt::Write
,但我也无法成功。
在高层次上,我想要这样的东西:
fn main() {
let prefix_include_a = true;
let prefix_include_b = true;
// prefix itself is a formatted string and it is further formatted here
println!("{prefix:<10}{message:>10}!",
prefix = format_prefix(prefix_include_a, prefix_include_b),
message = "message"
);
}
// formats the prefix component of the final string.
// needs multiple String allocations as `format!` is used
fn format_prefix(inc_a: bool, inc_b: bool) -> String {
format!("[{a:<5}{b:<5}]",
a = if inc_a {
format!("{:.1}", 1.234)
} else {
format!("")
},
b = if inc_b {
format!("{:.2}", 1.234)
} else {
format!("")
},
)
}
Run Code Online (Sandbox Code Playgroud)
这是否可以在没有或只有一次分配的情况下实现?
最简单的解决方案是直接write!
访问底层流,例如
use std::io::{stdout, Write};
fn main() {
let prefix_include_a = true;
let prefix_include_b = true;
let mut stdout = stdout();
let _ = format_prefix(&mut stdout, prefix_include_a, prefix_include_b);
let _ = write!(stdout, "{:>10}", "message");
}
// formats the prefix component of the final string.
// needs multiple String allocations as `format!` is used
fn format_prefix(mut s: impl Write, inc_a: bool, inc_b: bool) -> std::io::Result<()> {
write!(s, "[")?;
if inc_a {
write!(s, "{:<5.1}", 1.234)?;
} else {
write!(s, " ")?;
}
if inc_b {
write!(s, "{:<5.2}", 1.234)?;
} else {
write!(s, " ")?;
}
write!(s, "]")?;
Ok(())
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是将其具体prefix
化为类型并实现Display
它。我认为(希望?)格式化程序是底层流的传递,尽管我从未真正看过:
use std::io::{stdout, Write};
fn main() {
let prefix_include_a = true;
let prefix_include_b = true;
println!(
"{prefix:<10}{message:>10}!",
prefix = Prefix(prefix_include_a, prefix_include_b),
message = "message"
);
}
struct Prefix(bool, bool);
impl std::fmt::Display for Prefix {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
if self.0 {
write!(f, "{:<5.1}", 1.234)?;
} else {
write!(f, " ")?;
}
if self.1 {
write!(f, "{:<5.2}", 1.234)?;
} else {
write!(f, " ")?;
}
write!(f, "]")?;
Ok(())
}
}
Run Code Online (Sandbox Code Playgroud)
注意:我没有处理这两个版本中的前缀填充,尽管我认为这没有多大意义:两个前缀值都填充为 5,因此前缀始终至少为 12 宽。填充到 10 没有任何意义。
但是,如果需要,前缀对象可以使用外部指定的填充来分配到内部填充。请参阅std::fmt::Formatter
参考资料,您可以获得有关格式说明符的信息。
要清理条件,您可能可以使用format_args!
,尽管我对此缺乏经验。