为什么这样做?
fn main() {
println!("{:.3}", "this is just a test");
}
Run Code Online (Sandbox Code Playgroud)
打印 => thi
虽然这没有?
fn main() {
println!("{:.3}", format_args!("this is just a test"));
}
Run Code Online (Sandbox Code Playgroud)
打印 => this is just a test
这里是游乐场。
对于更多的上下文,我对其背后的推理感兴趣,以及一种无需任何分配就可以做到的方法。
我正在用 Rust开发一个终端游戏,其中有一个write!显示有关渲染和游戏循环的一些统计信息,并且该文本可能很长。现在我读取了终端大小并相应地调整了它的输出,我需要截断该输出,但没有任何分配。当我重构这个时,我认为我非常聪明:
write!(
stdout,
"{} ({} {} {}) {}",
...
)
Run Code Online (Sandbox Code Playgroud)
进入这个:
write!(
stdout,
"{:.10}", // simulate only 10 cols in terminal.
format_args!(
"{} ({} {} {}) {}",
...
)
)
Run Code Online (Sandbox Code Playgroud)
多么不幸,它不起作用……如何在不分配字符串的情况下做到这一点?
一方面,并非每种类型都遵守所有格式参数:
println!("{:.3}", 1024);
Run Code Online (Sandbox Code Playgroud)
println!("{:.3}", 1024);
Run Code Online (Sandbox Code Playgroud)
其次,format_args!作为所有std::fmt公用事业的支柱。从文档开始format_args:
此宏通过采用包含
{}每个附加参数的格式化字符串文字来运行。format_args!准备附加参数以确保输出可以解释为字符串并将参数规范化为单一类型。任何实现Displaytrait 的值都可以传递给format_args!,任何Debug实现都可以传递给{:?}格式化字符串中的 a 。这个宏产生一个类型的值
fmt::Arguments。该值可以传递给内部的宏std::fmt以执行有用的重定向。所有其他格式宏(format!、write!、println!等)都通过此宏进行代理。format_args!,与其派生的宏不同,避免了堆分配。您可以使用在调试和显示上下文
fmt::Arguments中format_args!返回的值,如下所示。该示例还显示了Debug与Display格式相同的内容:在format_args!.Run Code Online (Sandbox Code Playgroud)let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); let display = format!("{}", format_args!("{} foo {:?}", 1, 2)); assert_eq!("1 foo 2", display); assert_eq!(display, debug);
查看 的来源impl Display for Arguments,它只是忽略任何格式参数。我在任何地方都找不到明确的记录,但我可以想到几个原因:
format!改用。我真的很想在不分配任何字符串的情况下截断一些输出,你知道怎么做吗?
您可以写入固定大小的缓冲区:
use std::io::{Write, ErrorKind, Result};
use std::fmt::Arguments;
fn print_limited(args: Arguments<'_>) -> Result<()> {
const BUF_SIZE: usize = 3;
let mut buf = [0u8; BUF_SIZE];
let mut buf_writer = &mut buf[..];
let written = match buf_writer.write_fmt(args) {
// successfully wrote into the buffer, determine amount written
Ok(_) => BUF_SIZE - buf_writer.len(),
// a "failed to write whole buffer" error occurred meaning there was
// more to write than there was space for, return entire size.
Err(error) if error.kind() == ErrorKind::WriteZero => BUF_SIZE,
// something else went wrong
Err(error) => return Err(error),
};
// Pick a way to print `&buf[..written]`
println!("{}", std::str::from_utf8(&buf[..written]).unwrap());
Ok(())
}
fn main() {
print_limited(format_args!("this is just a test")).unwrap();
print_limited(format_args!("{}", 123)).unwrap();
print_limited(format_args!("{}", 'a')).unwrap();
}
Run Code Online (Sandbox Code Playgroud)
1024
Run Code Online (Sandbox Code Playgroud)
这实际上比我原先想象的要复杂得多。可能有一种更清洁的方法来做到这一点。
| 归档时间: |
|
| 查看次数: |
136 次 |
| 最近记录: |